|
|
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 |
|