Implement buffer_age() for the new xrender backend

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-02-25 01:15:21 +00:00
parent 244c23140d
commit 29ceea8412
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
1 changed files with 39 additions and 24 deletions

View File

@ -29,13 +29,14 @@ typedef struct _xrender_data {
bool vsync; bool vsync;
/// The idle fence for the present extension /// The idle fence for the present extension
xcb_sync_fence_t idle_fence; xcb_sync_fence_t idle_fence;
bool present_in_progress;
/// The target window /// The target window
xcb_window_t target_win; xcb_window_t target_win;
/// The painting target, it is either the root or the overlay /// The painting target, it is either the root or the overlay
xcb_render_picture_t target; xcb_render_picture_t target;
/// A back buffer /// A back buffer
xcb_render_picture_t back[2]; xcb_render_picture_t back[2];
/// Age of each back buffer
int buffer_age[2];
/// The back buffer we should be painting into /// The back buffer we should be painting into
int curr_back; int curr_back;
/// The corresponding pixmap to the back buffer /// The corresponding pixmap to the back buffer
@ -433,7 +434,6 @@ static void *init(session_t *ps) {
xd->shadow_pixel = solid_picture(ps, true, 1, ps->o.shadow_red, xd->shadow_pixel = solid_picture(ps, true, 1, ps->o.shadow_red,
ps->o.shadow_green, ps->o.shadow_blue); ps->o.shadow_green, ps->o.shadow_blue);
xd->shadow_kernel = gaussian_kernel(ps->o.shadow_radius); xd->shadow_kernel = gaussian_kernel(ps->o.shadow_radius);
xd->present_in_progress = false;
sum_kernel_preprocess(xd->shadow_kernel); sum_kernel_preprocess(xd->shadow_kernel);
if (ps->overlay != XCB_NONE) { if (ps->overlay != XCB_NONE) {
@ -486,6 +486,7 @@ static void *init(session_t *ps) {
ps->root_width, ps->root_height); ps->root_width, ps->root_height);
xd->back[i] = x_create_picture_with_pictfmt_and_pixmap( xd->back[i] = x_create_picture_with_pictfmt_and_pixmap(
ps->c, pictfmt, xd->back_pixmap[i], 0, NULL); ps->c, pictfmt, xd->back_pixmap[i], 0, NULL);
xd->buffer_age[i] = -1;
if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) { if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) {
log_error("Cannot create pixmap for rendering"); log_error("Cannot create pixmap for rendering");
goto err; goto err;
@ -518,21 +519,6 @@ static void *root_change(void *backend_data, session_t *ps) {
static void prepare(void *backend_data, session_t *ps, const region_t *reg_paint) { static void prepare(void *backend_data, session_t *ps, const region_t *reg_paint) {
struct _xrender_data *xd = backend_data; struct _xrender_data *xd = backend_data;
if (xd->vsync && xd->present_in_progress) {
// TODO don't block wait for present completion
xcb_present_generic_event_t *pev =
(void *)xcb_wait_for_special_event(ps->c, xd->present_event);
assert(pev->evtype == XCB_PRESENT_COMPLETE_NOTIFY);
xcb_present_complete_notify_event_t *pcev = (void *)pev;
// log_trace("Present complete: %d %ld", pcev->mode, pcev->msc);
if (pcev->mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
// We cannot use the pixmap we used anymore
xd->curr_back = 1 - xd->curr_back;
}
free(pev);
xd->present_in_progress = false;
}
// Paint the root pixmap (i.e. wallpaper) // Paint the root pixmap (i.e. wallpaper)
// Limit the paint area // Limit the paint area
@ -547,13 +533,35 @@ static void present(void *backend_data, session_t *ps) {
struct _xrender_data *xd = backend_data; struct _xrender_data *xd = backend_data;
if (xd->vsync) { if (xd->vsync) {
// Only reset the fence when we are sure we will trigger it again. // Make sure we got reply from PresentPixmap before waiting for events,
// To make sure rendering won't get stuck if user toggles vsync on the // to avoid deadlock
// fly. auto e = xcb_request_check(
xcb_present_pixmap(ps->c, xd->target_win, xd->back_pixmap[xd->curr_back], ps->c, xcb_present_pixmap_checked(
0, XCB_NONE, XCB_NONE, 0, 0, XCB_NONE, XCB_NONE, ps->c, xd->target_win, xd->back_pixmap[xd->curr_back], 0,
XCB_NONE, 0, 0, 0, 0, 0, NULL); XCB_NONE, XCB_NONE, 0, 0, XCB_NONE, XCB_NONE, XCB_NONE, 0,
xd->present_in_progress = true; 0, 0, 0, 0, NULL));
if (e) {
log_error("Failed to present pixmap");
free(e);
return;
}
// TODO don't block wait for present completion
xcb_present_generic_event_t *pev =
(void *)xcb_wait_for_special_event(ps->c, xd->present_event);
assert(pev->evtype == XCB_PRESENT_COMPLETE_NOTIFY);
xcb_present_complete_notify_event_t *pcev = (void *)pev;
// log_trace("Present complete: %d %ld", pcev->mode, pcev->msc);
xd->buffer_age[xd->curr_back] = 1;
// buffer_age < 0 means that back buffer is empty
if (xd->buffer_age[1 - xd->curr_back] > 0) {
xd->buffer_age[1 - xd->curr_back]++;
}
if (pcev->mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
// We cannot use the pixmap we used anymore
xd->curr_back = 1 - xd->curr_back;
}
free(pev);
} else { } else {
// compose() sets clip region, so clear it first to make // compose() sets clip region, so clear it first to make
// sure we update the whole screen. // sure we update the whole screen.
@ -564,9 +572,15 @@ static void present(void *backend_data, session_t *ps) {
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC,
xd->back[xd->curr_back], XCB_NONE, xd->target, 0, 0, xd->back[xd->curr_back], XCB_NONE, xd->target, 0, 0,
0, 0, 0, 0, ps->root_width, ps->root_height); 0, 0, 0, 0, ps->root_width, ps->root_height);
xd->buffer_age[xd->curr_back] = 1;
} }
} }
static int buffer_age(void *backend_data, session_t *ps) {
struct _xrender_data *xd = backend_data;
return xd->buffer_age[xd->curr_back];
}
struct backend_info xrender_backend = { struct backend_info xrender_backend = {
.init = init, .init = init,
.deinit = deinit, .deinit = deinit,
@ -580,6 +594,7 @@ struct backend_info xrender_backend = {
.release_win = release_win, .release_win = release_win,
.is_win_transparent = default_is_win_transparent, .is_win_transparent = default_is_win_transparent,
.is_frame_transparent = default_is_frame_transparent, .is_frame_transparent = default_is_frame_transparent,
.buffer_age = buffer_age,
.max_buffer_age = 2, .max_buffer_age = 2,
}; };