new xrender: implement partial updates
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
5a861d5d6a
commit
d37a4136ee
|
@ -28,15 +28,14 @@ typedef struct _xrender_data {
|
|||
/// If vsync is enabled and supported by the current system
|
||||
bool vsync;
|
||||
xcb_visualid_t default_visual;
|
||||
/// The idle fence for the present extension
|
||||
xcb_sync_fence_t idle_fence;
|
||||
/// The target window
|
||||
/// Target window
|
||||
xcb_window_t target_win;
|
||||
/// The painting target, it is either the root or the overlay
|
||||
/// Painting target, it is either the root or the overlay
|
||||
xcb_render_picture_t target;
|
||||
/// A back buffer
|
||||
xcb_render_picture_t back[2];
|
||||
/// Age of each back buffer
|
||||
/// Back buffers. Double buffer, with 1 for temporary render use
|
||||
xcb_render_picture_t back[3];
|
||||
/// The back buffer that is for temporary use
|
||||
/// Age of each back buffer.
|
||||
int buffer_age[2];
|
||||
/// The back buffer we should be painting into
|
||||
int curr_back;
|
||||
|
@ -104,9 +103,9 @@ static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
|
|||
// sure we get everything into the buffer
|
||||
x_clear_picture_clip_region(base->c, img->pict);
|
||||
|
||||
x_set_picture_clip_region(base->c, xd->back[xd->curr_back], 0, 0, ®);
|
||||
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[xd->curr_back],
|
||||
0, 0, 0, 0, to_i16_checked(dst_x), to_i16_checked(dst_y),
|
||||
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®);
|
||||
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[2], 0, 0, 0, 0,
|
||||
to_i16_checked(dst_x), to_i16_checked(dst_y),
|
||||
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
|
||||
pixman_region32_fini(®);
|
||||
}
|
||||
|
@ -114,10 +113,10 @@ static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
|
|||
static void fill(backend_t *base, struct color c, const region_t *clip) {
|
||||
struct _xrender_data *xd = (void *)base;
|
||||
const rect_t *extent = pixman_region32_extents((region_t *)clip);
|
||||
x_set_picture_clip_region(base->c, xd->back[xd->curr_back], 0, 0, clip);
|
||||
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, clip);
|
||||
// color is in X fixed point representation
|
||||
xcb_render_fill_rectangles(
|
||||
base->c, XCB_RENDER_PICT_OP_OVER, xd->back[xd->curr_back],
|
||||
base->c, XCB_RENDER_PICT_OP_OVER, xd->back[2],
|
||||
(xcb_render_color_t){.red = (uint16_t)(c.red * 0xffff),
|
||||
.green = (uint16_t)(c.green * 0xffff),
|
||||
.blue = (uint16_t)(c.blue * 0xffff),
|
||||
|
@ -177,7 +176,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
|
|||
x_set_picture_clip_region(c, tmp_picture[1], 0, 0, &clip);
|
||||
pixman_region32_fini(&clip);
|
||||
|
||||
xcb_render_picture_t src_pict = xd->back[xd->curr_back], dst_pict = tmp_picture[0];
|
||||
xcb_render_picture_t src_pict = xd->back[2], dst_pict = tmp_picture[0];
|
||||
auto alpha_pict = xd->alpha_pict[(int)(opacity * MAX_ALPHA)];
|
||||
int current = 0;
|
||||
x_set_picture_clip_region(c, src_pict, 0, 0, ®_op_resized);
|
||||
|
@ -212,11 +211,11 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
|
|||
XCB_NONE, dst_pict, 0, 0, 0, 0, 0, 0,
|
||||
width_resized, height_resized);
|
||||
} else {
|
||||
x_set_picture_clip_region(c, xd->back[xd->curr_back], 0, 0, ®_op);
|
||||
x_set_picture_clip_region(c, xd->back[2], 0, 0, ®_op);
|
||||
// This is the last pass, and we are doing more than 1 pass
|
||||
xcb_render_composite(c, XCB_RENDER_PICT_OP_OVER, src_pict,
|
||||
alpha_pict, xd->back[xd->curr_back], 0, 0, 0,
|
||||
0, to_i16_checked(extent_resized->x1),
|
||||
alpha_pict, xd->back[2], 0, 0, 0, 0,
|
||||
to_i16_checked(extent_resized->x1),
|
||||
to_i16_checked(extent_resized->y1),
|
||||
width_resized, height_resized);
|
||||
}
|
||||
|
@ -232,10 +231,10 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
|
|||
|
||||
// There is only 1 pass
|
||||
if (i == 1) {
|
||||
x_set_picture_clip_region(c, xd->back[xd->curr_back], 0, 0, ®_op);
|
||||
x_set_picture_clip_region(c, xd->back[2], 0, 0, ®_op);
|
||||
xcb_render_composite(
|
||||
c, XCB_RENDER_PICT_OP_OVER, src_pict, alpha_pict,
|
||||
xd->back[xd->curr_back], 0, 0, 0, 0, to_i16_checked(extent_resized->x1),
|
||||
c, XCB_RENDER_PICT_OP_OVER, src_pict, alpha_pict, xd->back[2], 0, 0,
|
||||
0, 0, to_i16_checked(extent_resized->x1),
|
||||
to_i16_checked(extent_resized->y1), width_resized, height_resized);
|
||||
}
|
||||
|
||||
|
@ -301,10 +300,25 @@ static void deinit(backend_t *backend_data) {
|
|||
free(xd);
|
||||
}
|
||||
|
||||
static void present(backend_t *base, const region_t *region attr_unused) {
|
||||
static void present(backend_t *base, const region_t *region) {
|
||||
struct _xrender_data *xd = (void *)base;
|
||||
const rect_t *extent = pixman_region32_extents((region_t *)region);
|
||||
int16_t orig_x = to_i16_checked(extent->x1), orig_y = to_i16_checked(extent->y1);
|
||||
uint16_t region_width = to_u16_checked(extent->x2 - extent->x1),
|
||||
region_height = to_u16_checked(extent->y2 - extent->y1);
|
||||
|
||||
// compose() sets clip region on the back buffer, so clear it first
|
||||
x_clear_picture_clip_region(base->c, xd->back[xd->curr_back]);
|
||||
|
||||
// limit the region of update
|
||||
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, region);
|
||||
|
||||
if (xd->vsync) {
|
||||
// Update the back buffer first, then present
|
||||
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, xd->back[2],
|
||||
XCB_NONE, xd->back[xd->curr_back], orig_x, orig_y, 0,
|
||||
0, orig_x, orig_y, region_width, region_height);
|
||||
|
||||
// Make sure we got reply from PresentPixmap before waiting for events,
|
||||
// to avoid deadlock
|
||||
auto e = xcb_request_check(
|
||||
|
@ -342,16 +356,13 @@ static void present(backend_t *base, const region_t *region attr_unused) {
|
|||
}
|
||||
free(pev);
|
||||
} else {
|
||||
// compose() sets clip region, so clear it first to make
|
||||
// sure we update the whole screen.
|
||||
x_clear_picture_clip_region(xd->base.c, xd->back[xd->curr_back]);
|
||||
// No vsync needed, draw into the target picture directly
|
||||
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, xd->back[2],
|
||||
XCB_NONE, xd->target, orig_x, orig_y, 0, 0, orig_x,
|
||||
orig_y, region_width, region_height);
|
||||
|
||||
// TODO buffer-age-like optimization might be possible here.
|
||||
// but that will require a different backend API
|
||||
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC,
|
||||
xd->back[xd->curr_back], XCB_NONE, xd->target, 0, 0,
|
||||
0, 0, 0, 0, to_u16_checked(xd->target_width),
|
||||
to_u16_checked(xd->target_height));
|
||||
// Only the target picture really holds the screen content, and its
|
||||
// content is always up to date. So buffer age is always 1.
|
||||
xd->buffer_age[xd->curr_back] = 1;
|
||||
}
|
||||
}
|
||||
|
@ -589,9 +600,10 @@ backend_t *backend_xrender_init(session_t *ps) {
|
|||
xd->vsync = false;
|
||||
}
|
||||
|
||||
// We might need to do double buffering for vsync
|
||||
int pixmap_needed = xd->vsync ? 2 : 1;
|
||||
for (int i = 0; i < pixmap_needed; i++) {
|
||||
// We might need to do double buffering for vsync, and buffer 0 and 1 are for
|
||||
// double buffering.
|
||||
int first_buffer_index = xd->vsync ? 0 : 2;
|
||||
for (int i = first_buffer_index; i < 3; i++) {
|
||||
xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root,
|
||||
to_u16_checked(ps->root_width),
|
||||
to_u16_checked(ps->root_height));
|
||||
|
|
Loading…
Reference in New Issue