Blame SOURCES/fix-nvidia-screen-flickering.patch

2c033f
From e13f43987b9cd3320441816de0b6b570be95c01f Mon Sep 17 00:00:00 2001
2c033f
From: Calvin Walton <calvin.walton@kepstin.ca>
2c033f
Date: Tue, 24 Mar 2015 11:21:25 -0400
2c033f
Subject: [PATCH 1/5] Include libXrender as a dependency, link it to libmutter
2c033f
2c033f
Mutter uses a function from libXrender (XRenderFindStandardFormat in
2c033f
src/x11/iconcache.c), but doesn't link to libXrender. This causes
2c033f
link issues on systems using the gold linker, particularly with
2c033f
-Wl,--as-needed.
2c033f
2c033f
Since mutter is using a function from libXrender, adding 'xrender'
2c033f
as a dependency seems appropriate, and fixes the issue.
2c033f
2c033f
https://bugzilla.gnome.org/show_bug.cgi?id=746692
2c033f
---
2c033f
 configure.ac | 1 +
2c033f
 1 file changed, 1 insertion(+)
2c033f
2c033f
diff --git a/configure.ac b/configure.ac
2c033f
index 74f4eeb..d193606 100644
2c033f
--- a/configure.ac
2c033f
+++ b/configure.ac
2c033f
@@ -88,6 +88,7 @@ MUTTER_PC_MODULES="
2c033f
    xi >= 1.6.0
2c033f
    xkbfile
2c033f
    xkeyboard-config
2c033f
+   xrender
2c033f
    xcb-randr
2c033f
 "
2c033f
 
2c033f
-- 
2c033f
2.5.0
2c033f
2c033f
2c033f
From 04173777a23549eea3823516483909112ac77303 Mon Sep 17 00:00:00 2001
2c033f
From: Rui Matos <tiagomatos@gmail.com>
2c033f
Date: Fri, 18 Apr 2014 20:21:20 +0200
2c033f
Subject: [PATCH 2/5] compositor: Add support for GL_EXT_x11_sync_object
2c033f
2c033f
If GL advertises this extension we'll use it to synchronize X with GL
2c033f
rendering instead of relying on the XSync() behavior with open source
2c033f
drivers.
2c033f
2c033f
Some driver bugs were uncovered while working on this so if we have
2c033f
had to reboot the ring a few times, something is probably wrong and
2c033f
we're likely to just make things worse by continuing to try.  Let's
2c033f
err on the side of caution, disable ourselves and fallback to the
2c033f
XSync() path in the compositor.
2c033f
2c033f
https://bugzilla.gnome.org/show_bug.cgi?id=728464
2c033f
---
2c033f
 configure.ac                        |   5 +
2c033f
 src/Makefile.am                     |   2 +
2c033f
 src/backends/x11/meta-backend-x11.c |   3 +
2c033f
 src/compositor/compositor-private.h |   4 +-
2c033f
 src/compositor/compositor.c         |  71 +++--
2c033f
 src/compositor/meta-sync-ring.c     | 566 ++++++++++++++++++++++++++++++++++++
2c033f
 src/compositor/meta-sync-ring.h     |  14 +
2c033f
 7 files changed, 641 insertions(+), 24 deletions(-)
2c033f
 create mode 100644 src/compositor/meta-sync-ring.c
2c033f
 create mode 100644 src/compositor/meta-sync-ring.h
2c033f
2c033f
diff --git a/configure.ac b/configure.ac
2c033f
index d193606..fe1c1eb 100644
2c033f
--- a/configure.ac
2c033f
+++ b/configure.ac
2c033f
@@ -312,6 +312,11 @@ fi
2c033f
 
2c033f
 GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
2c033f
 
2c033f
+AC_CHECK_DECL([GL_EXT_x11_sync_object],
2c033f
+              [],
2c033f
+              [AC_MSG_ERROR([GL_EXT_x11_sync_object definition not found, please update your GL headers])],
2c033f
+              [#include <GL/glx.h>])
2c033f
+
2c033f
 #### Warnings (last since -Werror can disturb other tests)
2c033f
 
2c033f
 # Stay command-line compatible with the gnome-common configure option. Here
2c033f
diff --git a/src/Makefile.am b/src/Makefile.am
2c033f
index e73a053..d7a44bc 100644
2c033f
--- a/src/Makefile.am
2c033f
+++ b/src/Makefile.am
2c033f
@@ -126,6 +126,8 @@ libmutter_la_SOURCES =				\
2c033f
 	compositor/meta-surface-actor.h		\
2c033f
 	compositor/meta-surface-actor-x11.c	\
2c033f
 	compositor/meta-surface-actor-x11.h	\
2c033f
+	compositor/meta-sync-ring.c		\
2c033f
+	compositor/meta-sync-ring.h		\
2c033f
 	compositor/meta-texture-rectangle.c	\
2c033f
 	compositor/meta-texture-rectangle.h	\
2c033f
 	compositor/meta-texture-tower.c		\
2c033f
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
2c033f
index 586f991..d77365d 100644
2c033f
--- a/src/backends/x11/meta-backend-x11.c
2c033f
+++ b/src/backends/x11/meta-backend-x11.c
2c033f
@@ -43,6 +43,7 @@
2c033f
 #include <meta/util.h>
2c033f
 #include "display-private.h"
2c033f
 #include "compositor/compositor-private.h"
2c033f
+#include "compositor/meta-sync-ring.h"
2c033f
 
2c033f
 struct _MetaBackendX11Private
2c033f
 {
2c033f
@@ -183,6 +184,8 @@ handle_host_xevent (MetaBackend *backend,
2c033f
         MetaCompositor *compositor = display->compositor;
2c033f
         if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event))
2c033f
           bypass_clutter = TRUE;
2c033f
+        if (compositor->have_x11_sync_object)
2c033f
+          meta_sync_ring_handle_event (event);
2c033f
       }
2c033f
   }
2c033f
 
2c033f
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
2c033f
index 80fb4e2..9e3e73d 100644
2c033f
--- a/src/compositor/compositor-private.h
2c033f
+++ b/src/compositor/compositor-private.h
2c033f
@@ -15,7 +15,8 @@ struct _MetaCompositor
2c033f
 {
2c033f
   MetaDisplay    *display;
2c033f
 
2c033f
-  guint           repaint_func_id;
2c033f
+  guint           pre_paint_func_id;
2c033f
+  guint           post_paint_func_id;
2c033f
 
2c033f
   gint64          server_time_query_time;
2c033f
   gint64          server_time_offset;
2c033f
@@ -40,6 +41,7 @@ struct _MetaCompositor
2c033f
   MetaPluginManager *plugin_mgr;
2c033f
 
2c033f
   gboolean frame_has_updated_xsurfaces;
2c033f
+  gboolean have_x11_sync_object;
2c033f
 };
2c033f
 
2c033f
 /* Wait 2ms after vblank before starting to draw next frame */
2c033f
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
2c033f
index 8bf469f..554faa1 100644
2c033f
--- a/src/compositor/compositor.c
2c033f
+++ b/src/compositor/compositor.c
2c033f
@@ -79,6 +79,7 @@
2c033f
 #include "frame.h"
2c033f
 #include <X11/extensions/shape.h>
2c033f
 #include <X11/extensions/Xcomposite.h>
2c033f
+#include "meta-sync-ring.h"
2c033f
 
2c033f
 #include "backends/x11/meta-backend-x11.h"
2c033f
 
2c033f
@@ -125,7 +126,11 @@ meta_switch_workspace_completed (MetaCompositor *compositor)
2c033f
 void
2c033f
 meta_compositor_destroy (MetaCompositor *compositor)
2c033f
 {
2c033f
-  clutter_threads_remove_repaint_func (compositor->repaint_func_id);
2c033f
+  clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
2c033f
+  clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
2c033f
+
2c033f
+  if (compositor->have_x11_sync_object)
2c033f
+    meta_sync_ring_destroy ();
2c033f
 }
2c033f
 
2c033f
 static void
2c033f
@@ -468,13 +473,11 @@ meta_compositor_manage (MetaCompositor *compositor)
2c033f
   MetaDisplay *display = compositor->display;
2c033f
   Display *xdisplay = display->xdisplay;
2c033f
   MetaScreen *screen = display->screen;
2c033f
+  MetaBackend *backend = meta_get_backend ();
2c033f
 
2c033f
   meta_screen_set_cm_selection (display->screen);
2c033f
 
2c033f
-  {
2c033f
-    MetaBackend *backend = meta_get_backend ();
2c033f
-    compositor->stage = meta_backend_get_stage (backend);
2c033f
-  }
2c033f
+  compositor->stage = meta_backend_get_stage (backend);
2c033f
 
2c033f
   /* We use connect_after() here to accomodate code in GNOME Shell that,
2c033f
    * when benchmarking drawing performance, connects to ::after-paint
2c033f
@@ -510,7 +513,7 @@ meta_compositor_manage (MetaCompositor *compositor)
2c033f
 
2c033f
       compositor->output = screen->composite_overlay_window;
2c033f
 
2c033f
-      xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (meta_get_backend ()));
2c033f
+      xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
2c033f
 
2c033f
       XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
2c033f
 
2c033f
@@ -530,6 +533,9 @@ meta_compositor_manage (MetaCompositor *compositor)
2c033f
        * contents until we show the stage.
2c033f
        */
2c033f
       XMapWindow (xdisplay, compositor->output);
2c033f
+
2c033f
+      compositor->have_x11_sync_object =
2c033f
+        meta_sync_ring_init (meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)));
2c033f
     }
2c033f
 
2c033f
   redirect_windows (display->screen);
2c033f
@@ -1044,11 +1050,12 @@ frame_callback (CoglOnscreen  *onscreen,
2c033f
     }
2c033f
 }
2c033f
 
2c033f
-static void
2c033f
-pre_paint_windows (MetaCompositor *compositor)
2c033f
+static gboolean
2c033f
+meta_pre_paint_func (gpointer data)
2c033f
 {
2c033f
   GList *l;
2c033f
   MetaWindowActor *top_window;
2c033f
+  MetaCompositor *compositor = data;
2c033f
 
2c033f
   if (compositor->onscreen == NULL)
2c033f
     {
2c033f
@@ -1060,7 +1067,7 @@ pre_paint_windows (MetaCompositor *compositor)
2c033f
     }
2c033f
 
2c033f
   if (compositor->windows == NULL)
2c033f
-    return;
2c033f
+    return TRUE;
2c033f
 
2c033f
   top_window = g_list_last (compositor->windows)->data;
2c033f
 
2c033f
@@ -1077,10 +1084,12 @@ pre_paint_windows (MetaCompositor *compositor)
2c033f
     {
2c033f
       /* We need to make sure that any X drawing that happens before
2c033f
        * the XDamageSubtract() for each window above is visible to
2c033f
-       * subsequent GL rendering; the only standardized way to do this
2c033f
-       * is EXT_x11_sync_object, which isn't yet widely available. For
2c033f
-       * now, we count on details of Xorg and the open source drivers,
2c033f
-       * and hope for the best otherwise.
2c033f
+       * subsequent GL rendering; the standardized way to do this is
2c033f
+       * GL_EXT_X11_sync_object. Since this isn't implemented yet in
2c033f
+       * mesa, we also have a path that relies on the implementation
2c033f
+       * of the open source drivers.
2c033f
+       *
2c033f
+       * Anything else, we just hope for the best.
2c033f
        *
2c033f
        * Xorg and open source driver specifics:
2c033f
        *
2c033f
@@ -1095,18 +1104,28 @@ pre_paint_windows (MetaCompositor *compositor)
2c033f
        * round trip request at this point is sufficient to flush the
2c033f
        * GLX buffers.
2c033f
        */
2c033f
-      XSync (compositor->display->xdisplay, False);
2c033f
-
2c033f
-      compositor->frame_has_updated_xsurfaces = FALSE;
2c033f
+      if (compositor->have_x11_sync_object)
2c033f
+        compositor->have_x11_sync_object = meta_sync_ring_insert_wait ();
2c033f
+      else
2c033f
+        XSync (compositor->display->xdisplay, False);
2c033f
     }
2c033f
+
2c033f
+  return TRUE;
2c033f
 }
2c033f
 
2c033f
 static gboolean
2c033f
-meta_repaint_func (gpointer data)
2c033f
+meta_post_paint_func (gpointer data)
2c033f
 {
2c033f
   MetaCompositor *compositor = data;
2c033f
-  if (meta_screen_get_n_monitors (compositor->display->screen) > 0)
2c033f
-    pre_paint_windows (compositor);
2c033f
+
2c033f
+  if (compositor->frame_has_updated_xsurfaces)
2c033f
+    {
2c033f
+      if (compositor->have_x11_sync_object)
2c033f
+        compositor->have_x11_sync_object = meta_sync_ring_after_frame ();
2c033f
+
2c033f
+      compositor->frame_has_updated_xsurfaces = FALSE;
2c033f
+    }
2c033f
+
2c033f
   return TRUE;
2c033f
 }
2c033f
 
2c033f
@@ -1141,10 +1160,16 @@ meta_compositor_new (MetaDisplay *display)
2c033f
                     G_CALLBACK (on_shadow_factory_changed),
2c033f
                     compositor);
2c033f
 
2c033f
-  compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
2c033f
-                                                                  compositor,
2c033f
-                                                                  NULL);
2c033f
-
2c033f
+  compositor->pre_paint_func_id =
2c033f
+    clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
2c033f
+                                           meta_pre_paint_func,
2c033f
+                                           compositor,
2c033f
+                                           NULL);
2c033f
+  compositor->post_paint_func_id =
2c033f
+    clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
2c033f
+                                           meta_post_paint_func,
2c033f
+                                           compositor,
2c033f
+                                           NULL);
2c033f
   return compositor;
2c033f
 }
2c033f
 
2c033f
diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
2c033f
new file mode 100644
2c033f
index 0000000..4ee61f8
2c033f
--- /dev/null
2c033f
+++ b/src/compositor/meta-sync-ring.c
2c033f
@@ -0,0 +1,566 @@
2c033f
+/*
2c033f
+ * This is based on an original C++ implementation for compiz that
2c033f
+ * carries the following copyright notice:
2c033f
+ *
2c033f
+ *
2c033f
+ * Copyright © 2011 NVIDIA Corporation
2c033f
+ *
2c033f
+ * Permission to use, copy, modify, distribute, and sell this software
2c033f
+ * and its documentation for any purpose is hereby granted without
2c033f
+ * fee, provided that the above copyright notice appear in all copies
2c033f
+ * and that both that copyright notice and this permission notice
2c033f
+ * appear in supporting documentation, and that the name of NVIDIA
2c033f
+ * Corporation not be used in advertising or publicity pertaining to
2c033f
+ * distribution of the software without specific, written prior
2c033f
+ * permission.  NVIDIA Corporation makes no representations about the
2c033f
+ * suitability of this software for any purpose. It is provided "as
2c033f
+ * is" without express or implied warranty.
2c033f
+ *
2c033f
+ * NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
2c033f
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
2c033f
+ * FITNESS, IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
2c033f
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2c033f
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
2c033f
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
2c033f
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2c033f
+ * SOFTWARE.
2c033f
+ *
2c033f
+ * Authors: James Jones <jajones@nvidia.com>
2c033f
+ */
2c033f
+
2c033f
+#include <string.h>
2c033f
+
2c033f
+#include <GL/gl.h>
2c033f
+#include <GL/glx.h>
2c033f
+#include <X11/extensions/sync.h>
2c033f
+
2c033f
+#include <cogl/cogl.h>
2c033f
+#include <clutter/clutter.h>
2c033f
+
2c033f
+#include <meta/util.h>
2c033f
+
2c033f
+#include "meta-sync-ring.h"
2c033f
+
2c033f
+/* Theory of operation:
2c033f
+ *
2c033f
+ * We use a ring of NUM_SYNCS fence objects. On each frame we advance
2c033f
+ * to the next fence in the ring. For each fence we do:
2c033f
+ *
2c033f
+ * 1. fence is XSyncTriggerFence()'d and glWaitSync()'d
2c033f
+ * 2. NUM_SYNCS / 2 frames later, fence should be triggered
2c033f
+ * 3. fence is XSyncResetFence()'d
2c033f
+ * 4. NUM_SYNCS / 2 frames later, fence should be reset
2c033f
+ * 5. go back to 1 and re-use fence
2c033f
+ *
2c033f
+ * glClientWaitSync() and XAlarms are used in steps 2 and 4,
2c033f
+ * respectively, to double-check the expectections.
2c033f
+ */
2c033f
+
2c033f
+#define NUM_SYNCS 10
2c033f
+#define MAX_SYNC_WAIT_TIME (1 * 1000 * 1000 * 1000) /* one sec */
2c033f
+#define MAX_REBOOT_ATTEMPTS 2
2c033f
+
2c033f
+typedef enum
2c033f
+{
2c033f
+  META_SYNC_STATE_READY,
2c033f
+  META_SYNC_STATE_WAITING,
2c033f
+  META_SYNC_STATE_DONE,
2c033f
+  META_SYNC_STATE_RESET_PENDING,
2c033f
+} MetaSyncState;
2c033f
+
2c033f
+typedef struct
2c033f
+{
2c033f
+  Display *xdisplay;
2c033f
+
2c033f
+  XSyncFence xfence;
2c033f
+  GLsync glsync;
2c033f
+
2c033f
+  XSyncCounter xcounter;
2c033f
+  XSyncAlarm xalarm;
2c033f
+  XSyncValue next_counter_value;
2c033f
+
2c033f
+  MetaSyncState state;
2c033f
+} MetaSync;
2c033f
+
2c033f
+typedef struct
2c033f
+{
2c033f
+  Display *xdisplay;
2c033f
+  int xsync_event_base;
2c033f
+  int xsync_error_base;
2c033f
+
2c033f
+  GHashTable *alarm_to_sync;
2c033f
+
2c033f
+  MetaSync *syncs_array[NUM_SYNCS];
2c033f
+  guint current_sync_idx;
2c033f
+  MetaSync *current_sync;
2c033f
+  guint warmup_syncs;
2c033f
+
2c033f
+  guint reboots;
2c033f
+} MetaSyncRing;
2c033f
+
2c033f
+static MetaSyncRing meta_sync_ring = { 0 };
2c033f
+
2c033f
+static XSyncValue SYNC_VALUE_ZERO;
2c033f
+static XSyncValue SYNC_VALUE_ONE;
2c033f
+
2c033f
+static const char*      (*meta_gl_get_string) (GLenum name);
2c033f
+static void             (*meta_gl_get_integerv) (GLenum  pname,
2c033f
+                                                 GLint  *params);
2c033f
+static const char*      (*meta_gl_get_stringi) (GLenum name,
2c033f
+                                                GLuint index);
2c033f
+static void             (*meta_gl_delete_sync) (GLsync sync);
2c033f
+static GLenum           (*meta_gl_client_wait_sync) (GLsync sync,
2c033f
+                                                     GLbitfield flags,
2c033f
+                                                     GLuint64 timeout);
2c033f
+static void             (*meta_gl_wait_sync) (GLsync sync,
2c033f
+                                              GLbitfield flags,
2c033f
+                                              GLuint64 timeout);
2c033f
+static GLsync           (*meta_gl_import_sync) (GLenum external_sync_type,
2c033f
+                                                GLintptr external_sync,
2c033f
+                                                GLbitfield flags);
2c033f
+
2c033f
+static MetaSyncRing *
2c033f
+meta_sync_ring_get (void)
2c033f
+{
2c033f
+  if (meta_sync_ring.reboots > MAX_REBOOT_ATTEMPTS)
2c033f
+    return NULL;
2c033f
+
2c033f
+  return &meta_sync_ring;
2c033f
+}
2c033f
+
2c033f
+static gboolean
2c033f
+load_gl_symbol (const char  *name,
2c033f
+                void       **func)
2c033f
+{
2c033f
+  *func = cogl_get_proc_address (name);
2c033f
+  if (!*func)
2c033f
+    {
2c033f
+      meta_verbose ("MetaSyncRing: failed to resolve required GL symbol \"%s\"\n", name);
2c033f
+      return FALSE;
2c033f
+    }
2c033f
+  return TRUE;
2c033f
+}
2c033f
+
2c033f
+static gboolean
2c033f
+check_gl_extensions (void)
2c033f
+{
2c033f
+  ClutterBackend *backend;
2c033f
+  CoglContext *cogl_context;
2c033f
+  CoglDisplay *cogl_display;
2c033f
+  CoglRenderer *cogl_renderer;
2c033f
+
2c033f
+  backend = clutter_get_default_backend ();
2c033f
+  cogl_context = clutter_backend_get_cogl_context (backend);
2c033f
+  cogl_display = cogl_context_get_display (cogl_context);
2c033f
+  cogl_renderer = cogl_display_get_renderer (cogl_display);
2c033f
+
2c033f
+  switch (cogl_renderer_get_driver (cogl_renderer))
2c033f
+    {
2c033f
+    case COGL_DRIVER_GL3:
2c033f
+      {
2c033f
+        int num_extensions, i;
2c033f
+        gboolean arb_sync = FALSE;
2c033f
+        gboolean x11_sync_object = FALSE;
2c033f
+
2c033f
+        meta_gl_get_integerv (GL_NUM_EXTENSIONS, &num_extensions);
2c033f
+
2c033f
+        for (i = 0; i < num_extensions; ++i)
2c033f
+          {
2c033f
+            const char *ext = meta_gl_get_stringi (GL_EXTENSIONS, i);
2c033f
+
2c033f
+            if (g_strcmp0 ("GL_ARB_sync", ext) == 0)
2c033f
+              arb_sync = TRUE;
2c033f
+            else if (g_strcmp0 ("GL_EXT_x11_sync_object", ext) == 0)
2c033f
+              x11_sync_object = TRUE;
2c033f
+          }
2c033f
+
2c033f
+        return arb_sync && x11_sync_object;
2c033f
+      }
2c033f
+    case COGL_DRIVER_GL:
2c033f
+      {
2c033f
+        const char *extensions = meta_gl_get_string (GL_EXTENSIONS);
2c033f
+        return (extensions != NULL &&
2c033f
+                strstr (extensions, "GL_ARB_sync") != NULL &&
2c033f
+                strstr (extensions, "GL_EXT_x11_sync_object") != NULL);
2c033f
+      }
2c033f
+    default:
2c033f
+      break;
2c033f
+    }
2c033f
+
2c033f
+  return FALSE;
2c033f
+}
2c033f
+
2c033f
+static gboolean
2c033f
+load_required_symbols (void)
2c033f
+{
2c033f
+  static gboolean success = FALSE;
2c033f
+
2c033f
+  if (success)
2c033f
+    return TRUE;
2c033f
+
2c033f
+  /* We don't link against libGL directly because cogl may want to
2c033f
+   * use something else. This assumes that cogl has been initialized
2c033f
+   * and dynamically loaded libGL at this point.
2c033f
+   */
2c033f
+
2c033f
+  if (!load_gl_symbol ("glGetString", (void **) &meta_gl_get_string))
2c033f
+    goto out;
2c033f
+  if (!load_gl_symbol ("glGetIntegerv", (void **) &meta_gl_get_integerv))
2c033f
+    goto out;
2c033f
+  if (!load_gl_symbol ("glGetStringi", (void **) &meta_gl_get_stringi))
2c033f
+    goto out;
2c033f
+
2c033f
+  if (!check_gl_extensions ())
2c033f
+    {
2c033f
+      meta_verbose ("MetaSyncRing: couldn't find required GL extensions\n");
2c033f
+      goto out;
2c033f
+    }
2c033f
+
2c033f
+  if (!load_gl_symbol ("glDeleteSync", (void **) &meta_gl_delete_sync))
2c033f
+    goto out;
2c033f
+  if (!load_gl_symbol ("glClientWaitSync", (void **) &meta_gl_client_wait_sync))
2c033f
+    goto out;
2c033f
+  if (!load_gl_symbol ("glWaitSync", (void **) &meta_gl_wait_sync))
2c033f
+    goto out;
2c033f
+  if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
2c033f
+    goto out;
2c033f
+
2c033f
+  success = TRUE;
2c033f
+ out:
2c033f
+  return success;
2c033f
+}
2c033f
+
2c033f
+static void
2c033f
+meta_sync_insert (MetaSync *self)
2c033f
+{
2c033f
+  g_return_if_fail (self->state == META_SYNC_STATE_READY);
2c033f
+
2c033f
+  XSyncTriggerFence (self->xdisplay, self->xfence);
2c033f
+  XFlush (self->xdisplay);
2c033f
+
2c033f
+  meta_gl_wait_sync (self->glsync, 0, GL_TIMEOUT_IGNORED);
2c033f
+
2c033f
+  self->state = META_SYNC_STATE_WAITING;
2c033f
+}
2c033f
+
2c033f
+static GLenum
2c033f
+meta_sync_check_update_finished (MetaSync *self,
2c033f
+                                 GLuint64  timeout)
2c033f
+{
2c033f
+  GLenum status = GL_WAIT_FAILED;
2c033f
+
2c033f
+  switch (self->state)
2c033f
+    {
2c033f
+    case META_SYNC_STATE_DONE:
2c033f
+      status = GL_ALREADY_SIGNALED;
2c033f
+      break;
2c033f
+    case META_SYNC_STATE_WAITING:
2c033f
+      status = meta_gl_client_wait_sync (self->glsync, 0, timeout);
2c033f
+      if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
2c033f
+        self->state = META_SYNC_STATE_DONE;
2c033f
+      break;
2c033f
+    default:
2c033f
+      break;
2c033f
+    }
2c033f
+
2c033f
+  g_warn_if_fail (status != GL_WAIT_FAILED);
2c033f
+
2c033f
+  return status;
2c033f
+}
2c033f
+
2c033f
+static void
2c033f
+meta_sync_reset (MetaSync *self)
2c033f
+{
2c033f
+  XSyncAlarmAttributes attrs;
2c033f
+  int overflow;
2c033f
+
2c033f
+  g_return_if_fail (self->state == META_SYNC_STATE_DONE);
2c033f
+
2c033f
+  XSyncResetFence (self->xdisplay, self->xfence);
2c033f
+
2c033f
+  attrs.trigger.wait_value = self->next_counter_value;
2c033f
+
2c033f
+  XSyncChangeAlarm (self->xdisplay, self->xalarm, XSyncCAValue, &attrs);
2c033f
+  XSyncSetCounter (self->xdisplay, self->xcounter, self->next_counter_value);
2c033f
+
2c033f
+  XSyncValueAdd (&self->next_counter_value,
2c033f
+                 self->next_counter_value,
2c033f
+                 SYNC_VALUE_ONE,
2c033f
+                 &overflow);
2c033f
+
2c033f
+  self->state = META_SYNC_STATE_RESET_PENDING;
2c033f
+}
2c033f
+
2c033f
+static void
2c033f
+meta_sync_handle_event (MetaSync              *self,
2c033f
+                        XSyncAlarmNotifyEvent *event)
2c033f
+{
2c033f
+  g_return_if_fail (event->alarm == self->xalarm);
2c033f
+  g_return_if_fail (self->state == META_SYNC_STATE_RESET_PENDING);
2c033f
+
2c033f
+  self->state = META_SYNC_STATE_READY;
2c033f
+}
2c033f
+
2c033f
+static MetaSync *
2c033f
+meta_sync_new (Display *xdisplay)
2c033f
+{
2c033f
+  MetaSync *self;
2c033f
+  XSyncAlarmAttributes attrs;
2c033f
+
2c033f
+  self = g_malloc0 (sizeof (MetaSync));
2c033f
+
2c033f
+  self->xdisplay = xdisplay;
2c033f
+
2c033f
+  self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
2c033f
+  self->glsync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
2c033f
+
2c033f
+  self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
2c033f
+
2c033f
+  attrs.trigger.counter = self->xcounter;
2c033f
+  attrs.trigger.value_type = XSyncAbsolute;
2c033f
+  attrs.trigger.wait_value = SYNC_VALUE_ONE;
2c033f
+  attrs.trigger.test_type = XSyncPositiveTransition;
2c033f
+  attrs.events = TRUE;
2c033f
+  self->xalarm = XSyncCreateAlarm (xdisplay,
2c033f
+                                   XSyncCACounter |
2c033f
+                                   XSyncCAValueType |
2c033f
+                                   XSyncCAValue |
2c033f
+                                   XSyncCATestType |
2c033f
+                                   XSyncCAEvents,
2c033f
+                                   &attrs);
2c033f
+
2c033f
+  XSyncIntToValue (&self->next_counter_value, 1);
2c033f
+
2c033f
+  self->state = META_SYNC_STATE_READY;
2c033f
+
2c033f
+  return self;
2c033f
+}
2c033f
+
2c033f
+static Bool
2c033f
+alarm_event_predicate (Display  *dpy,
2c033f
+                       XEvent   *event,
2c033f
+                       XPointer  data)
2c033f
+{
2c033f
+  MetaSyncRing *ring = meta_sync_ring_get ();
2c033f
+
2c033f
+  if (!ring)
2c033f
+    return False;
2c033f
+
2c033f
+  if (event->type == ring->xsync_event_base + XSyncAlarmNotify)
2c033f
+    {
2c033f
+      if (((MetaSync *) data)->xalarm == ((XSyncAlarmNotifyEvent *) event)->alarm)
2c033f
+        return True;
2c033f
+    }
2c033f
+  return False;
2c033f
+}
2c033f
+
2c033f
+static void
2c033f
+meta_sync_free (MetaSync *self)
2c033f
+{
2c033f
+  /* When our assumptions don't hold, something has gone wrong but we
2c033f
+   * don't know what, so we reboot the ring. While doing that, we
2c033f
+   * trigger fences before deleting them to try to get ourselves out
2c033f
+   * of a potentially stuck GPU state.
2c033f
+   */
2c033f
+  switch (self->state)
2c033f
+    {
2c033f
+    case META_SYNC_STATE_WAITING:
2c033f
+    case META_SYNC_STATE_DONE:
2c033f
+      /* nothing to do */
2c033f
+      break;
2c033f
+    case META_SYNC_STATE_RESET_PENDING:
2c033f
+      {
2c033f
+        XEvent event;
2c033f
+        XIfEvent (self->xdisplay, &event, alarm_event_predicate, (XPointer) self);
2c033f
+        meta_sync_handle_event (self, (XSyncAlarmNotifyEvent *) &event);
2c033f
+      }
2c033f
+      /* fall through */
2c033f
+    case META_SYNC_STATE_READY:
2c033f
+      XSyncTriggerFence (self->xdisplay, self->xfence);
2c033f
+      XFlush (self->xdisplay);
2c033f
+      break;
2c033f
+    default:
2c033f
+      break;
2c033f
+    }
2c033f
+
2c033f
+  meta_gl_delete_sync (self->glsync);
2c033f
+  XSyncDestroyFence (self->xdisplay, self->xfence);
2c033f
+  XSyncDestroyCounter (self->xdisplay, self->xcounter);
2c033f
+  XSyncDestroyAlarm (self->xdisplay, self->xalarm);
2c033f
+
2c033f
+  g_free (self);
2c033f
+}
2c033f
+
2c033f
+gboolean
2c033f
+meta_sync_ring_init (Display *xdisplay)
2c033f
+{
2c033f
+  gint major, minor;
2c033f
+  guint i;
2c033f
+  MetaSyncRing *ring = meta_sync_ring_get ();
2c033f
+
2c033f
+  if (!ring)
2c033f
+    return FALSE;
2c033f
+
2c033f
+  g_return_val_if_fail (xdisplay != NULL, FALSE);
2c033f
+  g_return_val_if_fail (ring->xdisplay == NULL, FALSE);
2c033f
+
2c033f
+  if (!load_required_symbols ())
2c033f
+    return FALSE;
2c033f
+
2c033f
+  if (!XSyncQueryExtension (xdisplay, &ring->xsync_event_base, &ring->xsync_error_base) ||
2c033f
+      !XSyncInitialize (xdisplay, &major, &minor))
2c033f
+    return FALSE;
2c033f
+
2c033f
+  XSyncIntToValue (&SYNC_VALUE_ZERO, 0);
2c033f
+  XSyncIntToValue (&SYNC_VALUE_ONE, 1);
2c033f
+
2c033f
+  ring->xdisplay = xdisplay;
2c033f
+
2c033f
+  ring->alarm_to_sync = g_hash_table_new (NULL, NULL);
2c033f
+
2c033f
+  for (i = 0; i < NUM_SYNCS; ++i)
2c033f
+    {
2c033f
+      MetaSync *sync = meta_sync_new (ring->xdisplay);
2c033f
+      ring->syncs_array[i] = sync;
2c033f
+      g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync);
2c033f
+    }
2c033f
+
2c033f
+  ring->current_sync_idx = 0;
2c033f
+  ring->current_sync = ring->syncs_array[0];
2c033f
+  ring->warmup_syncs = 0;
2c033f
+
2c033f
+  return TRUE;
2c033f
+}
2c033f
+
2c033f
+void
2c033f
+meta_sync_ring_destroy (void)
2c033f
+{
2c033f
+  guint i;
2c033f
+  MetaSyncRing *ring = meta_sync_ring_get ();
2c033f
+
2c033f
+  if (!ring)
2c033f
+    return;
2c033f
+
2c033f
+  g_return_if_fail (ring->xdisplay != NULL);
2c033f
+
2c033f
+  ring->current_sync_idx = 0;
2c033f
+  ring->current_sync = NULL;
2c033f
+  ring->warmup_syncs = 0;
2c033f
+
2c033f
+  for (i = 0; i < NUM_SYNCS; ++i)
2c033f
+    meta_sync_free (ring->syncs_array[i]);
2c033f
+
2c033f
+  g_hash_table_destroy (ring->alarm_to_sync);
2c033f
+
2c033f
+  ring->xsync_event_base = 0;
2c033f
+  ring->xsync_error_base = 0;
2c033f
+  ring->xdisplay = NULL;
2c033f
+}
2c033f
+
2c033f
+static gboolean
2c033f
+meta_sync_ring_reboot (Display *xdisplay)
2c033f
+{
2c033f
+  MetaSyncRing *ring = meta_sync_ring_get ();
2c033f
+
2c033f
+  if (!ring)
2c033f
+    return FALSE;
2c033f
+
2c033f
+  meta_sync_ring_destroy ();
2c033f
+
2c033f
+  ring->reboots += 1;
2c033f
+
2c033f
+  if (!meta_sync_ring_get ())
2c033f
+    {
2c033f
+      meta_warning ("MetaSyncRing: Too many reboots -- disabling\n");
2c033f
+      return FALSE;
2c033f
+    }
2c033f
+
2c033f
+  return meta_sync_ring_init (xdisplay);
2c033f
+}
2c033f
+
2c033f
+gboolean
2c033f
+meta_sync_ring_after_frame (void)
2c033f
+{
2c033f
+  MetaSyncRing *ring = meta_sync_ring_get ();
2c033f
+
2c033f
+  if (!ring)
2c033f
+    return FALSE;
2c033f
+
2c033f
+  g_return_if_fail (ring->xdisplay != NULL);
2c033f
+
2c033f
+  if (ring->warmup_syncs >= NUM_SYNCS / 2)
2c033f
+    {
2c033f
+      guint reset_sync_idx = (ring->current_sync_idx + NUM_SYNCS - (NUM_SYNCS / 2)) % NUM_SYNCS;
2c033f
+      MetaSync *sync_to_reset = ring->syncs_array[reset_sync_idx];
2c033f
+
2c033f
+      GLenum status = meta_sync_check_update_finished (sync_to_reset, 0);
2c033f
+      if (status == GL_TIMEOUT_EXPIRED)
2c033f
+        {
2c033f
+          meta_warning ("MetaSyncRing: We should never wait for a sync -- add more syncs?\n");
2c033f
+          status = meta_sync_check_update_finished (sync_to_reset, MAX_SYNC_WAIT_TIME);
2c033f
+        }
2c033f
+
2c033f
+      if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED)
2c033f
+        {
2c033f
+          meta_warning ("MetaSyncRing: Timed out waiting for sync object.\n");
2c033f
+          return meta_sync_ring_reboot (ring->xdisplay);
2c033f
+        }
2c033f
+
2c033f
+      meta_sync_reset (sync_to_reset);
2c033f
+    }
2c033f
+  else
2c033f
+    {
2c033f
+      ring->warmup_syncs += 1;
2c033f
+    }
2c033f
+
2c033f
+  ring->current_sync_idx += 1;
2c033f
+  ring->current_sync_idx %= NUM_SYNCS;
2c033f
+
2c033f
+  ring->current_sync = ring->syncs_array[ring->current_sync_idx];
2c033f
+
2c033f
+  return TRUE;
2c033f
+}
2c033f
+
2c033f
+gboolean
2c033f
+meta_sync_ring_insert_wait (void)
2c033f
+{
2c033f
+  MetaSyncRing *ring = meta_sync_ring_get ();
2c033f
+
2c033f
+  if (!ring)
2c033f
+    return FALSE;
2c033f
+
2c033f
+  g_return_if_fail (ring->xdisplay != NULL);
2c033f
+
2c033f
+  if (ring->current_sync->state != META_SYNC_STATE_READY)
2c033f
+    {
2c033f
+      meta_warning ("MetaSyncRing: Sync object is not ready -- were events handled properly?\n");
2c033f
+      if (!meta_sync_ring_reboot (ring->xdisplay))
2c033f
+        return FALSE;
2c033f
+    }
2c033f
+
2c033f
+  meta_sync_insert (ring->current_sync);
2c033f
+
2c033f
+  return TRUE;
2c033f
+}
2c033f
+
2c033f
+void
2c033f
+meta_sync_ring_handle_event (XEvent *xevent)
2c033f
+{
2c033f
+  XSyncAlarmNotifyEvent *event;
2c033f
+  MetaSync *sync;
2c033f
+  MetaSyncRing *ring = meta_sync_ring_get ();
2c033f
+
2c033f
+  if (!ring)
2c033f
+    return;
2c033f
+
2c033f
+  g_return_if_fail (ring->xdisplay != NULL);
2c033f
+
2c033f
+  if (xevent->type != (ring->xsync_event_base + XSyncAlarmNotify))
2c033f
+    return;
2c033f
+
2c033f
+  event = (XSyncAlarmNotifyEvent *) xevent;
2c033f
+
2c033f
+  sync = g_hash_table_lookup (ring->alarm_to_sync, (gpointer) event->alarm);
2c033f
+  if (sync)
2c033f
+    meta_sync_handle_event (sync, event);
2c033f
+}
2c033f
diff --git a/src/compositor/meta-sync-ring.h b/src/compositor/meta-sync-ring.h
2c033f
new file mode 100644
2c033f
index 0000000..6dca8ef
2c033f
--- /dev/null
2c033f
+++ b/src/compositor/meta-sync-ring.h
2c033f
@@ -0,0 +1,14 @@
2c033f
+#ifndef _META_SYNC_RING_H_
2c033f
+#define _META_SYNC_RING_H_
2c033f
+
2c033f
+#include <glib.h>
2c033f
+
2c033f
+#include <X11/Xlib.h>
2c033f
+
2c033f
+gboolean meta_sync_ring_init (Display *dpy);
2c033f
+void meta_sync_ring_destroy (void);
2c033f
+gboolean meta_sync_ring_after_frame (void);
2c033f
+gboolean meta_sync_ring_insert_wait (void);
2c033f
+void meta_sync_ring_handle_event (XEvent *event);
2c033f
+
2c033f
+#endif  /* _META_SYNC_RING_H_ */
2c033f
-- 
2c033f
2.5.0
2c033f
2c033f
2c033f
From 8b889d6ff46971edd4af7f412275e116e293e72a Mon Sep 17 00:00:00 2001
2c033f
From: Aaron Plattner <aplattner@nvidia.com>
2c033f
Date: Mon, 3 Aug 2015 21:15:15 -0700
2c033f
Subject: [PATCH 3/5] compositor: Fix GL_EXT_x11_sync_object race condition
2c033f
2c033f
The compositor maintains a ring of shared fences with the X server in order to
2c033f
properly synchronize rendering between the X server and the compositor's GPU
2c033f
channel.  When all of the fences have been used, the compositor needs to reset
2c033f
one so that it can be reused.  It does this by first waiting on the CPU for the
2c033f
fence to become triggered, and then sending a request to the X server to reset
2c033f
the fence.
2c033f
2c033f
If the compositor's GPU channel is busy processing other work (e.g. the desktop
2c033f
switcher animation), then the X server may process the reset request before the
2c033f
GPU has consumed the fence.  This causes the GPU channel to hang.
2c033f
2c033f
Fix the problem by having the compositor's GPU channel trigger its own fence
2c033f
after waiting for the X server's fence.  Wait for that fence on the CPU before
2c033f
sending the reset request to the X server.  This ensures that the GPU has
2c033f
consumed the X11 fence before the server resets it.
2c033f
2c033f
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
2c033f
2c033f
https://bugzilla.gnome.org/show_bug.cgi?id=728464
2c033f
---
2c033f
 src/compositor/meta-sync-ring.c | 25 +++++++++++++++++++------
2c033f
 1 file changed, 19 insertions(+), 6 deletions(-)
2c033f
2c033f
diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
2c033f
index 4ee61f8..44b1c41 100644
2c033f
--- a/src/compositor/meta-sync-ring.c
2c033f
+++ b/src/compositor/meta-sync-ring.c
2c033f
@@ -73,7 +73,8 @@ typedef struct
2c033f
   Display *xdisplay;
2c033f
 
2c033f
   XSyncFence xfence;
2c033f
-  GLsync glsync;
2c033f
+  GLsync gl_x11_sync;
2c033f
+  GLsync gpu_fence;
2c033f
 
2c033f
   XSyncCounter xcounter;
2c033f
   XSyncAlarm xalarm;
2c033f
@@ -118,6 +119,8 @@ static void             (*meta_gl_wait_sync) (GLsync sync,
2c033f
 static GLsync           (*meta_gl_import_sync) (GLenum external_sync_type,
2c033f
                                                 GLintptr external_sync,
2c033f
                                                 GLbitfield flags);
2c033f
+static GLsync           (*meta_gl_fence_sync) (GLenum condition,
2c033f
+                                               GLbitfield flags);
2c033f
 
2c033f
 static MetaSyncRing *
2c033f
 meta_sync_ring_get (void)
2c033f
@@ -224,6 +227,8 @@ load_required_symbols (void)
2c033f
     goto out;
2c033f
   if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
2c033f
     goto out;
2c033f
+  if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync))
2c033f
+    goto out;
2c033f
 
2c033f
   success = TRUE;
2c033f
  out:
2c033f
@@ -238,7 +243,8 @@ meta_sync_insert (MetaSync *self)
2c033f
   XSyncTriggerFence (self->xdisplay, self->xfence);
2c033f
   XFlush (self->xdisplay);
2c033f
 
2c033f
-  meta_gl_wait_sync (self->glsync, 0, GL_TIMEOUT_IGNORED);
2c033f
+  meta_gl_wait_sync (self->gl_x11_sync, 0, GL_TIMEOUT_IGNORED);
2c033f
+  self->gpu_fence = meta_gl_fence_sync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
2c033f
 
2c033f
   self->state = META_SYNC_STATE_WAITING;
2c033f
 }
2c033f
@@ -255,9 +261,13 @@ meta_sync_check_update_finished (MetaSync *self,
2c033f
       status = GL_ALREADY_SIGNALED;
2c033f
       break;
2c033f
     case META_SYNC_STATE_WAITING:
2c033f
-      status = meta_gl_client_wait_sync (self->glsync, 0, timeout);
2c033f
+      status = meta_gl_client_wait_sync (self->gpu_fence, 0, timeout);
2c033f
       if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
2c033f
-        self->state = META_SYNC_STATE_DONE;
2c033f
+        {
2c033f
+          self->state = META_SYNC_STATE_DONE;
2c033f
+          meta_gl_delete_sync (self->gpu_fence);
2c033f
+          self->gpu_fence = 0;
2c033f
+        }
2c033f
       break;
2c033f
     default:
2c033f
       break;
2c033f
@@ -312,7 +322,8 @@ meta_sync_new (Display *xdisplay)
2c033f
   self->xdisplay = xdisplay;
2c033f
 
2c033f
   self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
2c033f
-  self->glsync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
2c033f
+  self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
2c033f
+  self->gpu_fence = 0;
2c033f
 
2c033f
   self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
2c033f
 
2c033f
@@ -365,6 +376,8 @@ meta_sync_free (MetaSync *self)
2c033f
   switch (self->state)
2c033f
     {
2c033f
     case META_SYNC_STATE_WAITING:
2c033f
+      meta_gl_delete_sync (self->gpu_fence);
2c033f
+      break;
2c033f
     case META_SYNC_STATE_DONE:
2c033f
       /* nothing to do */
2c033f
       break;
2c033f
@@ -383,7 +396,7 @@ meta_sync_free (MetaSync *self)
2c033f
       break;
2c033f
     }
2c033f
 
2c033f
-  meta_gl_delete_sync (self->glsync);
2c033f
+  meta_gl_delete_sync (self->gl_x11_sync);
2c033f
   XSyncDestroyFence (self->xdisplay, self->xfence);
2c033f
   XSyncDestroyCounter (self->xdisplay, self->xcounter);
2c033f
   XSyncDestroyAlarm (self->xdisplay, self->xalarm);
2c033f
-- 
2c033f
2.5.0
2c033f
2c033f
2c033f
From 271b864a3a5fe2a59523a0ead0667072170e7bbe Mon Sep 17 00:00:00 2001
2c033f
From: Ting-Wei Lan <lantw@src.gnome.org>
2c033f
Date: Sat, 8 Aug 2015 20:12:09 +0800
2c033f
Subject: [PATCH 4/5] build: Fix return value in meta-sync-ring.c
2c033f
2c033f
https://bugzilla.gnome.org/show_bug.cgi?id=753380
2c033f
---
2c033f
 src/compositor/meta-sync-ring.c | 4 ++--
2c033f
 1 file changed, 2 insertions(+), 2 deletions(-)
2c033f
2c033f
diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
2c033f
index 44b1c41..217ebe5 100644
2c033f
--- a/src/compositor/meta-sync-ring.c
2c033f
+++ b/src/compositor/meta-sync-ring.c
2c033f
@@ -499,7 +499,7 @@ meta_sync_ring_after_frame (void)
2c033f
   if (!ring)
2c033f
     return FALSE;
2c033f
 
2c033f
-  g_return_if_fail (ring->xdisplay != NULL);
2c033f
+  g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
2c033f
 
2c033f
   if (ring->warmup_syncs >= NUM_SYNCS / 2)
2c033f
     {
2c033f
@@ -542,7 +542,7 @@ meta_sync_ring_insert_wait (void)
2c033f
   if (!ring)
2c033f
     return FALSE;
2c033f
 
2c033f
-  g_return_if_fail (ring->xdisplay != NULL);
2c033f
+  g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
2c033f
 
2c033f
   if (ring->current_sync->state != META_SYNC_STATE_READY)
2c033f
     {
2c033f
-- 
2c033f
2.5.0
2c033f
2c033f
2c033f
From 4d4bd1fb39cf396733de4dff4f3041b5266b803a Mon Sep 17 00:00:00 2001
2c033f
From: Rui Matos <tiagomatos@gmail.com>
2c033f
Date: Wed, 12 Aug 2015 15:26:34 +0200
2c033f
Subject: [PATCH 5/5] compositor: Handle fences in the frontend X connection
2c033f
2c033f
Since mutter has two X connections and does damage handling on the
2c033f
frontend while fence triggering is done on the backend, we have a race
2c033f
between XDamageSubtract() and XSyncFenceTrigger() causing missed
2c033f
redraws in the GL_EXT_X11_sync_object path.
2c033f
2c033f
If the fence trigger gets processed first by the server, any client
2c033f
drawing that happens between that and the damage subtract being
2c033f
processed and is completely contained in the last damage event box
2c033f
that mutter got, won't be included in the current frame nor will it
2c033f
cause a new damage event.
2c033f
2c033f
A simple fix for this would be XSync()ing on the frontend connection
2c033f
after doing all the damage subtracts but that would add a round trip
2c033f
on every frame again which defeats the asynchronous design of X
2c033f
fences.
2c033f
2c033f
Instead, if we move fence handling to the frontend we automatically
2c033f
get the right ordering between damage subtracts and fence triggers.
2c033f
2c033f
https://bugzilla.gnome.org/show_bug.cgi?id=728464
2c033f
---
2c033f
 src/backends/x11/meta-backend-x11.c |  3 ---
2c033f
 src/compositor/compositor.c         |  6 ++++--
2c033f
 src/compositor/meta-sync-ring.c     | 15 ++++++++++++++-
2c033f
 3 files changed, 18 insertions(+), 6 deletions(-)
2c033f
2c033f
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
2c033f
index d77365d..586f991 100644
2c033f
--- a/src/backends/x11/meta-backend-x11.c
2c033f
+++ b/src/backends/x11/meta-backend-x11.c
2c033f
@@ -43,7 +43,6 @@
2c033f
 #include <meta/util.h>
2c033f
 #include "display-private.h"
2c033f
 #include "compositor/compositor-private.h"
2c033f
-#include "compositor/meta-sync-ring.h"
2c033f
 
2c033f
 struct _MetaBackendX11Private
2c033f
 {
2c033f
@@ -184,8 +183,6 @@ handle_host_xevent (MetaBackend *backend,
2c033f
         MetaCompositor *compositor = display->compositor;
2c033f
         if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event))
2c033f
           bypass_clutter = TRUE;
2c033f
-        if (compositor->have_x11_sync_object)
2c033f
-          meta_sync_ring_handle_event (event);
2c033f
       }
2c033f
   }
2c033f
 
2c033f
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
2c033f
index 554faa1..2e182c2 100644
2c033f
--- a/src/compositor/compositor.c
2c033f
+++ b/src/compositor/compositor.c
2c033f
@@ -534,8 +534,7 @@ meta_compositor_manage (MetaCompositor *compositor)
2c033f
        */
2c033f
       XMapWindow (xdisplay, compositor->output);
2c033f
 
2c033f
-      compositor->have_x11_sync_object =
2c033f
-        meta_sync_ring_init (meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)));
2c033f
+      compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay);
2c033f
     }
2c033f
 
2c033f
   redirect_windows (display->screen);
2c033f
@@ -737,6 +736,9 @@ meta_compositor_process_event (MetaCompositor *compositor,
2c033f
         process_damage (compositor, (XDamageNotifyEvent *) event, window);
2c033f
     }
2c033f
 
2c033f
+  if (compositor->have_x11_sync_object)
2c033f
+    meta_sync_ring_handle_event (event);
2c033f
+
2c033f
   /* Clutter needs to know about MapNotify events otherwise it will
2c033f
      think the stage is invisible */
2c033f
   if (!meta_is_wayland_compositor () && event->type == MapNotify)
2c033f
diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
2c033f
index 217ebe5..336ccd4 100644
2c033f
--- a/src/compositor/meta-sync-ring.c
2c033f
+++ b/src/compositor/meta-sync-ring.c
2c033f
@@ -322,7 +322,7 @@ meta_sync_new (Display *xdisplay)
2c033f
   self->xdisplay = xdisplay;
2c033f
 
2c033f
   self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
2c033f
-  self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
2c033f
+  self->gl_x11_sync = 0;
2c033f
   self->gpu_fence = 0;
2c033f
 
2c033f
   self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
2c033f
@@ -347,6 +347,13 @@ meta_sync_new (Display *xdisplay)
2c033f
   return self;
2c033f
 }
2c033f
 
2c033f
+static void
2c033f
+meta_sync_import (MetaSync *self)
2c033f
+{
2c033f
+  g_return_if_fail (self->gl_x11_sync == 0);
2c033f
+  self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
2c033f
+}
2c033f
+
2c033f
 static Bool
2c033f
 alarm_event_predicate (Display  *dpy,
2c033f
                        XEvent   *event,
2c033f
@@ -437,6 +444,12 @@ meta_sync_ring_init (Display *xdisplay)
2c033f
       ring->syncs_array[i] = sync;
2c033f
       g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync);
2c033f
     }
2c033f
+  /* Since the connection we create the X fences on isn't the same as
2c033f
+   * the one used for the GLX context, we need to XSync() here to
2c033f
+   * ensure glImportSync() succeeds. */
2c033f
+  XSync (xdisplay, False);
2c033f
+  for (i = 0; i < NUM_SYNCS; ++i)
2c033f
+    meta_sync_import (ring->syncs_array[i]);
2c033f
 
2c033f
   ring->current_sync_idx = 0;
2c033f
   ring->current_sync = ring->syncs_array[0];
2c033f
-- 
2c033f
2.5.0
2c033f