diff --git a/src/common.h b/src/common.h index 8f569314..39893136 100644 --- a/src/common.h +++ b/src/common.h @@ -70,6 +70,7 @@ #include #include #include +#include #ifdef CONFIG_XINERAMA #include @@ -421,6 +422,7 @@ typedef struct session { void *backend_data; /// libev mainloop struct ev_loop *loop; + // === Display related === /// Display in use. Display *dpy; @@ -466,6 +468,8 @@ typedef struct session { // XXX should be in glx_session_t glx_prog_main_t glx_prog_win; #endif + /// Sync fence to sync draw operations + xcb_sync_fence_t sync_fence; // === Operation related === /// Program options. diff --git a/src/compton.c b/src/compton.c index 8bbf8442..6b521a41 100644 --- a/src/compton.c +++ b/src/compton.c @@ -957,11 +957,6 @@ unmap_win(session_t *ps, win **_w) { if (w->destroyed) return; - // One last synchronization - if (w->paint.pixmap && ps->o.xrender_sync_fence) { - x_fence_sync(ps, w->paint.pixmap); - } - // Set focus out win_set_focused(ps, w, false); @@ -2770,6 +2765,7 @@ session_init(session_t *ps_old, int argc, char **argv) { xcb_prefetch_extension_data(ps->c, &xcb_randr_id); xcb_prefetch_extension_data(ps->c, &xcb_xinerama_id); xcb_prefetch_extension_data(ps->c, &xcb_present_id); + xcb_prefetch_extension_data(ps->c, &xcb_sync_id); ext_info = xcb_get_extension_data(ps->c, &xcb_render_id); if (!ext_info || !ext_info->present) { @@ -2880,17 +2876,33 @@ session_init(session_t *ps_old, int argc, char **argv) { } // Query X Sync - if (XSyncQueryExtension(ps->dpy, &ps->xsync_event, &ps->xsync_error)) { - // TODO: Fencing may require version >= 3.0? - int major_version_return = 0, minor_version_return = 0; - if (XSyncInitialize(ps->dpy, &major_version_return, &minor_version_return)) + ext_info = xcb_get_extension_data(ps->c, &xcb_sync_id); + if (ext_info && ext_info->present) { + ps->xsync_error = ext_info->first_error; + ps->xsync_event = ext_info->first_event; + // Need X Sync 3.1 for fences + auto r = xcb_sync_initialize_reply(ps->c, xcb_sync_initialize(ps->c, 3, 1), NULL); + if (r) { ps->xsync_exists = true; + free(r); + } } + ps->sync_fence = XCB_NONE; if (!ps->xsync_exists && ps->o.xrender_sync_fence) { - log_fatal("X Sync extension not found. No X Sync fence sync is " + log_error("XSync extension not found. No XSync fence sync is " "possible. (xrender-sync-fence can't be enabled)"); - exit(1); + ps->o.xrender_sync_fence = false; + } + + if (ps->o.xrender_sync_fence) { + ps->sync_fence = xcb_generate_id(ps->c); + auto e = xcb_request_check(ps->c, xcb_sync_create_fence(ps->c, ps->root, ps->sync_fence, 0)); + if (e) { + log_error("Failed to create a XSync fence. xrender-sync-fence will be disabled"); + ps->o.xrender_sync_fence = false; + free(e); + } } // Query X RandR @@ -3188,6 +3200,11 @@ session_destroy(session_t *ps) { ps->overlay = XCB_NONE; } + if (ps->sync_fence) { + xcb_sync_destroy_fence(ps->c, ps->sync_fence); + ps->sync_fence = XCB_NONE; + } + // Free reg_win if (ps->reg_win) { xcb_destroy_window(ps->c, ps->reg_win); diff --git a/src/render.c b/src/render.c index 8fdf735e..e3af1301 100644 --- a/src/render.c +++ b/src/render.c @@ -167,7 +167,7 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) { ps, xcb_composite_name_window_pixmap(ps->c, w->id, w->paint.pixmap)); } - Drawable draw = w->paint.pixmap; + xcb_drawable_t draw = w->paint.pixmap; if (!draw) draw = w->id; @@ -181,10 +181,6 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) { ps, w->pictfmt, draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); } - if (IsViewable == w->a.map_state && ps->o.xrender_sync_fence) { - x_fence_sync(ps, draw); - } - // GLX: Build texture // Let glx_bind_pixmap() determine pixmap size, because if the user // is resizing windows, the width and height we get may not be up-to-date, @@ -605,11 +601,6 @@ static bool win_build_shadow(session_t *ps, win *w, double opacity) { assert(!w->shadow_paint.pict); w->shadow_paint.pict = shadow_picture_argb; - // Sync it once and only once - if (ps->o.xrender_sync_fence) { - x_fence_sync(ps, w->shadow_paint.pixmap); - } - xcb_free_gc(ps->c, gc); xcb_image_destroy(shadow_image); xcb_free_pixmap(ps->c, shadow_pixmap); @@ -822,8 +813,17 @@ win_blur_background(session_t *ps, win *w, xcb_render_picture_t tgt_buffer, /// region = ?? /// region_real = the damage region void paint_all(session_t *ps, region_t *region, const region_t *region_real, win *const t) { - if (!region_real) + if (ps->o.xrender_sync_fence) { + if (!x_fence_sync(ps, ps->sync_fence)) { + log_error("x_fence_sync failed, xrender-sync-fence will be disabled from now on."); + xcb_sync_destroy_fence(ps->c, ps->sync_fence); + ps->o.xrender_sync_fence = false; + } + } + + if (!region_real) { region_real = region; + } #ifdef DEBUG_REPAINT static struct timespec last_paint = {0}; @@ -1027,15 +1027,8 @@ void paint_all(session_t *ps, region_t *region, const region_t *region_real, win glFlush(); glXWaitX(); assert(ps->tgt_buffer.pixmap); - if (ps->o.xrender_sync_fence) { - x_fence_sync(ps, ps->tgt_buffer.pixmap); - } paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height, ps->depth, !ps->o.glx_no_rebind_pixmap); - // See #163 - if (ps->o.xrender_sync_fence) { - x_fence_sync(ps, ps->tgt_buffer.pixmap); - } if (ps->o.vsync_use_glfinish) glFinish(); else diff --git a/src/x.c b/src/x.c index 390b8724..ee9cf1e8 100644 --- a/src/x.c +++ b/src/x.c @@ -454,46 +454,36 @@ bool x_atom_is_background_prop(session_t *ps, xcb_atom_t atom) { return false; } -/** - * Free a XSync fence. - */ -static inline void -x_free_fence(session_t *ps, xcb_sync_fence_t *pfence) { - if (*pfence) { - xcb_sync_destroy_fence(ps->c, *pfence); - } - *pfence = XCB_NONE; -} - /** * Synchronizes a X Render drawable to ensure all pending painting requests * are completed. */ -void x_fence_sync(session_t *ps, xcb_drawable_t d) { - x_sync(ps->c); +bool x_fence_sync(session_t *ps, xcb_sync_fence_t f) { if (ps->xsync_exists) { // TODO(richardgv): If everybody just follows the rules stated in X Sync // prototype, we need only one fence per screen, but let's stay a bit // cautious right now - xcb_sync_fence_t tmp_fence = xcb_generate_id(ps->c); - xcb_generic_error_t *e = - xcb_request_check(ps->c, - xcb_sync_create_fence(ps->c, d, tmp_fence, 0)); + + auto e = xcb_request_check(ps->c, xcb_sync_trigger_fence_checked(ps->c, f)); if (e) { - log_error("Failed to create a XSync fence for %#010x", d); + log_error("Failed to trigger the fence."); free(e); - return; + return false; } - e = xcb_request_check(ps->c, xcb_sync_trigger_fence(ps->c, tmp_fence)); + e = xcb_request_check(ps->c, xcb_sync_await_fence_checked(ps->c, 1, &f)); if (e) { - log_error("Failed to trigger the fence"); + log_error("Failed to await on a fence."); free(e); - x_free_fence(ps, &tmp_fence); - return; + return false; } - xcb_sync_await_fence(ps->c, 1, &tmp_fence); - x_free_fence(ps, &tmp_fence); + e = xcb_request_check(ps->c, xcb_sync_reset_fence_checked(ps->c, f)); + if (e) { + log_error("Failed to reset the fence."); + free(e); + return false; + } } + return true; } diff --git a/src/x.h b/src/x.h index 03ba5ca8..937f1a6f 100644 --- a/src/x.h +++ b/src/x.h @@ -169,4 +169,4 @@ xcb_pixmap_t x_get_root_back_pixmap(session_t *ps); /// root window background pixmap bool x_atom_is_background_prop(session_t *ps, xcb_atom_t atom); -void x_fence_sync(session_t *, xcb_sync_fence_t); +bool x_fence_sync(session_t *, xcb_sync_fence_t);