[mutter/wip/xtoglsync-3-10: 3/4] compositor: Add support for GL_EXT_x11_sync_object



commit e6f100b6d46021f67473e8f59279309a77469f69
Author: Rui Matos <tiagomatos gmail com>
Date:   Fri Apr 18 20:21:20 2014 +0200

    compositor: Add support for GL_EXT_x11_sync_object
    
    If GL advertises this extension we'll use it to synchronize X with GL
    rendering instead of relying on the XSync() behavior with open source
    drivers.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=728464

 configure.ac                        |    5 +
 src/Makefile.am                     |    2 +
 src/compositor/compositor-private.h |    6 +-
 src/compositor/compositor.c         |   66 ++++-
 src/compositor/meta-sync-ring.c     |  482 +++++++++++++++++++++++++++++++++++
 src/compositor/meta-sync-ring.h     |   17 ++
 6 files changed, 561 insertions(+), 17 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index ef67b20..c894c1f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -363,6 +363,11 @@ fi
 
 GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
 
+AC_CHECK_DECL([GL_EXT_x11_sync_object],
+              [],
+              [AC_MSG_ERROR([GL_EXT_x11_sync_object definition not found, please update your GL headers])],
+              [#include <GL/glx.h>])
+
 #### Warnings (last since -Werror can disturb other tests)
 
 # Stay command-line compatible with the gnome-common configure option. Here
diff --git a/src/Makefile.am b/src/Makefile.am
index 6f91327..ee46a30 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -64,6 +64,8 @@ libmutter_la_SOURCES =                                \
        compositor/meta-shadow-factory.c        \
        compositor/meta-shadow-factory-private.h        \
        compositor/meta-shaped-texture.c        \
+       compositor/meta-sync-ring.c             \
+       compositor/meta-sync-ring.h             \
        compositor/meta-texture-rectangle.c     \
        compositor/meta-texture-rectangle.h     \
        compositor/meta-texture-tower.c         \
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
index 622dd0b..5cdb31f 100644
--- a/src/compositor/compositor-private.h
+++ b/src/compositor/compositor-private.h
@@ -19,7 +19,8 @@ struct _MetaCompositor
 
   Atom            atom_x_root_pixmap;
   Atom            atom_net_wm_window_opacity;
-  guint           repaint_func_id;
+  guint           pre_paint_func_id;
+  guint           post_paint_func_id;
 
   ClutterActor   *shadow_src;
 
@@ -33,7 +34,8 @@ struct _MetaCompositor
   guint           debug       : 1;
   guint           no_mipmaps  : 1;
 
-  gboolean need_sync_drawing;
+  gboolean frame_has_updated_xsurfaces;
+  gboolean have_x11_sync_object;
 };
 
 struct _MetaCompScreen
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 5eaca0c..add1ed6 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -86,6 +86,7 @@
 #include "display-private.h" /* for meta_display_lookup_x_window() */
 #include <X11/extensions/shape.h>
 #include <X11/extensions/Xcomposite.h>
+#include "meta-sync-ring.h"
 
 /* #define DEBUG_TRACE g_print */
 #define DEBUG_TRACE(X)
@@ -142,7 +143,11 @@ meta_switch_workspace_completed (MetaScreen *screen)
 void
 meta_compositor_destroy (MetaCompositor *compositor)
 {
-  clutter_threads_remove_repaint_func (compositor->repaint_func_id);
+  clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
+  clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
+
+  if (compositor->have_x11_sync_object)
+    meta_sync_ring_destroy ();
 }
 
 static void
@@ -174,7 +179,7 @@ process_damage (MetaCompositor     *compositor,
 
   meta_window_actor_process_damage (window_actor, event);
 
-  compositor->need_sync_drawing = TRUE;
+  compositor->frame_has_updated_xsurfaces = TRUE;
 }
 
 static void
@@ -721,6 +726,8 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
    */
   XMapWindow (xdisplay, info->output);
 
+  compositor->have_x11_sync_object = meta_sync_ring_init (display);
+
   redirect_windows (compositor, screen);
 }
 
@@ -1021,6 +1028,10 @@ meta_compositor_process_event (MetaCompositor *compositor,
   if (event->type == MapNotify)
     clutter_x11_handle_event (event);
 
+  if (compositor->have_x11_sync_object &&
+      event->type == (compositor->display->xsync_event_base + XSyncAlarmNotify))
+    meta_sync_ring_handle_event ((XSyncAlarmNotifyEvent *) event);
+
   /* The above handling is basically just "observing" the events, so we return
    * FALSE to indicate that the event should not be filtered out; if we have
    * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example.
@@ -1470,7 +1481,7 @@ pre_paint_windows (MetaCompScreen *info)
 }
 
 static gboolean
-meta_repaint_func (gpointer data)
+meta_pre_paint_func (gpointer data)
 {
   MetaCompositor *compositor = data;
   GSList *screens = meta_display_get_screens (compositor->display);
@@ -1486,14 +1497,16 @@ meta_repaint_func (gpointer data)
       pre_paint_windows (info);
     }
 
-  if (compositor->need_sync_drawing)
+  if (compositor->frame_has_updated_xsurfaces)
     {
       /* We need to make sure that any X drawing that happens before
-       * the XDamageSubtract() for each MWA above is visible to
-       * subsequent GL rendering; the only standardized way to do this
-       * is EXT_x11_sync_object, which isn't yet widely available. For
-       * now, we count on details of Xorg and the open source drivers,
-       * and hope for the best otherwise.
+       * the XDamageSubtract() for each window above is visible to
+       * subsequent GL rendering; the standardized way to do this is
+       * GL_EXT_X11_sync_object. Since this isn't implemented yet in
+       * mesa, we also have a path that relies on the implementation
+       * of the open source drivers.
+       *
+       * Anything else, we just hope for the best.
        *
        * Xorg and open source driver specifics:
        *
@@ -1508,9 +1521,26 @@ meta_repaint_func (gpointer data)
        * round trip request at this point is sufficient to flush the
        * GLX buffers.
        */
-      XSync (compositor->display->xdisplay, False);
+      if (compositor->have_x11_sync_object)
+        meta_sync_ring_insert_wait ();
+      else
+        XSync (compositor->display->xdisplay, False);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+meta_post_paint_func (gpointer data)
+{
+  MetaCompositor *compositor = data;
+
+  if (compositor->frame_has_updated_xsurfaces)
+    {
+      if (compositor->have_x11_sync_object)
+        meta_sync_ring_after_frame ();
 
-      compositor->need_sync_drawing = FALSE;
+      compositor->frame_has_updated_xsurfaces = FALSE;
     }
 
   return TRUE;
@@ -1574,10 +1604,16 @@ meta_compositor_new (MetaDisplay *display)
   compositor->atom_x_root_pixmap = atoms[0];
   compositor->atom_net_wm_window_opacity = atoms[1];
 
-  compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
-                                                                  compositor,
-                                                                  NULL);
-
+  compositor->pre_paint_func_id =
+    clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
+                                           meta_pre_paint_func,
+                                           compositor,
+                                           NULL);
+  compositor->post_paint_func_id =
+    clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
+                                           meta_post_paint_func,
+                                           compositor,
+                                           NULL);
   return compositor;
 }
 
diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
new file mode 100644
index 0000000..c17c814
--- /dev/null
+++ b/src/compositor/meta-sync-ring.c
@@ -0,0 +1,482 @@
+/*
+ * This is based on an original C++ implementation for compiz that
+ * carries the following copyright notice:
+ *
+ *
+ * Copyright © 2011 NVIDIA Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of NVIDIA
+ * Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  NVIDIA Corporation makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Authors: James Jones <jajones nvidia com>
+ */
+
+#include <string.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#include <cogl/cogl.h>
+
+#include <meta/display.h>
+#include <meta/util.h>
+
+#include "meta-sync-ring.h"
+
+/* Theory of operation:
+ *
+ * We use a ring of NUM_SYNCS fence objects. On each frame we advance
+ * to the next fence in the ring. For each fence we do:
+ *
+ * 1. fence is XSyncTriggerFence()'d and glWaitSync()'d
+ * 2. NUM_SYNCS / 2 frames later, fence should be triggered
+ * 3. fence is XSyncResetFence()'d
+ * 4. NUM_SYNCS / 2 frames later, fence should be reset
+ * 5. go back to 1 and re-use fence
+ *
+ * glClientWaitSync() and XAlarms are used in steps 2 and 4,
+ * respectively, to double-check the expectections.
+ */
+
+#define NUM_SYNCS 10
+#define MAX_SYNC_WAIT_TIME (1 * 1000 * 1000 * 1000) /* one sec */
+
+typedef enum
+{
+  META_SYNC_STATE_READY,
+  META_SYNC_STATE_WAITING,
+  META_SYNC_STATE_DONE,
+  META_SYNC_STATE_RESET_PENDING,
+} MetaSyncState;
+
+typedef struct
+{
+  Display *xdisplay;
+
+  XSyncFence xfence;
+  GLsync glsync;
+
+  XSyncCounter xcounter;
+  XSyncAlarm xalarm;
+  XSyncValue next_counter_value;
+
+  MetaSyncState state;
+} MetaSync;
+
+typedef struct
+{
+  MetaDisplay *display;
+
+  GHashTable *alarm_to_sync;
+
+  MetaSync *syncs_array[NUM_SYNCS];
+  guint current_sync_idx;
+  MetaSync *current_sync;
+  guint warmup_syncs;
+} MetaSyncRing;
+
+static MetaSyncRing meta_sync_ring = { 0 };
+
+static XSyncValue SYNC_VALUE_ZERO;
+static XSyncValue SYNC_VALUE_ONE;
+
+static void             (*meta_gl_get_integerv) (GLenum  pname,
+                                                 GLint  *params);
+static const char*      (*meta_gl_get_stringi) (GLenum name,
+                                                GLuint index);
+static void             (*meta_gl_delete_sync) (GLsync sync);
+static GLenum           (*meta_gl_client_wait_sync) (GLsync sync,
+                                                     GLbitfield flags,
+                                                     GLuint64 timeout);
+static void             (*meta_gl_wait_sync) (GLsync sync,
+                                              GLbitfield flags,
+                                              GLuint64 timeout);
+static GLsync           (*meta_gl_import_sync) (GLenum external_sync_type,
+                                                GLintptr external_sync,
+                                                GLbitfield flags);
+
+static MetaSyncRing *
+meta_sync_ring_get (void)
+{
+  return &meta_sync_ring;
+}
+
+static gboolean
+load_gl_symbol (const char  *name,
+                void       **func)
+{
+  *func = cogl_get_proc_address (name);
+  if (!*func)
+    {
+      meta_verbose ("MetaSyncRing: failed to resolve required GL symbol \"%s\"\n", name);
+      return FALSE;
+    }
+  return TRUE;
+}
+
+static gboolean
+check_gl_extensions (void)
+{
+  int num_extensions, i;
+  gboolean sync = FALSE;
+  gboolean x11_sync_object = FALSE;
+
+  meta_gl_get_integerv (GL_NUM_EXTENSIONS, &num_extensions);
+
+  for (i = 0; i < num_extensions; ++i)
+    {
+      const char *ext = meta_gl_get_stringi (GL_EXTENSIONS, i);
+
+      if (g_strcmp0 ("GL_ARB_sync", ext) == 0)
+        sync = TRUE;
+      else if (g_strcmp0 ("GL_EXT_x11_sync_object", ext) == 0)
+        x11_sync_object = TRUE;
+    }
+
+  return sync && x11_sync_object;
+}
+
+static gboolean
+load_required_symbols (void)
+{
+  static gboolean success = FALSE;
+
+  if (success)
+    return TRUE;
+
+  /* We don't link against libGL directly because cogl may want to
+   * use something else. This assumes that cogl has been initialized
+   * and dynamically loaded libGL at this point.
+   */
+
+  if (!load_gl_symbol ("glGetIntegerv", (void **) &meta_gl_get_integerv))
+    goto out;
+  if (!load_gl_symbol ("glGetStringi", (void **) &meta_gl_get_stringi))
+    goto out;
+
+  if (!check_gl_extensions ())
+    {
+      meta_verbose ("MetaSyncRing: couldn't find required GL extensions\n");
+      goto out;
+    }
+
+  if (!load_gl_symbol ("glDeleteSync", (void **) &meta_gl_delete_sync))
+    goto out;
+  if (!load_gl_symbol ("glClientWaitSync", (void **) &meta_gl_client_wait_sync))
+    goto out;
+  if (!load_gl_symbol ("glWaitSync", (void **) &meta_gl_wait_sync))
+    goto out;
+  if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
+    goto out;
+
+  success = TRUE;
+ out:
+  return success;
+}
+
+static void
+meta_sync_insert (MetaSync *self)
+{
+  g_return_if_fail (self->state == META_SYNC_STATE_READY);
+
+  XSyncTriggerFence (self->xdisplay, self->xfence);
+  XFlush (self->xdisplay);
+
+  meta_gl_wait_sync (self->glsync, 0, GL_TIMEOUT_IGNORED);
+
+  self->state = META_SYNC_STATE_WAITING;
+}
+
+static GLenum
+meta_sync_check_update_finished (MetaSync *self,
+                                 GLuint64  timeout)
+{
+  GLenum status = GL_WAIT_FAILED;
+
+  switch (self->state)
+    {
+    case META_SYNC_STATE_DONE:
+      status = GL_ALREADY_SIGNALED;
+      break;
+    case META_SYNC_STATE_WAITING:
+      status = meta_gl_client_wait_sync (self->glsync, 0, timeout);
+      if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
+        self->state = META_SYNC_STATE_DONE;
+      break;
+    default:
+      break;
+    }
+
+  g_warn_if_fail (status != GL_WAIT_FAILED);
+
+  return status;
+}
+
+static void
+meta_sync_reset (MetaSync *self)
+{
+  XSyncAlarmAttributes attrs;
+  int overflow;
+
+  g_return_if_fail (self->state == META_SYNC_STATE_DONE);
+
+  XSyncResetFence (self->xdisplay, self->xfence);
+
+  attrs.trigger.wait_value = self->next_counter_value;
+
+  XSyncChangeAlarm (self->xdisplay, self->xalarm, XSyncCAValue, &attrs);
+  XSyncSetCounter (self->xdisplay, self->xcounter, self->next_counter_value);
+
+  XSyncValueAdd (&self->next_counter_value,
+                 self->next_counter_value,
+                 SYNC_VALUE_ONE,
+                 &overflow);
+
+  self->state = META_SYNC_STATE_RESET_PENDING;
+}
+
+static void
+meta_sync_handle_event (MetaSync              *self,
+                        XSyncAlarmNotifyEvent *event)
+{
+  g_return_if_fail (event->alarm == self->xalarm);
+  g_return_if_fail (self->state == META_SYNC_STATE_RESET_PENDING);
+
+  self->state = META_SYNC_STATE_READY;
+}
+
+static MetaSync *
+meta_sync_new (Display *xdisplay)
+{
+  MetaSync *self;
+  XSyncAlarmAttributes attrs;
+
+  self = g_malloc0 (sizeof (MetaSync));
+
+  self->xdisplay = xdisplay;
+
+  self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
+  self->glsync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
+
+  self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
+
+  attrs.trigger.counter = self->xcounter;
+  attrs.trigger.value_type = XSyncAbsolute;
+  attrs.trigger.wait_value = SYNC_VALUE_ONE;
+  attrs.trigger.test_type = XSyncPositiveTransition;
+  attrs.events = TRUE;
+  self->xalarm = XSyncCreateAlarm (xdisplay,
+                                   XSyncCACounter |
+                                   XSyncCAValueType |
+                                   XSyncCAValue |
+                                   XSyncCATestType |
+                                   XSyncCAEvents,
+                                   &attrs);
+
+  XSyncIntToValue (&self->next_counter_value, 1);
+
+  self->state = META_SYNC_STATE_READY;
+
+  return self;
+}
+
+static Bool
+alarm_event_predicate (Display  *dpy,
+                       XEvent   *event,
+                       XPointer  data)
+{
+  MetaSyncRing *ring = meta_sync_ring_get ();
+  int xsync_event_base = meta_display_get_sync_event_base (ring->display);
+
+  if (event->type == xsync_event_base + XSyncAlarmNotify)
+    {
+      if (((MetaSync *) data)->xalarm == ((XSyncAlarmNotifyEvent *) event)->alarm)
+        return True;
+    }
+  return False;
+}
+
+static void
+meta_sync_free (MetaSync *self)
+{
+  /* When our assumptions don't hold, something has gone wrong but we
+   * don't know what, so we reboot the ring. While doing that, we
+   * trigger fences before deleting them to try to get ourselves out
+   * of a potentially stuck GPU state.
+   */
+  switch (self->state)
+    {
+    case META_SYNC_STATE_WAITING:
+    case META_SYNC_STATE_DONE:
+      /* nothing to do */
+      break;
+    case META_SYNC_STATE_RESET_PENDING:
+      {
+        XEvent event;
+        XIfEvent (self->xdisplay, &event, alarm_event_predicate, (XPointer) self);
+        meta_sync_handle_event (self, (XSyncAlarmNotifyEvent *) &event);
+      }
+      /* fall through */
+    case META_SYNC_STATE_READY:
+      XSyncTriggerFence (self->xdisplay, self->xfence);
+      XFlush (self->xdisplay);
+      break;
+    default:
+      break;
+    }
+
+  meta_gl_delete_sync (self->glsync);
+  XSyncDestroyFence (self->xdisplay, self->xfence);
+  XSyncDestroyCounter (self->xdisplay, self->xcounter);
+  XSyncDestroyAlarm (self->xdisplay, self->xalarm);
+
+  g_free (self);
+}
+
+gboolean
+meta_sync_ring_init (MetaDisplay *display)
+{
+  guint i;
+  MetaSyncRing *ring = meta_sync_ring_get ();
+
+  g_return_val_if_fail (display != NULL, FALSE);
+  g_return_val_if_fail (ring->display == NULL, FALSE);
+
+  if (!load_required_symbols ())
+    return FALSE;
+
+  if (!meta_display_has_sync (display))
+    return FALSE;
+
+  XSyncIntToValue (&SYNC_VALUE_ZERO, 0);
+  XSyncIntToValue (&SYNC_VALUE_ONE, 1);
+
+  ring->display = display;
+
+  ring->alarm_to_sync = g_hash_table_new (NULL, NULL);
+
+  for (i = 0; i < NUM_SYNCS; ++i)
+    {
+      MetaSync *sync = meta_sync_new (meta_display_get_xdisplay (display));
+      ring->syncs_array[i] = sync;
+      g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync);
+    }
+
+  ring->current_sync_idx = 0;
+  ring->current_sync = ring->syncs_array[0];
+  ring->warmup_syncs = 0;
+
+  return TRUE;
+}
+
+void
+meta_sync_ring_destroy (void)
+{
+  guint i;
+  MetaSyncRing *ring = meta_sync_ring_get ();
+
+  g_return_if_fail (ring->display != NULL);
+
+  ring->current_sync_idx = 0;
+  ring->current_sync = NULL;
+  ring->warmup_syncs = 0;
+
+  for (i = 0; i < NUM_SYNCS; ++i)
+    meta_sync_free (ring->syncs_array[i]);
+
+  g_hash_table_destroy (ring->alarm_to_sync);
+
+  ring->display = NULL;
+}
+
+static void
+meta_sync_ring_reboot (MetaDisplay *display)
+{
+  meta_sync_ring_destroy ();
+  meta_sync_ring_init (display);
+}
+
+void
+meta_sync_ring_after_frame (void)
+{
+  MetaSyncRing *ring = meta_sync_ring_get ();
+
+  g_return_if_fail (ring->display != NULL);
+
+  if (ring->warmup_syncs >= NUM_SYNCS / 2)
+    {
+      guint reset_sync_idx = (ring->current_sync_idx + NUM_SYNCS - (NUM_SYNCS / 2)) % NUM_SYNCS;
+      MetaSync *sync_to_reset = ring->syncs_array[reset_sync_idx];
+
+      GLenum status = meta_sync_check_update_finished (sync_to_reset, 0);
+      if (status == GL_TIMEOUT_EXPIRED)
+        {
+          meta_warning ("MetaSyncRing: We should never wait for a sync -- add more syncs?\n");
+          status = meta_sync_check_update_finished (sync_to_reset, MAX_SYNC_WAIT_TIME);
+        }
+
+      if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED)
+        {
+          meta_warning ("MetaSyncRing: Timed out waiting for sync object.\n");
+          meta_sync_ring_reboot (ring->display);
+          return;
+        }
+
+      meta_sync_reset (sync_to_reset);
+    }
+  else
+    {
+      ring->warmup_syncs += 1;
+    }
+
+  ring->current_sync_idx += 1;
+  ring->current_sync_idx %= NUM_SYNCS;
+
+  ring->current_sync = ring->syncs_array[ring->current_sync_idx];
+}
+
+void
+meta_sync_ring_insert_wait (void)
+{
+  MetaSyncRing *ring = meta_sync_ring_get ();
+
+  g_return_if_fail (ring->display != NULL);
+
+  if (ring->current_sync->state != META_SYNC_STATE_READY)
+    {
+      meta_warning ("MetaSyncRing: Sync object is not ready -- were events handled properly?\n");
+      meta_sync_ring_reboot (ring->display);
+    }
+
+  meta_sync_insert (ring->current_sync);
+}
+
+void
+meta_sync_ring_handle_event (XSyncAlarmNotifyEvent *event)
+{
+  MetaSync *sync;
+  MetaSyncRing *ring = meta_sync_ring_get ();
+
+  g_return_if_fail (ring->display != NULL);
+
+  sync = g_hash_table_lookup (ring->alarm_to_sync, (gpointer) event->alarm);
+  if (sync)
+    meta_sync_handle_event (sync, event);
+}
diff --git a/src/compositor/meta-sync-ring.h b/src/compositor/meta-sync-ring.h
new file mode 100644
index 0000000..b0d2275
--- /dev/null
+++ b/src/compositor/meta-sync-ring.h
@@ -0,0 +1,17 @@
+#ifndef _META_SYNC_RING_H_
+#define _META_SYNC_RING_H_
+
+#include <glib.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/sync.h>
+
+#include <meta/display.h>
+
+gboolean meta_sync_ring_init (MetaDisplay *dpy);
+void meta_sync_ring_destroy (void);
+void meta_sync_ring_after_frame (void);
+void meta_sync_ring_insert_wait (void);
+void meta_sync_ring_handle_event (XSyncAlarmNotifyEvent *event);
+
+#endif  /* _META_SYNC_RING_H_ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]