new xrender: implement partial updates

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-07-26 02:21:35 +01:00
parent 5a861d5d6a
commit d37a4136ee
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
1 changed files with 44 additions and 32 deletions

View File

@ -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, &reg);
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, &reg);
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(&reg);
}
@ -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, &reg_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, &reg_op);
x_set_picture_clip_region(c, xd->back[2], 0, 0, &reg_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, &reg_op);
x_set_picture_clip_region(c, xd->back[2], 0, 0, &reg_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));