Blame SOURCES/Enable-threeaded-swap-wait.patch

67f8b7
From 4d1005e3b86050f8b5bab41baf08704117f89b21 Mon Sep 17 00:00:00 2001
67f8b7
From: "Owen W. Taylor" <otaylor@fishsoup.net>
67f8b7
Date: Thu, 11 Feb 2016 15:06:23 -0500
67f8b7
Subject: [PATCH 1/7] CoglGPUInfo - fix check for NVIDIA
67f8b7
67f8b7
NVIDIA drivers have a vendor of "NVIDIA Corporation" not "NVIDIA".
67f8b7
Check for both in case older drivers did use "NVIDIA"
67f8b7
67f8b7
https://bugzilla.gnome.org/show_bug.cgi?id=779039
67f8b7
---
67f8b7
 cogl/cogl/cogl-gpu-info.c | 3 ++-
67f8b7
 1 file changed, 2 insertions(+), 1 deletion(-)
67f8b7
67f8b7
diff --git a/cogl/cogl/cogl-gpu-info.c b/cogl/cogl/cogl-gpu-info.c
67f8b7
index 845382881..23a846616 100644
67f8b7
--- a/cogl/cogl/cogl-gpu-info.c
67f8b7
+++ b/cogl/cogl/cogl-gpu-info.c
67f8b7
@@ -169,7 +169,8 @@ check_qualcomm_vendor (const CoglGpuInfoStrings *strings)
67f8b7
 static CoglBool
67f8b7
 check_nvidia_vendor (const CoglGpuInfoStrings *strings)
67f8b7
 {
67f8b7
-  if (strcmp (strings->vendor_string, "NVIDIA") != 0)
67f8b7
+  if (strcmp (strings->vendor_string, "NVIDIA") != 0 &&
67f8b7
+      strcmp (strings->vendor_string, "NVIDIA Corporation") != 0)
67f8b7
     return FALSE;
67f8b7
 
67f8b7
   return TRUE;
67f8b7
-- 
67f8b7
2.12.0
67f8b7
67f8b7
67f8b7
From 62a66bddf3aba14e65ab913746237d3d19a502dd Mon Sep 17 00:00:00 2001
67f8b7
From: "Owen W. Taylor" <otaylor@fishsoup.net>
67f8b7
Date: Thu, 11 Feb 2016 16:33:03 -0500
67f8b7
Subject: [PATCH 2/7] CoglWinsysGLX: factor out some duplicated code
67f8b7
67f8b7
Add a helper function for repeated calls to clock_gettime(CLOCK_MONOTONIC)
67f8b7
67f8b7
https://bugzilla.gnome.org/show_bug.cgi?id=779039
67f8b7
---
67f8b7
 cogl/cogl/winsys/cogl-winsys-glx.c | 24 ++++++++++++------------
67f8b7
 1 file changed, 12 insertions(+), 12 deletions(-)
67f8b7
67f8b7
diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
index c50db3a04..379658e8a 100644
67f8b7
--- a/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
+++ b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
@@ -192,6 +192,15 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid)
67f8b7
   return NULL;
67f8b7
 }
67f8b7
 
67f8b7
+static int64_t
67f8b7
+get_monotonic_time_ns (void)
67f8b7
+{
67f8b7
+  struct timespec ts;
67f8b7
+
67f8b7
+  clock_gettime (CLOCK_MONOTONIC, &ts);
67f8b7
+  return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
67f8b7
+}
67f8b7
+
67f8b7
 static void
67f8b7
 ensure_ust_type (CoglRenderer *renderer,
67f8b7
                  GLXDrawable drawable)
67f8b7
@@ -202,7 +211,6 @@ ensure_ust_type (CoglRenderer *renderer,
67f8b7
   int64_t msc;
67f8b7
   int64_t sbc;
67f8b7
   struct timeval tv;
67f8b7
-  struct timespec ts;
67f8b7
   int64_t current_system_time;
67f8b7
   int64_t current_monotonic_time;
67f8b7
 
67f8b7
@@ -232,9 +240,7 @@ ensure_ust_type (CoglRenderer *renderer,
67f8b7
 
67f8b7
   /* This is the time source that the newer (fixed) linux drm
67f8b7
    * drivers use (Linux >= 3.8) */
67f8b7
-  clock_gettime (CLOCK_MONOTONIC, &ts);
67f8b7
-  current_monotonic_time = (ts.tv_sec * G_GINT64_CONSTANT (1000000)) +
67f8b7
-    (ts.tv_nsec / G_GINT64_CONSTANT (1000));
67f8b7
+  current_monotonic_time = get_monotonic_time_ns () / 1000;
67f8b7
 
67f8b7
   if (current_monotonic_time > ust - 1000000 &&
67f8b7
       current_monotonic_time < ust + 1000000)
67f8b7
@@ -310,10 +316,7 @@ _cogl_winsys_get_clock_time (CoglContext *context)
67f8b7
       }
67f8b7
     case COGL_GLX_UST_IS_MONOTONIC_TIME:
67f8b7
       {
67f8b7
-        struct timespec ts;
67f8b7
-
67f8b7
-        clock_gettime (CLOCK_MONOTONIC, &ts);
67f8b7
-        return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
67f8b7
+        return get_monotonic_time_ns ();
67f8b7
       }
67f8b7
     }
67f8b7
 
67f8b7
@@ -1682,16 +1685,13 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
67f8b7
       else
67f8b7
         {
67f8b7
           uint32_t current_count;
67f8b7
-          struct timespec ts;
67f8b7
 
67f8b7
           glx_renderer->glXGetVideoSync (&current_count);
67f8b7
           glx_renderer->glXWaitVideoSync (2,
67f8b7
                                           (current_count + 1) % 2,
67f8b7
                                           &current_count);
67f8b7
 
67f8b7
-          clock_gettime (CLOCK_MONOTONIC, &ts);
67f8b7
-          info->presentation_time =
67f8b7
-            ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
67f8b7
+          info->presentation_time = get_monotonic_time_ns ();
67f8b7
         }
67f8b7
     }
67f8b7
 }
67f8b7
-- 
67f8b7
2.12.0
67f8b7
67f8b7
67f8b7
From 69e156c91c663e6f41759eec9f7c729a67da7dc5 Mon Sep 17 00:00:00 2001
67f8b7
From: "Owen W. Taylor" <otaylor@fishsoup.net>
67f8b7
Date: Thu, 11 Feb 2016 17:04:08 -0500
67f8b7
Subject: [PATCH 3/7] Usability of SGI_video_sync is per-display not
67f8b7
 per-renderer
67f8b7
67f8b7
As previously commented in the code, SGI_video_sync is per-display, rather
67f8b7
than per-renderer. The is_direct flag for the renderer was tested before
67f8b7
it was initialized (per-display) and that resulted in SGI_video_sync
67f8b7
never being used.
67f8b7
67f8b7
https://bugzilla.gnome.org/show_bug.cgi?id=779039
67f8b7
---
67f8b7
 cogl/cogl/cogl-glx-display-private.h  |  3 ++
67f8b7
 cogl/cogl/cogl-glx-renderer-private.h |  2 --
67f8b7
 cogl/cogl/winsys/cogl-winsys-glx.c    | 52 +++++++++++++++++++----------------
67f8b7
 3 files changed, 31 insertions(+), 26 deletions(-)
67f8b7
67f8b7
diff --git a/cogl/cogl/cogl-glx-display-private.h b/cogl/cogl/cogl-glx-display-private.h
67f8b7
index 133c1188c..1d1afc0cf 100644
67f8b7
--- a/cogl/cogl/cogl-glx-display-private.h
67f8b7
+++ b/cogl/cogl/cogl-glx-display-private.h
67f8b7
@@ -51,6 +51,9 @@ typedef struct _CoglGLXDisplay
67f8b7
 
67f8b7
   CoglBool found_fbconfig;
67f8b7
   CoglBool fbconfig_has_rgba_visual;
67f8b7
+  CoglBool is_direct;
67f8b7
+  CoglBool have_vblank_counter;
67f8b7
+  CoglBool can_vblank_wait;
67f8b7
   GLXFBConfig fbconfig;
67f8b7
 
67f8b7
   /* Single context for all wins */
67f8b7
diff --git a/cogl/cogl/cogl-glx-renderer-private.h b/cogl/cogl/cogl-glx-renderer-private.h
67f8b7
index cb8ff97f8..061f2ccb5 100644
67f8b7
--- a/cogl/cogl/cogl-glx-renderer-private.h
67f8b7
+++ b/cogl/cogl/cogl-glx-renderer-private.h
67f8b7
@@ -43,8 +43,6 @@ typedef struct _CoglGLXRenderer
67f8b7
   int glx_error_base;
67f8b7
   int glx_event_base;
67f8b7
 
67f8b7
-  CoglBool is_direct;
67f8b7
-
67f8b7
   /* Vblank stuff */
67f8b7
   int dri_fd;
67f8b7
 
67f8b7
diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
index 379658e8a..5a2700176 100644
67f8b7
--- a/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
+++ b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
@@ -715,23 +715,25 @@ update_base_winsys_features (CoglRenderer *renderer)
67f8b7
 
67f8b7
   g_strfreev (split_extensions);
67f8b7
 
67f8b7
-  /* Note: the GLX_SGI_video_sync spec explicitly states this extension
67f8b7
-   * only works for direct contexts. */
67f8b7
-  if (!glx_renderer->is_direct)
67f8b7
-    {
67f8b7
-      glx_renderer->glXGetVideoSync = NULL;
67f8b7
-      glx_renderer->glXWaitVideoSync = NULL;
67f8b7
-      COGL_FLAGS_SET (glx_renderer->base_winsys_features,
67f8b7
-                      COGL_WINSYS_FEATURE_VBLANK_COUNTER,
67f8b7
-                      FALSE);
67f8b7
-    }
67f8b7
+  /* The GLX_SGI_video_sync spec explicitly states this extension
67f8b7
+   * only works for direct contexts; we don't know per-renderer
67f8b7
+   * if the context is direct or not, so we turn off the feature
67f8b7
+   * flag; we still use the extension within this file looking
67f8b7
+   * instead at glx_display->have_vblank_counter.
67f8b7
+   */
67f8b7
+  COGL_FLAGS_SET (glx_renderer->base_winsys_features,
67f8b7
+                  COGL_WINSYS_FEATURE_VBLANK_COUNTER,
67f8b7
+                  FALSE);
67f8b7
+
67f8b7
 
67f8b7
   COGL_FLAGS_SET (glx_renderer->base_winsys_features,
67f8b7
                   COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
67f8b7
                   TRUE);
67f8b7
 
67f8b7
-  if (glx_renderer->glXWaitVideoSync ||
67f8b7
-      glx_renderer->glXWaitForMsc)
67f8b7
+  /* Because of the direct-context dependency, the VBLANK_WAIT feature
67f8b7
+   * doesn't reflect the presence of GLX_SGI_video_sync.
67f8b7
+   */
67f8b7
+  if (glx_renderer->glXWaitForMsc)
67f8b7
     COGL_FLAGS_SET (glx_renderer->base_winsys_features,
67f8b7
                     COGL_WINSYS_FEATURE_VBLANK_WAIT,
67f8b7
                     TRUE);
67f8b7
@@ -864,7 +866,7 @@ update_winsys_features (CoglContext *context, CoglError **error)
67f8b7
    * by the SwapInterval so we have to throttle swap_region requests
67f8b7
    * manually... */
67f8b7
   if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION) &&
67f8b7
-      _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT))
67f8b7
+      (glx_display->have_vblank_counter || glx_display->can_vblank_wait))
67f8b7
     COGL_FLAGS_SET (context->winsys_features,
67f8b7
                     COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
67f8b7
 
67f8b7
@@ -1142,11 +1144,13 @@ create_context (CoglDisplay *display, CoglError **error)
67f8b7
       return FALSE;
67f8b7
     }
67f8b7
 
67f8b7
-  glx_renderer->is_direct =
67f8b7
+  glx_display->is_direct =
67f8b7
     glx_renderer->glXIsDirect (xlib_renderer->xdpy, glx_display->glx_context);
67f8b7
+  glx_display->have_vblank_counter = glx_display->is_direct && glx_renderer->glXWaitVideoSync;
67f8b7
+  glx_display->can_vblank_wait = glx_renderer->glXWaitForMsc || glx_display->have_vblank_counter;
67f8b7
 
67f8b7
   COGL_NOTE (WINSYS, "Setting %s context",
67f8b7
-             glx_renderer->is_direct ? "direct" : "indirect");
67f8b7
+             glx_display->is_direct ? "direct" : "indirect");
67f8b7
 
67f8b7
   /* XXX: GLX doesn't let us make a context current without a window
67f8b7
    * so we create a dummy window that we can use while no CoglOnscreen
67f8b7
@@ -1658,12 +1662,13 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
67f8b7
   CoglContext *ctx = framebuffer->context;
67f8b7
   CoglGLXRenderer *glx_renderer;
67f8b7
   CoglXlibRenderer *xlib_renderer;
67f8b7
+  CoglGLXDisplay *glx_display;
67f8b7
 
67f8b7
   glx_renderer = ctx->display->renderer->winsys;
67f8b7
   xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer);
67f8b7
+  glx_display = ctx->display->winsys;
67f8b7
 
67f8b7
-  if (glx_renderer->glXWaitForMsc ||
67f8b7
-      glx_renderer->glXGetVideoSync)
67f8b7
+  if (glx_display->can_vblank_wait)
67f8b7
     {
67f8b7
       CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos);
67f8b7
 
67f8b7
@@ -1759,6 +1764,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
67f8b7
   CoglXlibRenderer *xlib_renderer =
67f8b7
     _cogl_xlib_renderer_get_data (context->display->renderer);
67f8b7
   CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
67f8b7
+  CoglGLXDisplay *glx_display = context->display->winsys;
67f8b7
   CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
67f8b7
   CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
67f8b7
   GLXDrawable drawable =
67f8b7
@@ -1815,9 +1821,8 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
67f8b7
 
67f8b7
   if (framebuffer->config.swap_throttled)
67f8b7
     {
67f8b7
-      have_counter =
67f8b7
-        _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER);
67f8b7
-      can_wait = _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT);
67f8b7
+      have_counter = glx_display->have_vblank_counter;
67f8b7
+      can_wait = glx_display->can_vblank_wait;
67f8b7
     }
67f8b7
   else
67f8b7
     {
67f8b7
@@ -1974,6 +1979,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
67f8b7
   CoglXlibRenderer *xlib_renderer =
67f8b7
     _cogl_xlib_renderer_get_data (context->display->renderer);
67f8b7
   CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
67f8b7
+  CoglGLXDisplay *glx_display = context->display->winsys;
67f8b7
   CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
67f8b7
   CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
67f8b7
   CoglBool have_counter;
67f8b7
@@ -1993,8 +1999,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
67f8b7
     {
67f8b7
       uint32_t end_frame_vsync_counter = 0;
67f8b7
 
67f8b7
-      have_counter =
67f8b7
-        _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER);
67f8b7
+      have_counter = glx_display->have_vblank_counter;
67f8b7
 
67f8b7
       /* If the swap_region API is also being used then we need to track
67f8b7
        * the vsync counter for each swap request so we can manually
67f8b7
@@ -2004,8 +2009,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
67f8b7
 
67f8b7
       if (!glx_renderer->glXSwapInterval)
67f8b7
         {
67f8b7
-          CoglBool can_wait =
67f8b7
-            _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT);
67f8b7
+          CoglBool can_wait = glx_display->can_vblank_wait;
67f8b7
 
67f8b7
           /* If we are going to wait for VBLANK manually, we not only
67f8b7
            * need to flush out pending drawing to the GPU before we
67f8b7
-- 
67f8b7
2.12.0
67f8b7
67f8b7
67f8b7
From 55b8900c1d66a4568ff261a0498d12ca857d2431 Mon Sep 17 00:00:00 2001
67f8b7
From: "Owen W. Taylor" <otaylor@fishsoup.net>
67f8b7
Date: Thu, 11 Feb 2016 17:12:09 -0500
67f8b7
Subject: [PATCH 4/7] Fix the get_clock_time() without GLX_OML_sync_control
67f8b7
67f8b7
When we don't have GLX_OML_sync_control, we still can set the
67f8b7
frame presentation time, but we always use the system monotonic time,
67f8b7
so return that from get_clock_time().
67f8b7
67f8b7
https://bugzilla.gnome.org/show_bug.cgi?id=779039
67f8b7
---
67f8b7
 cogl/cogl/winsys/cogl-winsys-glx.c | 3 +++
67f8b7
 1 file changed, 3 insertions(+)
67f8b7
67f8b7
diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
index 5a2700176..7ad1a3fdf 100644
67f8b7
--- a/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
+++ b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
@@ -296,6 +296,9 @@ _cogl_winsys_get_clock_time (CoglContext *context)
67f8b7
 {
67f8b7
   CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
67f8b7
 
67f8b7
+  if (!glx_renderer->glXWaitForMsc)
67f8b7
+    return get_monotonic_time_ns ();
67f8b7
+
67f8b7
   /* We don't call ensure_ust_type() because we don't have a drawable
67f8b7
    * to work with. cogl_get_clock_time() is documented to only work
67f8b7
    * once a valid, non-zero, timestamp has been retrieved from Cogl.
67f8b7
-- 
67f8b7
2.12.0
67f8b7
67f8b7
67f8b7
From cb784a7be6c72453bc441f03ced27a531ee687d5 Mon Sep 17 00:00:00 2001
67f8b7
From: "Owen W. Taylor" <otaylor@fishsoup.net>
67f8b7
Date: Thu, 11 Feb 2016 17:15:13 -0500
67f8b7
Subject: [PATCH 5/7] For NVIDIA proprietary drivers, implement sync events
67f8b7
 with a thread
67f8b7
67f8b7
It's a good guess that the buffer swap will occur at the next vblank,
67f8b7
so use glXWaitVideoSync in a separate thread to deliver a sync event
67f8b7
rather than just letting the client block when frame drawing, which
67f8b7
can signficantly change app logic as compared to the INTEL_swap_event
67f8b7
case.
67f8b7
67f8b7
https://bugzilla.gnome.org/show_bug.cgi?id=779039
67f8b7
---
67f8b7
 cogl/cogl/cogl-private.h           |   3 +
67f8b7
 cogl/cogl/winsys/cogl-winsys-glx.c | 294 +++++++++++++++++++++++++++++++++++--
67f8b7
 2 files changed, 286 insertions(+), 11 deletions(-)
67f8b7
67f8b7
diff --git a/cogl/cogl/cogl-private.h b/cogl/cogl/cogl-private.h
67f8b7
index 333955c65..e5dc9feda 100644
67f8b7
--- a/cogl/cogl/cogl-private.h
67f8b7
+++ b/cogl/cogl/cogl-private.h
67f8b7
@@ -77,6 +77,9 @@ typedef enum
67f8b7
   COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE,
67f8b7
   COGL_PRIVATE_FEATURE_GL_EMBEDDED,
67f8b7
   COGL_PRIVATE_FEATURE_GL_WEB,
67f8b7
+  /* This is currently only implemented for GLX, but isn't actually
67f8b7
+   * that winsys dependent */
67f8b7
+  COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT,
67f8b7
 
67f8b7
   COGL_N_PRIVATE_FEATURES
67f8b7
 } CoglPrivateFeature;
67f8b7
diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
index 7ad1a3fdf..1418d1501 100644
67f8b7
--- a/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
+++ b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
@@ -65,12 +65,16 @@
67f8b7
 #include <sys/types.h>
67f8b7
 #include <sys/stat.h>
67f8b7
 #include <sys/time.h>
67f8b7
+#include <errno.h>
67f8b7
 #include <fcntl.h>
67f8b7
 #include <time.h>
67f8b7
+#include <unistd.h>
67f8b7
 
67f8b7
 #include <GL/glx.h>
67f8b7
 #include <X11/Xlib.h>
67f8b7
 
67f8b7
+#include <glib.h>
67f8b7
+
67f8b7
 /* This is a relatively new extension */
67f8b7
 #ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
67f8b7
 #define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
67f8b7
@@ -100,6 +104,14 @@ typedef struct _CoglOnscreenGLX
67f8b7
   CoglBool pending_sync_notify;
67f8b7
   CoglBool pending_complete_notify;
67f8b7
   CoglBool pending_resize_notify;
67f8b7
+
67f8b7
+  GThread *swap_wait_thread;
67f8b7
+  GQueue *swap_wait_queue;
67f8b7
+  GCond swap_wait_cond;
67f8b7
+  GMutex swap_wait_mutex;
67f8b7
+  int swap_wait_pipe[2];
67f8b7
+  GLXContext swap_wait_context;
67f8b7
+  CoglBool closing_down;
67f8b7
 } CoglOnscreenGLX;
67f8b7
 
67f8b7
 typedef struct _CoglPixmapTextureEyeGLX
67f8b7
@@ -885,6 +897,28 @@ update_winsys_features (CoglContext *context, CoglError **error)
67f8b7
                       COGL_FEATURE_ID_PRESENTATION_TIME,
67f8b7
                       TRUE);
67f8b7
     }
67f8b7
+  else
67f8b7
+    {
67f8b7
+      CoglGpuInfo *info = &context->gpu;
67f8b7
+      if (glx_display->have_vblank_counter &&
67f8b7
+	  info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
67f8b7
+        {
67f8b7
+          COGL_FLAGS_SET (context->winsys_features,
67f8b7
+                          COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT, TRUE);
67f8b7
+          COGL_FLAGS_SET (context->winsys_features,
67f8b7
+                          COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, TRUE);
67f8b7
+          /* TODO: remove this deprecated feature */
67f8b7
+          COGL_FLAGS_SET (context->features,
67f8b7
+                          COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
67f8b7
+                          TRUE);
67f8b7
+          COGL_FLAGS_SET (context->features,
67f8b7
+                          COGL_FEATURE_ID_PRESENTATION_TIME,
67f8b7
+                          TRUE);
67f8b7
+          COGL_FLAGS_SET (context->private_features,
67f8b7
+                          COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT,
67f8b7
+                          TRUE);
67f8b7
+        }
67f8b7
+    }
67f8b7
 
67f8b7
   /* We'll manually handle queueing dirty events in response to
67f8b7
    * Expose events from X */
67f8b7
@@ -1481,7 +1515,8 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
67f8b7
     }
67f8b7
 
67f8b7
 #ifdef GLX_INTEL_swap_event
67f8b7
-  if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
67f8b7
+  if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT) &&
67f8b7
+      !_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT))
67f8b7
     {
67f8b7
       GLXDrawable drawable =
67f8b7
         glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
67f8b7
@@ -1524,6 +1559,31 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
67f8b7
       xlib_onscreen->output = NULL;
67f8b7
     }
67f8b7
 
67f8b7
+  if (glx_onscreen->swap_wait_thread)
67f8b7
+    {
67f8b7
+      g_mutex_lock (&glx_onscreen->swap_wait_mutex);
67f8b7
+      glx_onscreen->closing_down = TRUE;
67f8b7
+      g_cond_signal (&glx_onscreen->swap_wait_cond);
67f8b7
+      g_mutex_unlock (&glx_onscreen->swap_wait_mutex);
67f8b7
+      g_thread_join (glx_onscreen->swap_wait_thread);
67f8b7
+      glx_onscreen->swap_wait_thread = NULL;
67f8b7
+
67f8b7
+      g_cond_clear (&glx_onscreen->swap_wait_cond);
67f8b7
+      g_mutex_clear (&glx_onscreen->swap_wait_mutex);
67f8b7
+
67f8b7
+      g_queue_free (glx_onscreen->swap_wait_queue);
67f8b7
+      glx_onscreen->swap_wait_queue = NULL;
67f8b7
+
67f8b7
+      _cogl_poll_renderer_remove_fd (context->display->renderer,
67f8b7
+                                     glx_onscreen->swap_wait_pipe[0]);
67f8b7
+      
67f8b7
+      close (glx_onscreen->swap_wait_pipe[0]);
67f8b7
+      close (glx_onscreen->swap_wait_pipe[1]);
67f8b7
+
67f8b7
+      glx_renderer->glXDestroyContext (xlib_renderer->xdpy,
67f8b7
+                                       glx_onscreen->swap_wait_context);
67f8b7
+    }
67f8b7
+
67f8b7
   _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state);
67f8b7
 
67f8b7
   drawable =
67f8b7
@@ -1757,6 +1817,199 @@ set_frame_info_output (CoglOnscreen *onscreen,
67f8b7
     }
67f8b7
 }
67f8b7
 
67f8b7
+static gpointer
67f8b7
+threaded_swap_wait (gpointer data)
67f8b7
+{
67f8b7
+  CoglOnscreen *onscreen = data;
67f8b7
+
67f8b7
+  CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
67f8b7
+
67f8b7
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
67f8b7
+  CoglContext *context = framebuffer->context;
67f8b7
+  CoglDisplay *display = context->display;
67f8b7
+  CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer);
67f8b7
+  CoglGLXDisplay *glx_display = display->winsys;
67f8b7
+  CoglGLXRenderer *glx_renderer = display->renderer->winsys;
67f8b7
+  GLXDrawable dummy_drawable;
67f8b7
+
67f8b7
+  if (glx_display->dummy_glxwin)
67f8b7
+    dummy_drawable = glx_display->dummy_glxwin;
67f8b7
+  else
67f8b7
+    dummy_drawable = glx_display->dummy_xwin;
67f8b7
+
67f8b7
+  glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy,
67f8b7
+                                       dummy_drawable,
67f8b7
+                                       dummy_drawable,
67f8b7
+                                       glx_onscreen->swap_wait_context);
67f8b7
+
67f8b7
+  g_mutex_lock (&glx_onscreen->swap_wait_mutex);
67f8b7
+
67f8b7
+  while (TRUE)
67f8b7
+    {
67f8b7
+      gpointer queue_element;
67f8b7
+      uint32_t vblank_counter;
67f8b7
+
67f8b7
+      while (!glx_onscreen->closing_down && glx_onscreen->swap_wait_queue->length == 0)
67f8b7
+         g_cond_wait (&glx_onscreen->swap_wait_cond, &glx_onscreen->swap_wait_mutex);
67f8b7
+
67f8b7
+      if (glx_onscreen->closing_down)
67f8b7
+         break;
67f8b7
+
67f8b7
+      queue_element = g_queue_pop_tail (glx_onscreen->swap_wait_queue);
67f8b7
+      vblank_counter = GPOINTER_TO_UINT(queue_element);
67f8b7
+
67f8b7
+      g_mutex_unlock (&glx_onscreen->swap_wait_mutex);
67f8b7
+      glx_renderer->glXWaitVideoSync (2,
67f8b7
+                                      (vblank_counter + 1) % 2,
67f8b7
+                                      &vblank_counter);
67f8b7
+      g_mutex_lock (&glx_onscreen->swap_wait_mutex);
67f8b7
+
67f8b7
+      if (!glx_onscreen->closing_down)
67f8b7
+         {
67f8b7
+           int bytes_written = 0;
67f8b7
+
67f8b7
+           union {
67f8b7
+             char bytes[8];
67f8b7
+             int64_t presentation_time;
67f8b7
+           } u;
67f8b7
+
67f8b7
+           u.presentation_time = get_monotonic_time_ns ();
67f8b7
+
67f8b7
+           while (bytes_written < 8)
67f8b7
+             {
67f8b7
+               int res = write (glx_onscreen->swap_wait_pipe[1], u.bytes + bytes_written, 8 - bytes_written);
67f8b7
+               if (res == -1)
67f8b7
+                 {
67f8b7
+                   if (errno != EINTR)
67f8b7
+                     g_error ("Error writing to swap notification pipe: %s\n",
67f8b7
+                              g_strerror (errno));
67f8b7
+                 }
67f8b7
+               else
67f8b7
+                 {
67f8b7
+                   bytes_written += res;
67f8b7
+                 }
67f8b7
+             }
67f8b7
+         }
67f8b7
+    }
67f8b7
+
67f8b7
+  g_mutex_unlock (&glx_onscreen->swap_wait_mutex);
67f8b7
+
67f8b7
+  glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy,
67f8b7
+                                       None,
67f8b7
+                                       None,
67f8b7
+                                       NULL);
67f8b7
+
67f8b7
+  return NULL;
67f8b7
+}
67f8b7
+
67f8b7
+static int64_t
67f8b7
+threaded_swap_wait_pipe_prepare (void *user_data)
67f8b7
+{
67f8b7
+  return -1;
67f8b7
+}
67f8b7
+
67f8b7
+static void
67f8b7
+threaded_swap_wait_pipe_dispatch (void *user_data, int revents)
67f8b7
+{
67f8b7
+  CoglOnscreen *onscreen = user_data;
67f8b7
+  CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
67f8b7
+
67f8b7
+  CoglFrameInfo *info;
67f8b7
+
67f8b7
+  if ((revents & COGL_POLL_FD_EVENT_IN))
67f8b7
+    {
67f8b7
+      int bytes_read = 0;
67f8b7
+
67f8b7
+      union {
67f8b7
+         char bytes[8];
67f8b7
+         int64_t presentation_time;
67f8b7
+      } u;
67f8b7
+
67f8b7
+      while (bytes_read < 8)
67f8b7
+         {
67f8b7
+           int res = read (glx_onscreen->swap_wait_pipe[0], u.bytes + bytes_read, 8 - bytes_read);
67f8b7
+           if (res == -1)
67f8b7
+             {
67f8b7
+               if (errno != EINTR)
67f8b7
+                 g_error ("Error reading from swap notification pipe: %s\n",
67f8b7
+                          g_strerror (errno));
67f8b7
+             }
67f8b7
+           else
67f8b7
+             {
67f8b7
+               bytes_read += res;
67f8b7
+             }
67f8b7
+         }
67f8b7
+
67f8b7
+      set_sync_pending (onscreen);
67f8b7
+      set_complete_pending (onscreen);
67f8b7
+
67f8b7
+      info = g_queue_peek_head (&onscreen->pending_frame_infos);
67f8b7
+      info->presentation_time = u.presentation_time;
67f8b7
+    }
67f8b7
+}
67f8b7
+
67f8b7
+static void
67f8b7
+start_threaded_swap_wait (CoglOnscreen *onscreen,
67f8b7
+                           uint32_t      vblank_counter)
67f8b7
+{
67f8b7
+  CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
67f8b7
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
67f8b7
+  CoglContext *context = framebuffer->context;
67f8b7
+
67f8b7
+  if (glx_onscreen->swap_wait_thread == NULL)
67f8b7
+    {
67f8b7
+      CoglDisplay *display = context->display;
67f8b7
+      CoglGLXRenderer *glx_renderer = display->renderer->winsys;
67f8b7
+      CoglGLXDisplay *glx_display = display->winsys;
67f8b7
+      CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
67f8b7
+      CoglXlibRenderer *xlib_renderer =
67f8b7
+        _cogl_xlib_renderer_get_data (display->renderer);
67f8b7
+
67f8b7
+      GLXDrawable drawable =
67f8b7
+        glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
67f8b7
+      int i;
67f8b7
+
67f8b7
+      ensure_ust_type (display->renderer, drawable);
67f8b7
+      
67f8b7
+      if ((pipe (glx_onscreen->swap_wait_pipe) == -1))
67f8b7
+        g_error ("Couldn't create pipe for swap notification: %s\n",
67f8b7
+                 g_strerror (errno));
67f8b7
+
67f8b7
+      for (i = 0; i < 2; i++)
67f8b7
+	{
67f8b7
+	  if (fcntl(glx_onscreen->swap_wait_pipe[i], F_SETFD,
67f8b7
+		    fcntl(glx_onscreen->swap_wait_pipe[i], F_GETFD, 0) | FD_CLOEXEC) == -1)
67f8b7
+	    g_error ("Couldn't set swap notification pipe CLOEXEC: %s\n",
67f8b7
+		     g_strerror (errno));
67f8b7
+	}
67f8b7
+
67f8b7
+      _cogl_poll_renderer_add_fd (display->renderer,
67f8b7
+                                  glx_onscreen->swap_wait_pipe[0],
67f8b7
+                                  COGL_POLL_FD_EVENT_IN,
67f8b7
+                                  threaded_swap_wait_pipe_prepare,
67f8b7
+                                  threaded_swap_wait_pipe_dispatch,
67f8b7
+                                  onscreen);
67f8b7
+
67f8b7
+      glx_onscreen->swap_wait_queue = g_queue_new ();
67f8b7
+      g_mutex_init (&glx_onscreen->swap_wait_mutex);
67f8b7
+      g_cond_init (&glx_onscreen->swap_wait_cond);
67f8b7
+      glx_onscreen->swap_wait_context =
67f8b7
+         glx_renderer->glXCreateNewContext (xlib_renderer->xdpy,
67f8b7
+                                            glx_display->fbconfig,
67f8b7
+                                            GLX_RGBA_TYPE,
67f8b7
+                                            glx_display->glx_context,
67f8b7
+                                            True);
67f8b7
+      glx_onscreen->swap_wait_thread = g_thread_new ("cogl_glx_swap_wait",
67f8b7
+                                                     threaded_swap_wait,
67f8b7
+                                                     onscreen);
67f8b7
+    }
67f8b7
+
67f8b7
+  g_mutex_lock (&glx_onscreen->swap_wait_mutex);
67f8b7
+  g_queue_push_head (glx_onscreen->swap_wait_queue, GUINT_TO_POINTER(vblank_counter));
67f8b7
+  g_cond_signal (&glx_onscreen->swap_wait_cond);
67f8b7
+  g_mutex_unlock (&glx_onscreen->swap_wait_mutex);
67f8b7
+}
67f8b7
+
67f8b7
 static void
67f8b7
 _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
67f8b7
                                    const int *user_rectangles,
67f8b7
@@ -2000,19 +2253,38 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
67f8b7
 
67f8b7
   if (framebuffer->config.swap_throttled)
67f8b7
     {
67f8b7
-      uint32_t end_frame_vsync_counter = 0;
67f8b7
-
67f8b7
       have_counter = glx_display->have_vblank_counter;
67f8b7
 
67f8b7
-      /* If the swap_region API is also being used then we need to track
67f8b7
-       * the vsync counter for each swap request so we can manually
67f8b7
-       * throttle swap_region requests. */
67f8b7
-      if (have_counter)
67f8b7
-        end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context);
67f8b7
-
67f8b7
-      if (!glx_renderer->glXSwapInterval)
67f8b7
+      if (glx_renderer->glXSwapInterval)
67f8b7
         {
67f8b7
-          CoglBool can_wait = glx_display->can_vblank_wait;
67f8b7
+          if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT))
67f8b7
+            {
67f8b7
+	      /* If we didn't wait for the GPU here, then it's easy to get the case
67f8b7
+	       * where there is a VBlank between the point where we get the vsync counter
67f8b7
+	       * and the point where the GPU is ready to actually perform the glXSwapBuffers(),
67f8b7
+	       * and the swap wait terminates at the first VBlank rather than the one
67f8b7
+	       * where the swap buffers happens. Calling glFinish() here makes this a
67f8b7
+	       * rare race since the GPU is already ready to swap when we call glXSwapBuffers().
67f8b7
+	       * The glFinish() also prevents any serious damage if the rare race happens,
67f8b7
+	       * since it will wait for the preceding glXSwapBuffers() and prevent us from
67f8b7
+	       * getting premanently ahead. (For NVIDIA drivers, glFinish() after glXSwapBuffers()
67f8b7
+	       * waits for the buffer swap to happen.)
67f8b7
+	       */
67f8b7
+              _cogl_winsys_wait_for_gpu (onscreen);
67f8b7
+              start_threaded_swap_wait (onscreen, _cogl_winsys_get_vsync_counter (context));
67f8b7
+            }
67f8b7
+        }
67f8b7
+      else
67f8b7
+        {
67f8b7
+          CoglBool can_wait = have_counter || glx_display->can_vblank_wait;
67f8b7
+
67f8b7
+          uint32_t end_frame_vsync_counter = 0;
67f8b7
+
67f8b7
+          /* If the swap_region API is also being used then we need to track
67f8b7
+           * the vsync counter for each swap request so we can manually
67f8b7
+           * throttle swap_region requests. */
67f8b7
+          if (have_counter)
67f8b7
+            end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context);
67f8b7
 
67f8b7
           /* If we are going to wait for VBLANK manually, we not only
67f8b7
            * need to flush out pending drawing to the GPU before we
67f8b7
-- 
67f8b7
2.12.0
67f8b7
67f8b7
67f8b7
From fb0978b4ea33c88e7a42d4f478d60ef86e271414 Mon Sep 17 00:00:00 2001
67f8b7
From: "Owen W. Taylor" <otaylor@fishsoup.net>
67f8b7
Date: Wed, 29 Jun 2016 13:52:59 -0400
67f8b7
Subject: [PATCH 6/7] Add cogl_xlib_renderer_set_threaded_swap_wait_enabled()
67f8b7
67f8b7
Because the threaded-swap-wait functionality requires XInitThreads(),
67f8b7
and because it isn't clear that it is a win for all applications,
67f8b7
add a API function to conditionally enable it.
67f8b7
67f8b7
Fix the cogl-crate example not to just have a hard-coded dependency
67f8b7
on libX11.
67f8b7
67f8b7
https://bugzilla.gnome.org/show_bug.cgi?id=779039
67f8b7
---
67f8b7
 cogl/cogl/cogl-renderer-private.h  |  1 +
67f8b7
 cogl/cogl/cogl-renderer.c          | 11 +++++++++++
67f8b7
 cogl/cogl/cogl-xlib-renderer.h     | 30 ++++++++++++++++++++++++++++++
67f8b7
 cogl/cogl/winsys/cogl-winsys-glx.c |  1 +
67f8b7
 4 files changed, 43 insertions(+)
67f8b7
67f8b7
diff --git a/cogl/cogl/cogl-renderer-private.h b/cogl/cogl/cogl-renderer-private.h
67f8b7
index 8627b6cc6..33ed0ceac 100644
67f8b7
--- a/cogl/cogl/cogl-renderer-private.h
67f8b7
+++ b/cogl/cogl/cogl-renderer-private.h
67f8b7
@@ -69,6 +69,7 @@ struct _CoglRenderer
67f8b7
   Display *foreign_xdpy;
67f8b7
   CoglBool xlib_enable_event_retrieval;
67f8b7
   CoglBool xlib_want_reset_on_video_memory_purge;
67f8b7
+  CoglBool xlib_enable_threaded_swap_wait;
67f8b7
 #endif
67f8b7
 
67f8b7
   CoglDriver driver;
67f8b7
diff --git a/cogl/cogl/cogl-renderer.c b/cogl/cogl/cogl-renderer.c
67f8b7
index 51a04ffdd..e6575d808 100644
67f8b7
--- a/cogl/cogl/cogl-renderer.c
67f8b7
+++ b/cogl/cogl/cogl-renderer.c
67f8b7
@@ -285,6 +285,17 @@ cogl_xlib_renderer_request_reset_on_video_memory_purge (CoglRenderer *renderer,
67f8b7
 
67f8b7
   renderer->xlib_want_reset_on_video_memory_purge = enable;
67f8b7
 }
67f8b7
+
67f8b7
+void
67f8b7
+cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer,
67f8b7
+						   CoglBool enable)
67f8b7
+{
67f8b7
+  _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
67f8b7
+  /* NB: Renderers are considered immutable once connected */
67f8b7
+  _COGL_RETURN_IF_FAIL (!renderer->connected);
67f8b7
+
67f8b7
+  renderer->xlib_enable_threaded_swap_wait = enable;
67f8b7
+}
67f8b7
 #endif /* COGL_HAS_XLIB_SUPPORT */
67f8b7
 
67f8b7
 CoglBool
67f8b7
diff --git a/cogl/cogl/cogl-xlib-renderer.h b/cogl/cogl/cogl-xlib-renderer.h
67f8b7
index f3c1d7c09..3c0db189b 100644
67f8b7
--- a/cogl/cogl/cogl-xlib-renderer.h
67f8b7
+++ b/cogl/cogl/cogl-xlib-renderer.h
67f8b7
@@ -168,6 +168,36 @@ cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer,
67f8b7
                                                 CoglBool enable);
67f8b7
 
67f8b7
 /**
67f8b7
+ * cogl_xlib_renderer_set_threaded_swap_wait_enabled:
67f8b7
+ * @renderer: a #CoglRenderer
67f8b7
+ * @enable: The new value
67f8b7
+ *
67f8b7
+ * Sets whether Cogl is allowed to use a separate threaded to wait for the
67f8b7
+ * completion of glXSwapBuffers() and call the frame callback for the
67f8b7
+ * corresponding #CoglOnscreen. This is a way of emulating the
67f8b7
+ * INTEL_swap_event extension, and will only ever be used if
67f8b7
+ * INTEL_swap_event is not present; it will also only be used for
67f8b7
+ * specific white-listed drivers that are known to work correctly with
67f8b7
+ * multiple contexts sharing state between threads.
67f8b7
+ *
67f8b7
+ * The advantage of enabling this is that it will allow your main loop
67f8b7
+ * to do other work while waiting for the system to be ready to draw
67f8b7
+ * the next frame, instead of blocking in glXSwapBuffers(). A disadvantage
67f8b7
+ * is that the driver will be prevented from buffering up multiple frames
67f8b7
+ * even if it thinks that it would be advantageous. In general, this
67f8b7
+ * will work best for something like a system compositor that is doing
67f8b7
+ * simple drawing but handling lots of other complex tasks.
67f8b7
+ * 
67f8b7
+ * If you enable this, you must call XInitThreads() before any other
67f8b7
+ * X11 calls in your program. (See the documentation for XInitThreads())
67f8b7
+ *
67f8b7
+ * Stability: unstable
67f8b7
+ */
67f8b7
+void
67f8b7
+cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer,
67f8b7
+						   CoglBool enable);
67f8b7
+
67f8b7
+/**
67f8b7
  * cogl_xlib_renderer_get_display: (skip)
67f8b7
  */
67f8b7
 Display *
67f8b7
diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
index 1418d1501..74b0895d1 100644
67f8b7
--- a/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
+++ b/cogl/cogl/winsys/cogl-winsys-glx.c
67f8b7
@@ -901,6 +901,7 @@ update_winsys_features (CoglContext *context, CoglError **error)
67f8b7
     {
67f8b7
       CoglGpuInfo *info = &context->gpu;
67f8b7
       if (glx_display->have_vblank_counter &&
67f8b7
+	  context->display->renderer->xlib_enable_threaded_swap_wait &&
67f8b7
 	  info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
67f8b7
         {
67f8b7
           COGL_FLAGS_SET (context->winsys_features,
67f8b7
-- 
67f8b7
2.12.0
67f8b7
67f8b7
67f8b7
From 9505ce8cce4fe14443b5c9868e4e7301268a8d23 Mon Sep 17 00:00:00 2001
67f8b7
From: "Owen W. Taylor" <otaylor@fishsoup.net>
67f8b7
Date: Tue, 21 Feb 2017 13:51:16 -0500
67f8b7
Subject: [PATCH 7/7] Call cogl_xlib_renderer_set_threaded_swap_wait_enabled()
67f8b7
67f8b7
Set up things so that if the INTEL_swap_event extension is not present,
67f8b7
but the driver is known to have good thread support, we use an extra
67f8b7
thread and call glXWaitVideoSync() in the thread. This allows idles
67f8b7
to work properly, even when Mutter is constantly redrawing new frames;
67f8b7
otherwise, without INTEL_swap_event, we'll just block in glXSwapBuffers().
67f8b7
67f8b7
https://bugzilla.gnome.org/show_bug.cgi?id=779039
67f8b7
---
67f8b7
 src/backends/x11/meta-backend-x11.c  | 6 ++++++
67f8b7
 src/backends/x11/meta-renderer-x11.c | 8 ++++++++
67f8b7
 2 files changed, 14 insertions(+)
67f8b7
67f8b7
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
67f8b7
index a0b196efe..413b0622a 100644
67f8b7
--- a/src/backends/x11/meta-backend-x11.c
67f8b7
+++ b/src/backends/x11/meta-backend-x11.c
67f8b7
@@ -913,6 +913,12 @@ meta_backend_x11_init (MetaBackendX11 *x11)
67f8b7
 {
67f8b7
   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
67f8b7
 
67f8b7
+  /* XInitThreads() is needed to use the "threaded swap wait" functionality
67f8b7
+   * in Cogl - see meta_renderer_x11_create_cogl_renderer(). We call it here
67f8b7
+   * to hopefully call it before any other use of XLib.
67f8b7
+   */
67f8b7
+  XInitThreads();
67f8b7
+
67f8b7
   clutter_x11_request_reset_on_video_memory_purge ();
67f8b7
 
67f8b7
   /* We do X11 event retrieval ourselves */
67f8b7
diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c
67f8b7
index c0405bedc..9a86f493a 100644
67f8b7
--- a/src/backends/x11/meta-renderer-x11.c
67f8b7
+++ b/src/backends/x11/meta-renderer-x11.c
67f8b7
@@ -65,6 +65,14 @@ meta_renderer_x11_create_cogl_renderer (MetaRenderer *renderer)
67f8b7
   cogl_renderer_set_custom_winsys (cogl_renderer, get_x11_cogl_winsys_vtable);
67f8b7
   cogl_xlib_renderer_set_foreign_display (cogl_renderer, xdisplay);
67f8b7
 
67f8b7
+  /* Set up things so that if the INTEL_swap_event extension is not present,
67f8b7
+   * but the driver is known to have good thread support, we use an extra
67f8b7
+   * thread and call glXWaitVideoSync() in the thread. This allows idles
67f8b7
+   * to work properly, even when Mutter is constantly redrawing new frames;
67f8b7
+   * otherwise, without INTEL_swap_event, we'll just block in glXSwapBuffers().
67f8b7
+   */
67f8b7
+  cogl_xlib_renderer_set_threaded_swap_wait_enabled (cogl_renderer, TRUE);
67f8b7
+
67f8b7
   return cogl_renderer;
67f8b7
 }
67f8b7
 
67f8b7
-- 
67f8b7
2.12.0
67f8b7