From d6e7fbc4aa17018dd30a7bac1867947d948c9f57 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <fourdan@xfce.org>
Date: Wed, 1 Aug 2018 23:17:38 +0200
Subject: [PATCH] compositor: Use a fence to sync X and GL

Bug: 13519

Use a fence to prevent the pixmap updates to be picked up before
being complete, which causes visual glitches and blinking.

Signed-off-by: Olivier Fourdan <fourdan@xfce.org>
---
 src/compositor.c | 51 ++++++++++++++++++++++++++++++++++++++++++------
 src/screen.h     |  3 +++
 2 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index 8cbe17518..500f68fd6 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -39,6 +39,9 @@
 #ifdef HAVE_EPOXY
 #include <epoxy/gl.h>
 #include <epoxy/glx.h>
+#ifdef HAVE_XSYNC_EXTENSION
+#include <X11/extensions/sync.h>
+#endif /* HAVE_XSYNC_EXTENSION */
 #endif /* HAVE_EPOXY */
 
 #ifdef HAVE_PRESENT_EXTENSION
@@ -1449,6 +1452,40 @@ unbind_glx_texture (ScreenInfo *screen_info)
     check_gl_error();
 }
 
+static void
+fence_sync_pixmap (ScreenInfo *screen_info, Pixmap pixmap)
+{
+#ifdef HAVE_XSYNC
+    Bool triggered = False;
+
+    if (screen_info->fence == None)
+    {
+        screen_info->fence = XSyncCreateFence (myScreenGetXDisplay (screen_info), pixmap, FALSE);
+    }
+    if (!screen_info->fence)
+    {
+        TRACE ("Cannot create fence\n");
+        return;
+    }
+    if (!XSyncQueryFence(myScreenGetXDisplay (screen_info),
+                         screen_info->fence, &triggered))
+    {
+        TRACE ("Cannot query fence\n");
+        return;
+    }
+    if (triggered)
+    {
+        TRACE ("Fence already triggered\n");
+        return;
+    }
+    TRACE ("Awaiting fence of drawable 0x%x\n", pixmap);
+    XSyncTriggerFence(myScreenGetXDisplay (screen_info), screen_info->fence);
+    XSyncAwaitFence(myScreenGetXDisplay (screen_info), &screen_info->fence, 1);
+    XSyncResetFence(myScreenGetXDisplay (screen_info), screen_info->fence);
+    TRACE ("Fence for drawable 0x%x cleared\n", pixmap);
+#endif /* HAVE_XSYNC */
+}
+
 static void
 bind_glx_texture (ScreenInfo *screen_info, Pixmap pixmap)
 {
@@ -1465,7 +1502,6 @@ bind_glx_texture (ScreenInfo *screen_info, Pixmap pixmap)
     {
         screen_info->glx_drawable = create_glx_drawable (screen_info, pixmap);
     }
-
     TRACE ("(re)Binding GLX pixmap 0x%lx to texture 0x%x",
            screen_info->glx_drawable, screen_info->rootTexture);
     enable_glx_texture (screen_info);
@@ -1501,9 +1537,6 @@ redraw_glx_texture (ScreenInfo *screen_info)
     TRACE ("(re)Drawing GLX pixmap 0x%lx/texture 0x%x",
            screen_info->glx_drawable, screen_info->rootTexture);
 
-    /* Make sure previous updates are completed */
-    glXWaitX ();
-
     glMatrixMode(GL_TEXTURE);
     glPushMatrix();
 
@@ -1551,8 +1584,6 @@ redraw_glx_texture (ScreenInfo *screen_info)
     glXReleaseTexImageEXT (myScreenGetXDisplay (screen_info),
                            screen_info->glx_drawable, GLX_FRONT_EXT);
 
-    glXWaitGL ();
-
     check_gl_error();
 }
 #endif /* HAVE_EPOXY */
@@ -2212,6 +2243,8 @@ paint_all (ScreenInfo *screen_info, XserverRegion region, gushort buffer)
 #ifdef HAVE_EPOXY
     if (screen_info->use_glx)
     {
+        fence_sync_pixmap (screen_info,
+                           screen_info->rootPixmap[buffer]);
         bind_glx_texture (screen_info,
                           screen_info->rootPixmap[buffer]);
         redraw_glx_texture (screen_info);
@@ -4368,6 +4401,9 @@ compositorManageScreen (ScreenInfo *screen_info)
 
 #ifdef HAVE_EPOXY
     screen_info->use_glx = !screen_info->use_present &&
+#ifdef HAVE_XSYNC
+                            display_info->have_xsync &&
+#endif /* HAVE_XSYNC */
                            (display_info->vblank_method == VBLANK_AUTO ||
                             display_info->vblank_method == VBLANK_GLX);
 
@@ -4378,6 +4414,9 @@ compositorManageScreen (ScreenInfo *screen_info)
         screen_info->rootTexture = None;
         screen_info->glx_drawable = None;
         screen_info->texture_filter = GL_LINEAR;
+#ifdef HAVE_XSYNC
+        screen_info->fence = None;
+#endif /* HAVE_XSYNC */
         screen_info->use_glx = init_glx (screen_info);
     }
 #else /* HAVE_EPOXY */
diff --git a/src/screen.h b/src/screen.h
index 14a2d8443..01bc61cbc 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -217,6 +217,9 @@ struct _ScreenInfo
     GLXFBConfig glx_fbconfig;
     GLXContext glx_context;
     GLXWindow glx_window;
+#ifdef HAVE_XSYNC
+    XSyncFence fence;
+#endif /* HAVE_XSYNC */
 #endif /* HAVE_EPOXY */
 
 #ifdef HAVE_PRESENT_EXTENSION
-- 
GitLab