Skip to content

Instantly share code, notes, and snippets.

@richardgv
Created March 13, 2014 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richardgv/9529221 to your computer and use it in GitHub Desktop.
Save richardgv/9529221 to your computer and use it in GitHub Desktop.
chjj/compton #181: Add X Sync fence support
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