=== modified file 'plugins/opengl/include/opengl/opengl.h'
--- plugins/opengl/include/opengl/opengl.h	2013-04-27 23:30:28 +0000
+++ plugins/opengl/include/opengl/opengl.h	2014-12-10 19:46:40 +0000
@@ -36,7 +36,9 @@
 #include <EGL/eglext.h>
 #else
 #include <GL/gl.h>
+#include <GL/glext.h>
 #include <GL/glx.h>
+#include <inttypes.h>
 
 /* Some implementations have not yet given a definition
  * to GLX_BACK_BUFFER_AGE_EXT but this is the token as defined
@@ -117,6 +119,39 @@
 #define GLX_FRONT_LEFT_EXT                 0x20DE
 #endif
 
+#ifndef GL_ARB_sync
+# ifndef GL_ES_VERSION_2_0
+typedef struct __GLsync *GLsync;
+typedef int64_t GLint64;
+typedef uint64_t GLuint64;
+typedef intptr_t GLintptr;
+# endif
+
+# ifdef GL_APPLE_sync
+#  define GL_TIMEOUT_IGNORED               GL_TIMEOUT_IGNORED_APPLE
+#  define GL_ALREADY_SIGNALED              GL_ALREADY_SIGNALED_APPLE
+#  define GL_TIMEOUT_EXPIRED               GL_TIMEOUT_EXPIRED_APPLE
+#  define GL_CONDITION_SATISFIED           GL_CONDITION_SATISFIED_APPLE
+#  define GL_WAIT_FAILED                   GL_WAIT_FAILED_APPLE
+#  define GL_SYNC_GPU_COMMANDS_COMPLETE    GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE
+#  define GL_SYNC_STATUS                   GL_SYNC_STATUS _APPLE
+#  define GL_SIGNALED                      GL_SIGNALED_APPLE
+# else
+#  define GL_TIMEOUT_IGNORED               0xFFFFFFFFFFFFFFFFull
+#  define GL_ALREADY_SIGNALED              0x911A
+#  define GL_TIMEOUT_EXPIRED               0x911B
+#  define GL_CONDITION_SATISFIED           0x911C
+#  define GL_WAIT_FAILED                   0x911D
+#  define GL_SYNC_GPU_COMMANDS_COMPLETE    0x9117
+#  define GL_SYNC_STATUS                   0x9114
+#  define GL_SIGNALED                      0x9119
+# endif
+#endif
+
+#ifndef GL_EXT_x11_sync_object
+#define GL_SYNC_X11_FENCE_EXT              0x90E1
+#endif
+
 namespace GL {
     #ifdef USE_GLES
     typedef EGLImageKHR (*EGLCreateImageKHRProc)  (EGLDisplay dpy,
@@ -320,6 +355,24 @@
 					   GLsizei width,
 					   GLsizei height);
 
+    typedef GLsync (*GLFenceSyncProc) (GLenum condition, GLbitfield flags);
+    typedef void (*GLDeleteSyncProc) (GLsync sync);
+    typedef GLenum (*GLClientWaitSyncProc) (GLsync sync,
+					GLbitfield flags,
+					GLuint64 timeout);
+    typedef void (*GLWaitSyncProc) (GLsync sync,
+				GLbitfield flags,
+				GLuint64 timeout);
+    typedef void (*GLGetSyncivProc) (GLsync sync,
+				 GLenum pname,
+				 GLsizei bufSize,
+				 GLsizei *length,
+				 GLint *values);
+
+    typedef GLsync (*GLImportSyncProc) (GLenum external_sync_type,
+				    GLintptr external_sync,
+				    GLbitfield flags);
+
 
     /* GL_ARB_shader_objects */
     #ifndef USE_GLES
@@ -519,6 +572,14 @@
 
 #endif
 
+    extern GLFenceSyncProc      fenceSync;
+    extern GLDeleteSyncProc     deleteSync;
+    extern GLClientWaitSyncProc clientWaitSync;
+    extern GLWaitSyncProc       waitSync;
+    extern GLGetSyncivProc      getSynciv;
+
+    extern GLImportSyncProc importSync;
+
     extern bool  textureFromPixmap;
     extern bool  textureRectangle;
     extern bool  textureNonPowerOfTwo;
@@ -538,6 +599,9 @@
     extern GLint maxTextureUnits;
     extern bool  bufferAge;
 
+    extern bool  sync;
+    extern bool  xToGLSync;
+
     extern bool canDoSaturated;
     extern bool canDoSlightlySaturated;
 

=== added file 'plugins/opengl/include/opengl/xtoglsync.h'
--- plugins/opengl/include/opengl/xtoglsync.h	1970-01-01 00:00:00 +0000
+++ plugins/opengl/include/opengl/xtoglsync.h	2014-12-10 19:46:40 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2011 NVIDIA Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * NVIDIA Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * NVIDIA Corporation makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: James Jones <jajones@nvidia.com>
+ */
+
+#ifndef _GLXTOGLSYNC_H
+#define _GLXTOGLSYNC_H
+
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+#include <X11/extensions/sync.h>
+
+#include "opengl/opengl.h"
+
+/**
+ * Class that manages an XFenceSync wrapped in a GLsync object.
+ *
+ * Can be used to synchronize operations in the GL command stream
+ * with operations in the X command stream.
+ */
+class XToGLSync {
+    public:
+	XToGLSync ();
+	~XToGLSync ();
+
+	XSyncAlarm alarm (void) const { return a; }
+	bool isReady (void) const { return state == XTOGLS_READY; }
+
+	/**
+	 * Sends the trigger request to the server. The fence will be signaled
+	 * after all rendering has completed.
+	 */
+	void trigger (void);
+
+	/**
+	 * Calls glWaitSync. Any OpenGL commands after this will wait for the
+	 * fence to be signaled.
+	 */
+	void insertWait (void);
+
+	/**
+	 * Blocks until the fence is signaled, or until a timeout expires.
+	 *
+	 * \param The maximum time to wait, in nanoseconds.
+	 * \return One of \c GL_ALREADY_SIGNALED, \c GL_CONDITION_SATISFIED,
+	 *	\c GL_TIMEOUT_EXPIRED, or \c GL_WAIT_FAILED.
+	 */
+	GLenum checkUpdateFinished (GLuint64 timeout);
+
+	/**
+	 * Resets the fence.
+	 */
+	void reset (void);
+	void handleEvent (XSyncAlarmNotifyEvent *ev);
+
+    private:
+	XSyncFence f;
+	GLsync fGL;
+
+	XSyncCounter c;
+	XSyncAlarm a;
+	XSyncValue nextCounterValue;
+
+	enum {
+	    XTOGLS_READY,
+	    XTOGLS_TRIGGER_SENT,
+	    XTOGLS_WAITING,
+	    XTOGLS_DONE,
+	    XTOGLS_RESET_PENDING,
+	} state;
+
+	static bool syncValuesInitialized;
+	static XSyncValue zero;
+	static XSyncValue one;
+
+	static Bool alarmEventPredicate (Display *dpy, XEvent *ev, XPointer arg);
+};
+
+#endif

=== modified file 'plugins/opengl/opengl.xml.in'
--- plugins/opengl/opengl.xml.in	2012-12-17 10:53:59 +0000
+++ plugins/opengl/opengl.xml.in	2014-12-10 19:46:40 +0000
@@ -59,6 +59,11 @@
 		<_long>Use glXSwapBuffers to display every frame. This eliminates visible tearing with most drivers and dramatically improves visual smoothness. Automatically enabled when framebuffer_object is on.</_long>
 		<default>true</default>
 	    </option>
+	    <option name="enable_x11_sync" type="bool">
+		<_short>X11 Sync objects</_short>
+		<_long>Use X11 Sync fences to synchronize rendering between X11 and OpenGL (GL_EXT_x11_sync_object). Without this, the contents of windows may not be completely redrawn.</_long>
+		<default>true</default>
+	    </option>
 	    <option name="unredirect_driver_blacklist" type="string">
 		<_short>Unredirect Driver Blacklist</_short>
 		<_long>If non-empty, specifies a POSIX (extended) regular expression to match against the OpenGL driver strings (newline separated): "GL_VENDOR\nGL_RENDERER\nGL_VERSION". If the regular expression matches a substring of that concatenation then no windows will ever be unredirected while using that particular graphics driver.</_long>

=== modified file 'plugins/opengl/src/privates.h'
--- plugins/opengl/src/privates.h	2013-04-25 17:01:46 +0000
+++ plugins/opengl/src/privates.h	2014-12-10 19:46:40 +0000
@@ -35,6 +35,7 @@
 
 #include <composite/composite.h>
 #include <opengl/opengl.h>
+#include <opengl/xtoglsync.h>
 #include <core/atoms.h>
 #include <core/configurerequestbuffer.h>
 
@@ -184,6 +185,12 @@
 
 	void updateView ();
 
+	bool syncObjectsInitialized () const;
+	bool syncObjectsEnabled ();
+	void initXToGLSyncs ();
+	void destroyXToGLSyncs ();
+	void updateXToGLSyncs ();
+
 	bool driverIsBlacklisted (const char *regex) const;
 
 	bool postprocessRequiredForCurrentFrame ();
@@ -253,6 +260,12 @@
 	bool postprocessingRequired;
 	mutable CompString prevRegex;
 	mutable bool       prevBlacklisted;
+
+	std::vector<XToGLSync*> xToGLSyncs;
+	std::map<XSyncAlarm, XToGLSync*> alarmToSync;
+	std::vector<XToGLSync*>::size_type currentSyncNum;
+	XToGLSync *currentSync;
+	std::vector<XToGLSync*>::size_type warmupSyncs;
 };
 
 class PrivateGLWindow :

=== modified file 'plugins/opengl/src/screen.cpp'
--- plugins/opengl/src/screen.cpp	2013-10-30 20:31:20 +0000
+++ plugins/opengl/src/screen.cpp	2014-12-10 19:46:40 +0000
@@ -68,6 +68,16 @@
 
 using namespace compiz::opengl;
 
+/**
+ * The number of X11 sync objects to create.
+ */
+static const size_t NUM_X11_SYNCS = 16;
+
+/**
+ * The maximum time to wait for a sync object, in nanoseconds.
+ */
+static const GLuint64 MAX_SYNC_WAIT_TIME = 1000000000ull; // One second
+
 namespace GL {
     #ifdef USE_GLES
     EGLCreateImageKHRProc  createImage;
@@ -170,6 +180,14 @@
     GLBindRenderbufferProc bindRenderbuffer = NULL;
     GLRenderbufferStorageProc renderbufferStorage = NULL;
 
+    GLFenceSyncProc      fenceSync = NULL;
+    GLDeleteSyncProc     deleteSync = NULL;
+    GLClientWaitSyncProc clientWaitSync = NULL;
+    GLWaitSyncProc       waitSync = NULL;
+    GLGetSyncivProc      getSynciv = NULL;
+
+    GLImportSyncProc importSync = NULL;
+
     bool  textureFromPixmap = true;
     bool  textureRectangle = false;
     bool  textureNonPowerOfTwo = false;
@@ -188,6 +206,9 @@
     GLint maxTextureUnits = 1;
     bool  bufferAge = false;
 
+    bool sync = false;
+    bool xToGLSync = false;
+
     bool canDoSaturated = false;
     bool canDoSlightlySaturated = false;
 
@@ -1054,6 +1075,36 @@
     if (strstr (glExtensions, "GL_ARB_texture_compression"))
 	GL::textureCompression = true;
 
+    if (strstr (glExtensions, "GL_ARB_sync"))
+    {
+	GL::fenceSync = (GL::GLFenceSyncProc)
+	    getProcAddress ("glFenceSync");
+	GL::deleteSync = (GL::GLDeleteSyncProc)
+	    getProcAddress ("glDeleteSync");
+	GL::clientWaitSync = (GL::GLClientWaitSyncProc)
+	    getProcAddress ("glClientWaitSync");
+	GL::waitSync = (GL::GLWaitSyncProc)
+	    getProcAddress ("glWaitSync");
+	GL::getSynciv = (GL::GLGetSyncivProc)
+	    getProcAddress ("glGetSynciv");
+
+	if (GL::fenceSync      &&
+	    GL::deleteSync     &&
+	    GL::clientWaitSync &&
+	    GL::waitSync       &&
+	    GL::getSynciv)
+	    GL::sync = true;
+    }
+
+    if (strstr (glExtensions, "GL_EXT_x11_sync_object"))
+    {
+	GL::importSync = (GL::GLImportSyncProc)
+	    getProcAddress ("glImportSyncEXT");
+
+	if (GL::importSync)
+	    GL::xToGLSync = true;
+    }
+
     glClearColor (0.0, 0.0, 0.0, 1.0);
     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
     glEnable (GL_CULL_FACE);
@@ -1257,6 +1308,8 @@
 	    getProcAddress ("glXSwapIntervalSGI");
     }
 
+    priv->initXToGLSyncs ();
+
     fbConfigs = (*GL::getFBConfigs) (dpy, s->screenNum (), &nElements);
 
     GL::stencilBuffer = false;
@@ -1411,6 +1464,9 @@
 
 GLScreen::~GLScreen ()
 {
+    // Must occur before context is destroyed.
+    priv->destroyXToGLSyncs ();
+
     if (priv->hasCompositing)
 	CompositeScreen::get (screen)->unregisterPaintHandler ();
 
@@ -1471,7 +1527,10 @@
     glVersion (NULL),
     postprocessingRequired (false),
     prevRegex (),
-    prevBlacklisted (false)
+    prevBlacklisted (false),
+    currentSyncNum (0),
+    currentSync (0),
+    warmupSyncs (0)
 {
     ScreenInterface::setHandler (screen);
     CompositeScreenInterface::setHandler (cScreen);
@@ -1563,6 +1622,16 @@
 		 * be recopying the root window pixmap all the time
 		 * which is no good, so don't do that */
 	    }
+	    else if (event->type == screen->syncEvent () + XSyncAlarmNotify)
+	    {
+		XSyncAlarmNotifyEvent *ae =
+		    reinterpret_cast<XSyncAlarmNotifyEvent*>(event);
+		std::map<XSyncAlarm, XToGLSync*>::iterator it =
+		    alarmToSync.find (ae->alarm);
+
+		if (it != alarmToSync.end ())
+		    it->second->handleEvent (ae);
+	    }
 	    break;
     }
 }
@@ -2026,6 +2095,101 @@
 {
 }
 
+bool
+PrivateGLScreen::syncObjectsInitialized () const
+{
+    return !xToGLSyncs.empty ();
+}
+
+bool
+PrivateGLScreen::syncObjectsEnabled ()
+{
+    return GL::sync && GL::xToGLSync && optionGetEnableX11Sync ();
+}
+
+void
+PrivateGLScreen::initXToGLSyncs ()
+{
+    assert (!syncObjectsInitialized ());
+    assert (xToGLSyncs.empty ());
+    assert (alarmToSync.empty ());
+
+    if (syncObjectsEnabled () && !syncObjectsInitialized ())
+    {
+	xToGLSyncs.resize (NUM_X11_SYNCS, NULL);
+
+	foreach (XToGLSync*& sync, xToGLSyncs)
+	{
+	    sync = new XToGLSync ();
+	    alarmToSync[sync->alarm ()] = sync;
+	}
+
+	currentSyncNum = 0;
+	currentSync = xToGLSyncs[0];
+	warmupSyncs = 0;
+    }
+}
+
+void
+PrivateGLScreen::destroyXToGLSyncs ()
+{
+    if (syncObjectsInitialized ())
+    {
+	foreach (XToGLSync* sync, xToGLSyncs)
+	    delete sync;
+	xToGLSyncs.resize (0);
+    }
+    alarmToSync.clear ();
+    currentSyncNum = 0;
+    currentSync = NULL;
+    warmupSyncs = 0;
+}
+
+void
+PrivateGLScreen::updateXToGLSyncs ()
+{
+    const std::vector<XToGLSync*>::size_type numSyncs = xToGLSyncs.size ();
+
+    if (numSyncs)
+    {
+	if (warmupSyncs >= numSyncs / 2)
+	{
+	    const std::vector<XToGLSync*>::size_type resetSyncIdx =
+		(currentSyncNum + (numSyncs / 2)) % numSyncs;
+
+	    XToGLSync* syncToReset = xToGLSyncs[resetSyncIdx];
+
+	    GLenum status = syncToReset->checkUpdateFinished (0);
+	    if (status == GL_TIMEOUT_EXPIRED)
+	    {
+		status = syncToReset->checkUpdateFinished (MAX_SYNC_WAIT_TIME);
+	    }
+
+	    if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED)
+	    {
+		// This should never happen. If there was an error somewhere,
+		// then we don't want to risk a hang here, so just destroy the
+		// sync objects. We'll recreate them again in the next call to
+		// prepareDrawing.
+		compLogMessage ("opengl", CompLogLevelError, "Timed out waiting for sync object.");
+		destroyXToGLSyncs ();
+		return;
+	    }
+
+	    syncToReset->reset ();
+	}
+	else
+	{
+	    warmupSyncs++;
+	}
+
+	currentSyncNum++;
+	currentSyncNum %= numSyncs;
+
+	currentSync = xToGLSyncs[currentSyncNum];
+    }
+}
+
 #ifndef USE_GLES
 
 void
@@ -2199,6 +2363,9 @@
 	    glClear (GL_COLOR_BUFFER_BIT);
     }
 
+    if (currentSync)
+	currentSync->insertWait ();
+
     // Disable everything that we don't usually need and could slow us down
     glDisable (GL_BLEND);
     glDisable (GL_STENCIL_TEST);
@@ -2352,6 +2519,8 @@
     doubleBuffer.render (paintRegion, fullscreen);
 
     lastMask = mask;
+
+    updateXToGLSyncs ();
 }
 
 unsigned int
@@ -2448,6 +2617,55 @@
 	updateFrameProvider ();
 	CompositeScreen::get (screen)->damageScreen ();
     }
+
+    // Check if the option to use sync objects has been enabled or disabled.
+    if (syncObjectsEnabled () && !syncObjectsInitialized ())
+    {
+	initXToGLSyncs ();
+    }
+    else if (!syncObjectsEnabled () && syncObjectsInitialized ())
+    {
+	destroyXToGLSyncs ();
+    }
+
+    if (currentSync)
+    {
+	if (!currentSync->isReady ())
+	{
+	    for (std::vector<XToGLSync*>::size_type i = xToGLSyncs.size () / 2; i > 0; i--)
+	    {
+		// try to check next sync
+		updateXToGLSyncs ();
+
+		// method updateXToGLSync may disable syncs
+		if (!currentSync)
+		    break;
+
+		if (currentSync->isReady ())
+		    break;
+	    }
+	}
+    }
+
+    if (currentSync)
+    {
+	if (!currentSync->isReady ())
+	{
+	    // If this happens, then we must have missed an event or update
+	    // somewhere. Destroy and recreate the sync objects to put us back
+	    // into a good state.
+	    destroyXToGLSyncs ();
+	    initXToGLSyncs ();
+	}
+    }
+
+    if (currentSync)
+    {
+	// Tell the server to trigger the fence object after all rendering has
+	// completed.
+	assert (currentSync->isReady ());
+	currentSync->trigger ();
+    }
 }
 
 bool

=== added file 'plugins/opengl/src/xtoglsync.cpp'
--- plugins/opengl/src/xtoglsync.cpp	1970-01-01 00:00:00 +0000
+++ plugins/opengl/src/xtoglsync.cpp	2014-12-10 19:46:40 +0000
@@ -0,0 +1,194 @@
+/*
+ * Copyright © 2011 NVIDIA Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * NVIDIA Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * NVIDIA Corporation makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: James Jones <jajones@nvidia.com>
+ */
+
+#include "opengl/xtoglsync.h"
+
+bool XToGLSync::syncValuesInitialized = false;
+XSyncValue XToGLSync::zero;
+XSyncValue XToGLSync::one;
+
+XToGLSync::XToGLSync () :
+    f (None),
+    fGL (NULL),
+    c (None),
+    a (None),
+    state (XToGLSync::XTOGLS_READY)
+{
+    Display *dpy = screen->dpy ();
+
+    f = XSyncCreateFence (dpy, DefaultRootWindow (dpy), False);
+    fGL = GL::importSync (GL_SYNC_X11_FENCE_EXT, f, 0);
+
+    if (!syncValuesInitialized)
+    {
+	XSyncIntToValue (&zero, 0);
+	XSyncIntToValue (&one, 1);
+	syncValuesInitialized = true;
+    }
+
+    XSyncIntToValue (&nextCounterValue, 1);
+    c = XSyncCreateCounter (dpy, zero);
+
+    XSyncAlarmAttributes alarmAttribs;
+    alarmAttribs.trigger.counter = c;
+    alarmAttribs.trigger.value_type = XSyncAbsolute;
+    alarmAttribs.trigger.wait_value = one;
+    alarmAttribs.trigger.test_type = XSyncPositiveTransition;
+    alarmAttribs.events = True;
+    a = XSyncCreateAlarm (dpy,
+			  XSyncCACounter |
+			  XSyncCAValueType |
+			  XSyncCAValue |
+			  XSyncCATestType |
+			  XSyncCAEvents,
+			  &alarmAttribs);
+
+}
+
+XToGLSync::~XToGLSync ()
+{
+    Display *dpy = screen->dpy ();
+
+    switch (state) {
+    case XTOGLS_WAITING:
+	break;
+
+    case XTOGLS_RESET_PENDING:
+	{
+	    XEvent ev;
+
+	    XIfEvent (dpy, &ev, &XToGLSync::alarmEventPredicate,
+		      reinterpret_cast<XPointer>(this));
+	    handleEvent(reinterpret_cast<XSyncAlarmNotifyEvent*>(&ev));
+	}
+	// Fall through.
+    case XTOGLS_READY:
+	XSyncTriggerFence (dpy, f);
+	XFlush (dpy);
+	break;
+
+    case XTOGLS_TRIGGER_SENT:
+    case XTOGLS_DONE:
+	// Nothing to do.
+	break;
+    }
+
+    GL::deleteSync (fGL);
+    XSyncDestroyFence (dpy, f);
+    XSyncDestroyCounter (dpy, c);
+    XSyncDestroyAlarm (dpy, a);
+}
+
+Bool XToGLSync::alarmEventPredicate (Display *dpy, XEvent *ev, XPointer arg)
+{
+    if (ev->type == screen->syncEvent () + XSyncAlarmNotify)
+    {
+	XToGLSync *sync = reinterpret_cast<XToGLSync*>(arg);
+	XSyncAlarmNotifyEvent *ae =
+	    reinterpret_cast<XSyncAlarmNotifyEvent*>(ev);
+
+	if (ae->alarm == sync->a)
+	    return True;
+    }
+
+    return False;
+}
+
+void XToGLSync::trigger (void)
+{
+    Display *dpy = screen->dpy ();
+    assert (state == XTOGLS_READY);
+
+    XSyncTriggerFence (dpy, f);
+    XFlush (dpy);
+
+    state = XTOGLS_TRIGGER_SENT;
+}
+
+void XToGLSync::insertWait (void)
+{
+    if (state != XTOGLS_TRIGGER_SENT)
+	return;
+
+    GL::waitSync (fGL, 0, GL_TIMEOUT_IGNORED);
+
+    state = XTOGLS_WAITING;
+}
+
+GLenum XToGLSync::checkUpdateFinished (GLuint64 timeout)
+{
+    GLenum status;
+
+    switch (state) {
+	case XTOGLS_DONE:
+	    return GL_ALREADY_SIGNALED;
+
+	case XTOGLS_WAITING:
+	    status = GL::clientWaitSync (fGL, 0, timeout);
+	    if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
+	    {
+		state = XTOGLS_DONE;
+	    }
+	    return status;
+
+	default:
+	    return GL_WAIT_FAILED;
+    }
+}
+
+void XToGLSync::reset (void)
+{
+    Display *dpy = screen->dpy ();
+    if (state != XTOGLS_DONE)
+    {
+	return;
+    }
+
+    XSyncResetFence (dpy, f);
+
+    XSyncAlarmAttributes values;
+    values.trigger.wait_value = nextCounterValue;
+    XSyncChangeAlarm (dpy, a, XSyncCAValue, &values);
+    XSyncSetCounter (dpy, c, nextCounterValue);
+
+    int overflow;
+    XSyncValueAdd (&nextCounterValue, nextCounterValue, one, &overflow);
+
+    state = XTOGLS_RESET_PENDING;
+}
+
+void XToGLSync::handleEvent (XSyncAlarmNotifyEvent* ae)
+{
+    if (ae->alarm == a)
+    {
+	if (state != XTOGLS_RESET_PENDING)
+	{
+	    return;
+	}
+
+	state = XTOGLS_READY;
+    }
+}
+

