From e31a4722c43db908e1831f77559d7a721cc08c1d Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Wed, 29 Jun 2016 13:52:59 -0400
Subject: [PATCH] Add cogl_xlib_renderer_set_threaded_swap_wait_enabled()
Because the threaded-swap-wait functionality requires XInitThreads(),
and because it isn't clear that it is a win for all applications,
add a API function to conditionally enable it.
Fix the cogl-crate example not to just have a hard-coded dependency
on libX11.
---
cogl/cogl-renderer-private.h | 1 +
cogl/cogl-renderer.c | 11 +++++++++++
cogl/cogl-xlib-renderer.h | 30 ++++++++++++++++++++++++++++++
cogl/winsys/cogl-winsys-glx.c | 4 +++-
examples/cogl-crate.c | 32 ++++++++++++++++++++++++++++++--
5 files changed, 75 insertions(+), 3 deletions(-)
diff -up cogl-1.18.2/cogl/cogl-renderer.c.swap-wait-setter cogl-1.18.2/cogl/cogl-renderer.c
--- cogl-1.18.2/cogl/cogl-renderer.c.swap-wait-setter 2016-06-30 15:58:16.047534998 -0400
+++ cogl-1.18.2/cogl/cogl-renderer.c 2016-06-30 15:58:16.084535595 -0400
@@ -357,6 +357,17 @@ cogl_xlib_renderer_request_reset_on_vide
renderer->xlib_want_reset_on_video_memory_purge = enable;
}
+
+void
+cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer,
+ CoglBool enable)
+{
+ _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
+ /* NB: Renderers are considered immutable once connected */
+ _COGL_RETURN_IF_FAIL (!renderer->connected);
+
+ renderer->xlib_enable_threaded_swap_wait = enable;
+}
#endif /* COGL_HAS_XLIB_SUPPORT */
CoglBool
diff -up cogl-1.18.2/cogl/cogl-renderer-private.h.swap-wait-setter cogl-1.18.2/cogl/cogl-renderer-private.h
--- cogl-1.18.2/cogl/cogl-renderer-private.h.swap-wait-setter 2016-06-30 15:58:16.047534998 -0400
+++ cogl-1.18.2/cogl/cogl-renderer-private.h 2016-06-30 15:58:16.084535595 -0400
@@ -71,6 +71,7 @@ struct _CoglRenderer
Display *foreign_xdpy;
CoglBool xlib_enable_event_retrieval;
CoglBool xlib_want_reset_on_video_memory_purge;
+ CoglBool xlib_enable_threaded_swap_wait;
#endif
#ifdef COGL_HAS_WIN32_SUPPORT
diff -up cogl-1.18.2/cogl/cogl-xlib-renderer.h.swap-wait-setter cogl-1.18.2/cogl/cogl-xlib-renderer.h
--- cogl-1.18.2/cogl/cogl-xlib-renderer.h.swap-wait-setter 2016-06-30 15:58:16.047534998 -0400
+++ cogl-1.18.2/cogl/cogl-xlib-renderer.h 2016-06-30 15:58:16.084535595 -0400
@@ -166,6 +166,36 @@ void
cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer,
CoglBool enable);
+/**
+ * cogl_xlib_renderer_set_threaded_swap_wait_enabled:
+ * @renderer: a #CoglRenderer
+ * @enable: The new value
+ *
+ * Sets whether Cogl is allowed to use a separate threaded to wait for the
+ * completion of glXSwapBuffers() and call the frame callback for the
+ * corresponding #CoglOnscreen. This is a way of emulating the
+ * INTEL_swap_event extension, and will only ever be used if
+ * INTEL_swap_event is not present; it will also only be used for
+ * specific white-listed drivers that are known to work correctly with
+ * multiple contexts sharing state between threads.
+ *
+ * The advantage of enabling this is that it will allow your main loop
+ * to do other work while waiting for the system to be ready to draw
+ * the next frame, instead of blocking in glXSwapBuffers(). A disadvantage
+ * is that the driver will be prevented from buffering up multiple frames
+ * even if it thinks that it would be advantageous. In general, this
+ * will work best for something like a system compositor that is doing
+ * simple drawing but handling lots of other complex tasks.
+ *
+ * If you enable this, you must call XInitThreads() before any other
+ * X11 calls in your program. (See the documentation for XInitThreads())
+ *
+ * Stability: unstable
+ */
+void
+cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer,
+ CoglBool enable);
+
Display *
cogl_xlib_renderer_get_display (CoglRenderer *renderer);
diff -up cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c.swap-wait-setter cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c
--- cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c.swap-wait-setter 2016-06-30 15:58:16.085535611 -0400
+++ cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c 2016-06-30 15:58:55.708175372 -0400
@@ -901,6 +901,7 @@ update_winsys_features (CoglContext *con
{
CoglGpuInfo *info = &context->gpu;
if (glx_display->have_vblank_counter &&
+ context->display->renderer->xlib_enable_threaded_swap_wait &&
info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
{
COGL_FLAGS_SET (context->winsys_features,
diff -up cogl-1.18.2/examples/cogl-crate.c.swap-wait-setter cogl-1.18.2/examples/cogl-crate.c
--- cogl-1.18.2/examples/cogl-crate.c.swap-wait-setter 2016-06-30 15:58:16.082535563 -0400
+++ cogl-1.18.2/examples/cogl-crate.c 2016-06-30 15:58:16.085535611 -0400
@@ -1,6 +1,9 @@
#include <cogl/cogl.h>
#include <cogl-pango/cogl-pango.h>
+#ifdef COGL_HAS_XLIB_SUPPORT
#include <X11/Xlib.h>
+#include <cogl/cogl-xlib.h>
+#endif /* COGL_HAS_XLIB_SUPPORT */
/* The state for this example... */
typedef struct _Data
@@ -145,6 +148,8 @@ frame_event_cb (CoglOnscreen *onscreen,
int
main (int argc, char **argv)
{
+ CoglRenderer *renderer;
+ CoglDisplay *display;
CoglContext *ctx;
CoglOnscreen *onscreen;
CoglFramebuffer *fb;
@@ -154,9 +159,32 @@ main (int argc, char **argv)
float fovy, aspect, z_near, z_2d, z_far;
CoglDepthState depth_state;
- XInitThreads ();
+ renderer = cogl_renderer_new ();
- ctx = cogl_context_new (NULL, &error);
+#ifdef COGL_HAS_XLIB_SUPPORT
+ /* Guess if we're using the GLX renderer; we could just blindly
+ * call XInitThreads() as long as we're linked against Xlib
+ * but it's a bit cleaner not to if we're not going to even
+ * open a display.
+ */
+ if (g_getenv("DISPLAY") != NULL)
+ {
+ const char *renderer_environment = g_getenv("COGL_RENDERER_NEW");
+ if (renderer_environment == NULL || g_strcmp0 (renderer_environment, "GLX") == 0)
+ {
+ XInitThreads ();
+ cogl_xlib_renderer_set_threaded_swap_wait_enabled (renderer, TRUE);
+ }
+ }
+#endif /* COGL_HAS_XLIB_SUPPORT */
+
+ if (!cogl_renderer_connect (renderer, &error)) {
+ fprintf (stderr, "Failed to connect CoglRenderer: %s\n", error->message);
+ return 1;
+ }
+
+ display = cogl_display_new (renderer, NULL);
+ ctx = cogl_context_new (display, &error);
if (!ctx) {
fprintf (stderr, "Failed to create context: %s\n", error->message);
return 1;