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/damage.h>
|
||||||
#include <xcb/randr.h>
|
#include <xcb/randr.h>
|
||||||
#include <xcb/shape.h>
|
#include <xcb/shape.h>
|
||||||
|
#include <xcb/sync.h>
|
||||||
|
|
||||||
#ifdef CONFIG_XINERAMA
|
#ifdef CONFIG_XINERAMA
|
||||||
#include <xcb/xinerama.h>
|
#include <xcb/xinerama.h>
|
||||||
@ -421,6 +422,7 @@ typedef struct session {
|
|||||||
void *backend_data;
|
void *backend_data;
|
||||||
/// libev mainloop
|
/// libev mainloop
|
||||||
struct ev_loop *loop;
|
struct ev_loop *loop;
|
||||||
|
|
||||||
// === Display related ===
|
// === Display related ===
|
||||||
/// Display in use.
|
/// Display in use.
|
||||||
Display *dpy;
|
Display *dpy;
|
||||||
@ -466,6 +468,8 @@ typedef struct session {
|
|||||||
// XXX should be in glx_session_t
|
// XXX should be in glx_session_t
|
||||||
glx_prog_main_t glx_prog_win;
|
glx_prog_main_t glx_prog_win;
|
||||||
#endif
|
#endif
|
||||||
|
/// Sync fence to sync draw operations
|
||||||
|
xcb_sync_fence_t sync_fence;
|
||||||
|
|
||||||
// === Operation related ===
|
// === Operation related ===
|
||||||
/// Program options.
|
/// Program options.
|
||||||
|
@ -957,11 +957,6 @@ unmap_win(session_t *ps, win **_w) {
|
|||||||
|
|
||||||
if (w->destroyed) return;
|
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
|
// Set focus out
|
||||||
win_set_focused(ps, w, false);
|
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_randr_id);
|
||||||
xcb_prefetch_extension_data(ps->c, &xcb_xinerama_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_present_id);
|
||||||
|
xcb_prefetch_extension_data(ps->c, &xcb_sync_id);
|
||||||
|
|
||||||
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id);
|
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id);
|
||||||
if (!ext_info || !ext_info->present) {
|
if (!ext_info || !ext_info->present) {
|
||||||
@ -2880,17 +2876,33 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Query X Sync
|
// Query X Sync
|
||||||
if (XSyncQueryExtension(ps->dpy, &ps->xsync_event, &ps->xsync_error)) {
|
ext_info = xcb_get_extension_data(ps->c, &xcb_sync_id);
|
||||||
// TODO: Fencing may require version >= 3.0?
|
if (ext_info && ext_info->present) {
|
||||||
int major_version_return = 0, minor_version_return = 0;
|
ps->xsync_error = ext_info->first_error;
|
||||||
if (XSyncInitialize(ps->dpy, &major_version_return, &minor_version_return))
|
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;
|
ps->xsync_exists = true;
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ps->sync_fence = XCB_NONE;
|
||||||
if (!ps->xsync_exists && ps->o.xrender_sync_fence) {
|
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)");
|
"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
|
// Query X RandR
|
||||||
@ -3188,6 +3200,11 @@ session_destroy(session_t *ps) {
|
|||||||
ps->overlay = XCB_NONE;
|
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
|
// Free reg_win
|
||||||
if (ps->reg_win) {
|
if (ps->reg_win) {
|
||||||
xcb_destroy_window(ps->c, 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));
|
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)
|
if (!draw)
|
||||||
draw = w->id;
|
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);
|
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
|
// GLX: Build texture
|
||||||
// Let glx_bind_pixmap() determine pixmap size, because if the user
|
// 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,
|
// 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);
|
assert(!w->shadow_paint.pict);
|
||||||
w->shadow_paint.pict = shadow_picture_argb;
|
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_free_gc(ps->c, gc);
|
||||||
xcb_image_destroy(shadow_image);
|
xcb_image_destroy(shadow_image);
|
||||||
xcb_free_pixmap(ps->c, shadow_pixmap);
|
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 = ??
|
||||||
/// region_real = the damage region
|
/// region_real = the damage region
|
||||||
void paint_all(session_t *ps, region_t *region, const region_t *region_real, win *const t) {
|
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;
|
region_real = region;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_REPAINT
|
#ifdef DEBUG_REPAINT
|
||||||
static struct timespec last_paint = {0};
|
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();
|
glFlush();
|
||||||
glXWaitX();
|
glXWaitX();
|
||||||
assert(ps->tgt_buffer.pixmap);
|
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,
|
paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height,
|
||||||
ps->depth, !ps->o.glx_no_rebind_pixmap);
|
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)
|
if (ps->o.vsync_use_glfinish)
|
||||||
glFinish();
|
glFinish();
|
||||||
else
|
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;
|
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
|
* Synchronizes a X Render drawable to ensure all pending painting requests
|
||||||
* are completed.
|
* are completed.
|
||||||
*/
|
*/
|
||||||
void x_fence_sync(session_t *ps, xcb_drawable_t d) {
|
bool x_fence_sync(session_t *ps, xcb_sync_fence_t f) {
|
||||||
x_sync(ps->c);
|
|
||||||
if (ps->xsync_exists) {
|
if (ps->xsync_exists) {
|
||||||
// TODO(richardgv): If everybody just follows the rules stated in X Sync
|
// 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
|
// prototype, we need only one fence per screen, but let's stay a bit
|
||||||
// cautious right now
|
// cautious right now
|
||||||
xcb_sync_fence_t tmp_fence = xcb_generate_id(ps->c);
|
|
||||||
xcb_generic_error_t *e =
|
auto e = xcb_request_check(ps->c, xcb_sync_trigger_fence_checked(ps->c, f));
|
||||||
xcb_request_check(ps->c,
|
|
||||||
xcb_sync_create_fence(ps->c, d, tmp_fence, 0));
|
|
||||||
if (e) {
|
if (e) {
|
||||||
log_error("Failed to create a XSync fence for %#010x", d);
|
log_error("Failed to trigger the fence.");
|
||||||
free(e);
|
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) {
|
if (e) {
|
||||||
log_error("Failed to trigger the fence");
|
log_error("Failed to await on a fence.");
|
||||||
free(e);
|
free(e);
|
||||||
x_free_fence(ps, &tmp_fence);
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_sync_await_fence(ps->c, 1, &tmp_fence);
|
e = xcb_request_check(ps->c, xcb_sync_reset_fence_checked(ps->c, f));
|
||||||
x_free_fence(ps, &tmp_fence);
|
if (e) {
|
||||||
|
log_error("Failed to reset the fence.");
|
||||||
|
free(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
2
src/x.h
2
src/x.h
@ -169,4 +169,4 @@ xcb_pixmap_t x_get_root_back_pixmap(session_t *ps);
|
|||||||
/// root window background pixmap
|
/// root window background pixmap
|
||||||
bool x_atom_is_background_prop(session_t *ps, xcb_atom_t atom);
|
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user