Created
March 13, 2014 14:11
-
-
Save richardgv/9529221 to your computer and use it in GitHub Desktop.
chjj/compton #181: Add X Sync fence support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/common.h b/src/common.h | |
index e87651c..f20fc58 100644 | |
--- a/src/common.h | |
+++ b/src/common.h | |
@@ -89,6 +89,7 @@ | |
#include <X11/extensions/shape.h> | |
#include <X11/extensions/Xrandr.h> | |
#include <X11/extensions/Xdbe.h> | |
+#include <X11/extensions/sync.h> | |
#ifdef CONFIG_XINERAMA | |
#include <X11/extensions/Xinerama.h> | |
@@ -850,6 +851,12 @@ typedef struct { | |
/// Number of Xinerama screens. | |
int xinerama_nscrs; | |
#endif | |
+ /// Whether X Sync extension exists. | |
+ bool xsync_exists; | |
+ /// Event base number for X Sync extension. | |
+ int xsync_event; | |
+ /// Error base number for X Sync extension. | |
+ int xsync_error; | |
/// Whether X Render convolution filter exists. | |
bool xrfilter_convolution_exists; | |
@@ -1913,6 +1920,33 @@ free_winprop(winprop_t *pprop) { | |
pprop->nitems = 0; | |
} | |
+/** | |
+ * Synchronizes a X Render drawable to ensure all pending painting requests | |
+ * are completed. | |
+ */ | |
+static inline void | |
+xrender_sync(session_t *ps, Drawable d) { | |
+ if (ps->xsync_exists) { | |
+ // TODO: 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 | |
+ XSyncFence fence = XSyncCreateFence(ps->dpy, d, False); | |
+ if (fence) { | |
+ Bool triggered = False; | |
+ // The fence may fail to be created (e.g. because of died drawable) | |
+ assert(!XSyncQueryFence(ps->dpy, fence, &triggered) || !triggered); | |
+ XSyncTriggerFence(ps->dpy, fence); | |
+ XSyncAwaitFence(ps->dpy, &fence, 1); | |
+ assert(!XSyncQueryFence(ps->dpy, fence, &triggered) || triggered); | |
+ XSyncDestroyFence(ps->dpy, fence); | |
+ } | |
+ else { | |
+ printf_errf("(%#010lx): Failed to create X Sync fence.", d); | |
+ } | |
+ } | |
+ XSync(ps->dpy, False); | |
+} | |
+ | |
void | |
force_repaint(session_t *ps); | |
diff --git a/src/compton.c b/src/compton.c | |
index 645aa5c..9b5ce7d 100644 | |
--- a/src/compton.c | |
+++ b/src/compton.c | |
@@ -1509,6 +1509,9 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint, | |
const reg_data_t *pcache_reg) { | |
glx_mark(ps, w->id, true); | |
+ if (!w->destroyed) | |
+ xrender_sync(ps, w->id); | |
+ | |
// Fetch Pixmap | |
if (!w->paint.pixmap && ps->has_name_pixmap) { | |
set_ignore_next(ps); | |
@@ -1528,6 +1531,10 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint, | |
CPSubwindowMode, &pa); | |
} | |
} | |
+ | |
+ if (w->paint.pixmap) | |
+ xrender_sync(ps, w->paint.pixmap); | |
+ | |
// 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, | |
@@ -1948,6 +1955,8 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t | |
else | |
glFlush(); | |
glXWaitX(); | |
+ if (ps->tgt_buffer.pixmap) | |
+ xrender_sync(ps, ps->tgt_buffer.pixmap); | |
paint_bind_tex_real(ps, &ps->tgt_buffer, | |
ps->root_width, ps->root_height, ps->depth, | |
!ps->o.glx_no_rebind_pixmap); | |
@@ -3188,10 +3197,10 @@ damage_win(session_t *ps, XDamageNotifyEvent *de) { | |
* Xlib error handler function. | |
*/ | |
static int | |
-error(Display __attribute__((unused)) *dpy, XErrorEvent *ev) { | |
+xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) { | |
session_t * const ps = ps_g; | |
- int o; | |
+ int o = 0; | |
const char *name = "Unknown"; | |
if (should_ignore(ps, ev->serial)) { | |
@@ -3240,6 +3249,15 @@ error(Display __attribute__((unused)) *dpy, XErrorEvent *ev) { | |
} | |
#endif | |
+ if (ps->xsync_exists) { | |
+ o = ev->error_code - ps->xsync_error; | |
+ switch (o) { | |
+ CASESTRRET2(XSyncBadCounter); | |
+ CASESTRRET2(XSyncBadAlarm); | |
+ CASESTRRET2(XSyncBadFence); | |
+ } | |
+ } | |
+ | |
switch (ev->error_code) { | |
CASESTRRET2(BadAccess); | |
CASESTRRET2(BadAlloc); | |
@@ -3771,18 +3789,25 @@ ev_name(session_t *ps, XEvent *ev) { | |
CASESTRRET(Expose); | |
CASESTRRET(PropertyNotify); | |
CASESTRRET(ClientMessage); | |
- default: | |
- if (isdamagenotify(ps, ev)) | |
- return "Damage"; | |
+ } | |
- if (ps->shape_exists && ev->type == ps->shape_event) { | |
- return "ShapeNotify"; | |
- } | |
+ if (isdamagenotify(ps, ev)) | |
+ return "Damage"; | |
- sprintf(buf, "Event %d", ev->type); | |
+ if (ps->shape_exists && ev->type == ps->shape_event) | |
+ return "ShapeNotify"; | |
- return buf; | |
+ if (ps->xsync_exists) { | |
+ int o = ev->type - ps->xsync_event; | |
+ switch (o) { | |
+ CASESTRRET(CounterNotify); | |
+ CASESTRRET(AlarmNotify); | |
+ } | |
} | |
+ | |
+ sprintf(buf, "Event %d", ev->type); | |
+ | |
+ return buf; | |
} | |
static Window | |
@@ -6852,7 +6877,7 @@ session_init(session_t *ps_old, int argc, char **argv) { | |
} | |
} | |
- XSetErrorHandler(error); | |
+ XSetErrorHandler(xerror); | |
if (ps->o.synchronize) { | |
XSynchronize(ps->dpy, 1); | |
} | |
@@ -6912,6 +6937,13 @@ session_init(session_t *ps_old, int argc, char **argv) { | |
ps->shape_exists = true; | |
} | |
+ // Query X Sync | |
+ if (XSyncQueryExtension(ps->dpy, &ps->xsync_event, &ps->xsync_error)) { | |
+ int major_version_return = 0, minor_version_return = 0; | |
+ if (XSyncInitialize(ps->dpy, &major_version_return, &minor_version_return)) | |
+ ps->xsync_exists = true; | |
+ } | |
+ | |
// Build a safe representation of display name | |
{ | |
char *display_repr = DisplayString(ps->dpy); | |
diff --git a/src/compton.h b/src/compton.h | |
index 22ee195..192d311 100644 | |
--- a/src/compton.h | |
+++ b/src/compton.h | |
@@ -883,7 +883,7 @@ static void | |
damage_win(session_t *ps, XDamageNotifyEvent *de); | |
static int | |
-error(Display *dpy, XErrorEvent *ev); | |
+xerror(Display *dpy, XErrorEvent *ev); | |
static void | |
expose_root(session_t *ps, XRectangle *rects, int nrects); | |
diff --git a/src/opengl.c b/src/opengl.c | |
index d557aea..974880a 100644 | |
--- a/src/opengl.c | |
+++ b/src/opengl.c | |
@@ -523,6 +523,8 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, | |
return false; | |
} | |
+ xrender_sync(ps, pixmap); | |
+ | |
glx_texture_t *ptex = *pptex; | |
bool need_release = true; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment