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

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