Use one global XSync fence
And only sync once per frame. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
80847dd3fa
commit
4bfed7f7e3
@ -70,6 +70,7 @@
|
||||
#include <xcb/damage.h>
|
||||
#include <xcb/randr.h>
|
||||
#include <xcb/shape.h>
|
||||
#include <xcb/sync.h>
|
||||
|
||||
#ifdef CONFIG_XINERAMA
|
||||
#include <xcb/xinerama.h>
|
||||
@ -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.
|
||||
|
@ -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);
|
||||
|
29
src/render.c
29
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
|
||||
|
40
src/x.c
40
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user