[cogl/wip/frame-synchronization: 217/223] onscreen: Provide more general CoglFrameCallback api



commit 8a1a1f56135af22c7316529f9e6f400059e305b8
Author: Robert Bragg <robert linux intel com>
Date:   Thu Jan 10 19:23:48 2013 +0000

    onscreen: Provide more general CoglFrameCallback api
    
    This reworks the cogl_onscreen_add_swap_complete_callback api to instead
    be named cogl_onscreen_add_frame_callback and to take a callback that
    can accept other events besides just swap completion events. This means
    we can add more events in the future that signal the progression of a
    frame without needing lots of new callback api for each event.
    
    TODO: squash this back into owen's patch

 cogl/cogl-context-private.h       |    3 +
 cogl/cogl-context.c               |    6 +
 cogl/cogl-context.h               |    6 +
 cogl/cogl-glx-display-private.h   |    4 +-
 cogl/cogl-onscreen-private.h      |   37 ++-----
 cogl/cogl-onscreen.c              |  198 +++++++++++++++++++++++--------------
 cogl/cogl-onscreen.h              |  202 ++++++++++++++++++++++++++----------
 cogl/winsys/cogl-winsys-egl-kms.c |   10 ++-
 cogl/winsys/cogl-winsys-glx.c     |   88 +++++++++-------
 9 files changed, 356 insertions(+), 198 deletions(-)
---
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 2780a59..ce92aa7 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -190,6 +190,9 @@ struct _CoglContext
   gboolean have_last_offscreen_allocate_flags;
   CoglOffscreenAllocateFlags last_offscreen_allocate_flags;
 
+  GHashTable *swap_callback_closures;
+  int next_frame_callback_id;
+
   CoglGLES2Context *current_gles2_context;
   GQueue gles2_context_stack;
 
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 6dff50c..5f3453f 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -308,6 +308,9 @@ cogl_context_new (CoglDisplay *display,
   context->current_draw_buffer_state_flushed = 0;
   context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;
 
+  context->swap_callback_closures =
+    g_hash_table_new (g_direct_hash, g_direct_equal);
+
   g_queue_init (&context->gles2_context_stack);
 
   context->journal_flush_attributes_array =
@@ -503,6 +506,9 @@ _cogl_context_free (CoglContext *context)
   if (context->blit_texture_pipeline)
     cogl_object_unref (context->blit_texture_pipeline);
 
+  if (context->swap_callback_closures)
+    g_hash_table_destroy (context->swap_callback_closures);
+
   g_warn_if_fail (context->gles2_context_stack.length == 0);
 
   if (context->journal_flush_attributes_array)
diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h
index 3356440..ae306d6 100644
--- a/cogl/cogl-context.h
+++ b/cogl/cogl-context.h
@@ -208,6 +208,10 @@ cogl_is_context (void *object);
  *    suported.
  * @COGL_FEATURE_ID_DEPTH_TEXTURE: Whether #CoglFramebuffer support rendering
  *     the depth buffer to a texture.
+ * @COGL_FEATURE_ID_FRAME_SYNC: Whether %COGL_FRAME_EVENT_SYNC events
+ *    will be sent to registered #CoglFrameCallback functions.
+ * @COGL_FEATURE_ID_PRESENTATION_TIME: Whether frame presentation
+ *    time stamps will be recorded in #CoglFrameInfo objects.
  *
  * All the capabilities that can vary between different GPUs supported
  * by Cogl. Applications that depend on any of these features should explicitly
@@ -237,6 +241,8 @@ typedef enum _CoglFeatureID
   COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
   COGL_FEATURE_ID_GLES2_CONTEXT,
   COGL_FEATURE_ID_DEPTH_TEXTURE,
+  COGL_FEATURE_ID_FRAME_SYNC,
+  COGL_FEATURE_ID_PRESENTATION_TIME,
 
   /*< private >*/
   _COGL_N_FEATURE_IDS   /*< skip >*/
diff --git a/cogl/cogl-glx-display-private.h b/cogl/cogl-glx-display-private.h
index fb7f395..69b1570 100644
--- a/cogl/cogl-glx-display-private.h
+++ b/cogl/cogl-glx-display-private.h
@@ -50,9 +50,9 @@ typedef struct _CoglGLXDisplay
   GLXContext glx_context;
   GLXWindow dummy_glxwin;
   Window dummy_xwin;
-  CoglBool pending_swap_notify;
+  CoglBool pending_sync_notify;
+  CoglBool pending_complete_notify;
   CoglBool pending_resize_notify;
-  CoglBool pending_frame_info_notify;
 } CoglGLXDisplay;
 
 #endif /* __COGL_DISPLAY_GLX_PRIVATE_H */
diff --git a/cogl/cogl-onscreen-private.h b/cogl/cogl-onscreen-private.h
index e6c2b42..da36de0 100644
--- a/cogl/cogl-onscreen-private.h
+++ b/cogl/cogl-onscreen-private.h
@@ -24,6 +24,7 @@
 #ifndef __COGL_ONSCREEN_PRIVATE_H
 #define __COGL_ONSCREEN_PRIVATE_H
 
+#include "cogl-onscreen.h"
 #include "cogl-framebuffer-private.h"
 #include "cogl-queue.h"
 
@@ -35,17 +36,16 @@
 
 #define COGL_ONSCREEN_MAX_FRAME_INFOS 16
 
-typedef struct _CoglSwapBuffersNotifyEntry CoglSwapBuffersNotifyEntry;
+COGL_TAILQ_HEAD (CoglFrameCallbackList, CoglFrameClosure);
 
-COGL_TAILQ_HEAD (CoglSwapBuffersNotifyList, CoglSwapBuffersNotifyEntry);
-
-struct _CoglSwapBuffersNotifyEntry
+struct _CoglFrameClosure
 {
-  COGL_TAILQ_ENTRY (CoglSwapBuffersNotifyEntry) list_node;
+  COGL_TAILQ_ENTRY (CoglFrameClosure) list_node;
+
+  CoglFrameCallback callback;
 
-  CoglSwapBuffersNotify callback;
   void *user_data;
-  unsigned int id;
+  CoglUserDataDestroyCallback destroy;
 };
 
 typedef struct _CoglResizeNotifyEntry CoglResizeNotifyEntry;
@@ -61,19 +61,6 @@ struct _CoglResizeNotifyEntry
   unsigned int id;
 };
 
-typedef struct _CoglFrameInfoCallbackEntry CoglFrameInfoCallbackEntry;
-
-COGL_TAILQ_HEAD (CoglFrameInfoCallbackList, CoglFrameInfoCallbackEntry);
-
-struct _CoglFrameInfoCallbackEntry
-{
-  COGL_TAILQ_ENTRY (CoglFrameInfoCallbackEntry) list_node;
-
-  CoglFrameInfoCallback callback;
-  void *user_data;
-  unsigned int id;
-};
-
 struct _CoglOnscreen
 {
   CoglFramebuffer  _parent;
@@ -90,13 +77,11 @@ struct _CoglOnscreen
 
   CoglBool swap_throttled;
 
-  CoglSwapBuffersNotifyList swap_callbacks;
+  CoglFrameCallbackList frame_closures;
 
   CoglBool resizable;
   CoglResizeNotifyList resize_callbacks;
 
-  CoglFrameInfoCallbackList frame_info_callbacks;
-
   int64_t frame_counter;
   int64_t swap_frame_counter; /* frame counter at last all to
                                * cogl_onscreen_swap_region() or
@@ -116,12 +101,12 @@ _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
                                       int width, int height);
 
 void
-_cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen);
+_cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info);
 
 void
-_cogl_onscreen_notify_resize (CoglOnscreen *onscreen);
+_cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info);
 
 void
-_cogl_onscreen_notify_frame_info (CoglOnscreen *onscreen);
+_cogl_onscreen_notify_resize (CoglOnscreen *onscreen);
 
 #endif /* __COGL_ONSCREEN_PRIVATE_H */
diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c
index 52490b6..a1481da 100644
--- a/cogl/cogl-onscreen.c
+++ b/cogl/cogl-onscreen.c
@@ -48,9 +48,8 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
 
-  COGL_TAILQ_INIT (&onscreen->swap_callbacks);
+  COGL_TAILQ_INIT (&onscreen->frame_closures);
   COGL_TAILQ_INIT (&onscreen->resize_callbacks);
-  COGL_TAILQ_INIT (&onscreen->frame_info_callbacks);
 
   framebuffer->config = onscreen_template->config;
   cogl_object_ref (framebuffer->config.swap_chain);
@@ -122,7 +121,8 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
   CoglResizeNotifyEntry *resize_entry;
-  CoglSwapBuffersNotifyEntry *swap_entry;
+  CoglFrameClosure *frame_closure;
+  int i;
 
   while ((resize_entry = COGL_TAILQ_FIRST (&onscreen->resize_callbacks)))
     {
@@ -130,10 +130,20 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
       g_slice_free (CoglResizeNotifyEntry, resize_entry);
     }
 
-  while ((swap_entry = COGL_TAILQ_FIRST (&onscreen->swap_callbacks)))
+  while ((frame_closure = COGL_TAILQ_FIRST (&onscreen->frame_closures)))
     {
-      COGL_TAILQ_REMOVE (&onscreen->swap_callbacks, swap_entry, list_node);
-      g_slice_free (CoglSwapBuffersNotifyEntry, swap_entry);
+      COGL_TAILQ_REMOVE (&onscreen->frame_closures, frame_closure, list_node);
+
+      if (frame_closure->destroy)
+        frame_closure->destroy (frame_closure->user_data);
+
+      g_slice_free (CoglFrameClosure, frame_closure);
+    }
+
+  for (i = 0; i < onscreen->n_frame_infos; i++)
+    {
+      cogl_object_unref (onscreen->frame_info[i]);
+      onscreen->frame_info[i] = NULL;
     }
 
   if (framebuffer->context->window_buffer == COGL_FRAMEBUFFER (onscreen))
@@ -281,38 +291,107 @@ cogl_win32_onscreen_get_window (CoglOnscreen *onscreen)
 
 #endif /* COGL_HAS_WIN32_SUPPORT */
 
+CoglFrameClosure *
+cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
+                                  CoglFrameCallback callback,
+                                  void *user_data,
+                                  CoglUserDataDestroyCallback destroy)
+{
+  CoglFrameClosure *closure = g_slice_new0 (CoglFrameClosure);
+
+  closure->callback = callback;
+  closure->user_data = user_data;
+  closure->destroy = destroy;
+
+  COGL_TAILQ_INSERT_TAIL (&onscreen->frame_closures, closure, list_node);
+
+  return closure;
+}
+
+void
+cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
+                                     CoglFrameClosure *closure)
+{
+  _COGL_RETURN_IF_FAIL (closure);
+
+  if (closure->destroy)
+    closure->destroy (closure->user_data);
+
+  COGL_TAILQ_REMOVE (&onscreen->frame_closures, closure, list_node);
+
+  g_slice_free (CoglFrameClosure, closure);
+}
+
+typedef struct _SwapBufferCallbackState
+{
+  CoglSwapBuffersNotify callback;
+  void *user_data;
+} SwapBufferCallbackState;
+
+static void
+destroy_swap_buffers_callback_state (void *user_data)
+{
+  g_slice_free (SwapBufferCallbackState, user_data);
+}
+
+static void
+shim_swap_buffers_callback (CoglOnscreen *onscreen,
+                            CoglFrameEvent event,
+                            CoglFrameInfo *info,
+                            void *user_data)
+{
+  SwapBufferCallbackState *state = user_data;
+
+  /* XXX: Note that technically it is a change in semantics for this
+   * interface to forward _SYNC events here and also makes the api
+   * name somewhat missleading.
+   *
+   * In practice though this interface is currently used by
+   * applications for throttling, not because they are strictly
+   * interested in knowing when a frame has been presented and so
+   * forwarding _SYNC events should serve them better.
+   */
+  if (event == COGL_FRAME_EVENT_SYNC)
+    state->callback (COGL_FRAMEBUFFER (onscreen), state->user_data);
+}
+
 unsigned int
 cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
                                          CoglSwapBuffersNotify callback,
                                          void *user_data)
 {
-  CoglSwapBuffersNotifyEntry *entry = g_slice_new0 (CoglSwapBuffersNotifyEntry);
-  static int next_swap_buffers_callback_id = 0;
+  CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
+  SwapBufferCallbackState *state = g_slice_new (SwapBufferCallbackState);
+  CoglFrameClosure *closure;
+  unsigned int id = ctx->next_frame_callback_id++;
 
-  entry->callback = callback;
-  entry->user_data = user_data;
-  entry->id = next_swap_buffers_callback_id++;
+  state->callback = callback;
+  state->user_data = user_data;
 
-  COGL_TAILQ_INSERT_TAIL (&onscreen->swap_callbacks, entry, list_node);
+  closure =
+    cogl_onscreen_add_frame_callback (onscreen,
+                                      shim_swap_buffers_callback,
+                                      state,
+                                      destroy_swap_buffers_callback_state);
 
-  return entry->id;
+  g_hash_table_insert (ctx->swap_callback_closures,
+                       GINT_TO_POINTER (id),
+                       closure);
+
+  return id;
 }
 
 void
 cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
                                             unsigned int id)
 {
-  CoglSwapBuffersNotifyEntry *entry;
+  CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
+  CoglFrameClosure *closure = g_hash_table_lookup (ctx->swap_callback_closures,
+                                                   GINT_TO_POINTER (id));
 
-  COGL_TAILQ_FOREACH (entry, &onscreen->swap_callbacks, list_node)
-    {
-      if (entry->id == id)
-        {
-          COGL_TAILQ_REMOVE (&onscreen->swap_callbacks, entry, list_node);
-          g_slice_free (CoglSwapBuffersNotifyEntry, entry);
-          break;
-        }
-    }
+  _COGL_RETURN_IF_FAIL (closure);
+
+  cogl_onscreen_remove_frame_callback (onscreen, closure);
 }
 
 void
@@ -361,15 +440,33 @@ cogl_onscreen_hide (CoglOnscreen *onscreen)
 }
 
 void
-_cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen)
+_cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info)
+{
+  CoglFrameClosure *entry, *tmp;
+
+  COGL_TAILQ_FOREACH_SAFE (entry,
+                           &onscreen->frame_closures,
+                           list_node,
+                           tmp)
+    {
+      entry->callback (onscreen, COGL_FRAME_EVENT_SYNC, info,
+                       entry->user_data);
+    }
+}
+
+void
+_cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info)
 {
-  CoglSwapBuffersNotifyEntry *entry, *tmp;
+  CoglFrameClosure *entry, *tmp;
 
   COGL_TAILQ_FOREACH_SAFE (entry,
-                           &onscreen->swap_callbacks,
+                           &onscreen->frame_closures,
                            list_node,
                            tmp)
-    entry->callback (COGL_FRAMEBUFFER (onscreen), entry->user_data);
+    {
+      entry->callback (onscreen, COGL_FRAME_EVENT_COMPLETE, info,
+                       entry->user_data);
+    }
 }
 
 void
@@ -519,50 +616,3 @@ cogl_onscreen_get_frame_info (CoglOnscreen *onscreen,
 
   return onscreen->frame_info[pos];
 }
-
-unsigned int
-cogl_onscreen_add_frame_info_callback (CoglOnscreen *onscreen,
-                                       CoglFrameInfoCallback callback,
-                                       void *user_data)
-{
-  CoglFrameInfoCallbackEntry *entry = g_slice_new (CoglFrameInfoCallbackEntry);
-  static int next_resize_callback_id = 0;
-
-  entry->callback = callback;
-  entry->user_data = user_data;
-  entry->id = next_resize_callback_id++;
-
-  COGL_TAILQ_INSERT_TAIL (&onscreen->frame_info_callbacks, entry, list_node);
-
-  return entry->id;
-}
-
-void
-cogl_onscreen_remove_frame_info_callback (CoglOnscreen *onscreen,
-                                          unsigned int id)
-{
-  CoglFrameInfoCallbackEntry *entry;
-
-  COGL_TAILQ_FOREACH (entry, &onscreen->frame_info_callbacks, list_node)
-    {
-      if (entry->id == id)
-        {
-          COGL_TAILQ_REMOVE (&onscreen->frame_info_callbacks, entry, list_node);
-          g_slice_free (CoglFrameInfoCallbackEntry, entry);
-          break;
-        }
-    }
-}
-
-void
-_cogl_onscreen_notify_frame_info (CoglOnscreen *onscreen)
-{
-  CoglFrameInfoCallbackEntry *entry, *tmp;
-
-  COGL_TAILQ_FOREACH_SAFE (entry,
-                           &onscreen->frame_info_callbacks,
-                           list_node,
-                           tmp)
-    entry->callback (onscreen, entry->user_data);
-}
-
diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h
index e872b90..7954eb4 100644
--- a/cogl/cogl-onscreen.h
+++ b/cogl/cogl-onscreen.h
@@ -35,6 +35,7 @@
 #include <cogl/cogl-context.h>
 #include <cogl/cogl-framebuffer.h>
 #include <cogl/cogl-frame-info.h>
+#include <cogl/cogl-object.h>
 
 COGL_BEGIN_DECLS
 
@@ -333,6 +334,149 @@ cogl_onscreen_swap_region (CoglOnscreen *onscreen,
                            const int *rectangles,
                            int n_rectangles);
 
+/**
+ * CoglFrameEvent:
+ * @COGL_FRAME_EVENT_SYNC: Notifies that the system compositor has
+ *                         acknowledged a frame and is ready for a
+ *                         new frame to be created. Only delivered
+ *                         if the %COGL_FEATURE_ID_FRAME_SYNC
+ *                         feature is supported.
+ * @COGL_FRAME_EVENT_COMPLETE: Notifies that a frame has ended. This
+ *                             is a good time for applications to
+ *                             collect statistics about the frame
+ *                             since the #CoglFrameInfo should hold
+ *                             the most data at this point. No other
+ *                             events should be expected after a
+ *                             @COGL_FRAME_EVENT_COMPLETE event.
+ *
+ * Identifiers that are passed to #CoglFrameCallback functions
+ * (registered using cogl_onscreen_add_frame_callback()) that
+ * mark the progression of a frame in some way which usually
+ * means that new information will have been accumulated in the
+ * frame's corresponding #CoglFrameInfo object.
+ *
+ * The last event that will be sent for a frame will be a
+ * @COGL_FRAME_EVENT_COMPLETE event and so these are a good
+ * opportunity to collect statistics about a frame since the
+ * #CoglFrameInfo should hold the most data at this point.
+ *
+ * <note>A frame may not be completed before the next frame can start
+ * so applications should avoid needing to collect all statistics for
+ * a particular frame before they can start a new frame.</note>
+ *
+ * Since: 1.14
+ * Stability: unstable
+ */
+typedef enum _CoglFrameEvent
+{
+  COGL_FRAME_EVENT_SYNC = 1,
+  COGL_FRAME_EVENT_COMPLETE
+} CoglFrameEvent;
+
+/**
+ * CoglFrameCallback:
+ * @onscreen: The onscreen that the frame is associated with
+ * @event: A #CoglFrameEvent notifying how the frame has progressed
+ * @info: The meta information, such as timing information, about
+ *        the frame that has progressed.
+ * @user_data: The user pointer passed to
+ *             cogl_onscreen_add_frame_callback()
+ *
+ * Is a callback that can be registered via
+ * cogl_onscreen_add_frame_callback() to be called when a frame
+ * progresses in some notable way.
+ *
+ * Please see the documentation for #CoglFrameEvent and
+ * cogl_onscreen_add_frame_callback() for more details about what
+ * events can be notified.
+ *
+ * Since: 1.14
+ * Stability: unstable
+ */
+typedef void (*CoglFrameCallback) (CoglOnscreen *onscreen,
+                                   CoglFrameEvent event,
+                                   CoglFrameInfo *info,
+                                   void *user_data);
+
+/**
+ * CoglFrameClosure:
+ *
+ * An opaque type that tracks a #CoglFrameCallback and associated user
+ * data. A #CoglFrameClosure pointer will be returned from
+ * cogl_onscreen_add_frame_callback() and it allows you to remove a
+ * callback later using cogl_onscreen_remove_frame_callback().
+ *
+ * Since: 1.14
+ * Stability: unstable
+ */
+typedef struct _CoglFrameClosure CoglFrameClosure;
+
+/**
+ * cogl_onscreen_add_frame_callback:
+ * @onscreen: A #CoglOnscreen framebuffer
+ * @callback: A callback function to call for frame events
+ * @user_data: A private pointer to be passed to @callback
+ * @destroy: An optional callback to destroy @user_data when the
+ *           @callback is removed or @onscreen is freed.
+ *
+ * Installs a @callback function that will be called for significant
+ * events relating to the given @onscreen framebuffer.
+ *
+ * If the %COGL_FEATURE_ID_FRAME_SYNC feature is supported
+ * then @callback will be used to notify when the system compositor is
+ * ready for this application to render a new frame. In this case
+ * %COGL_FRAME_EVENT_SYNC will be passed as the event argument to the
+ * given @callback in addition to the #CoglFrameInfo corresponding to
+ * the frame beeing acknowledged by the compositor.
+ *
+ * If the %COGL_FEATURE_ID_PRESENTATION_EVENTS is available then
+ * @callback will be called to notify when the frame has become
+ * visible to the user. In this case %COGL_FRAME_EVENT_PRESENTED will
+ * be passed as the event argument to the given @callback in addition
+ * to the #CoglFrameInfo corresponding to the newly presented frame.
+ *
+ * We recommend throttling your application according to
+ * %COGL_FRAME_EVENT_SYNC events whenever the
+ * %COGL_FEATURE_ID_FRAME_SYNC feature is available. This allows your
+ * application to avoid being blocked by the driver which will block
+ * your applications mainloop.
+ *
+ * <note>Applications should not make assumptions about the relative
+ * ordering of different types of frame events. A
+ * %COGL_FRAME_EVENT_PRESENTED event can be received before a
+ * %COGL_FRAME_EVENT_SYNC if the compositor is agressively throttling
+ * your application.</note>
+ *
+ * Return value: a #CoglFrameClosure pointer that can be used to
+ *               remove the callback and associated @user_data later.
+ * Since: 1.14
+ * Stability: unstable
+ */
+CoglFrameClosure *
+cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
+                                  CoglFrameCallback callback,
+                                  void *user_data,
+                                  CoglUserDataDestroyCallback destroy);
+
+/**
+ * cogl_onscreen_remove_frame_callback:
+ * @onscreen: A #CoglOnscreen
+ * @closure: A #CoglFrameClosure returned from
+ *           cogl_onscreen_add_frame_callback()
+ *
+ * Removes a callback and associated user data that were previously
+ * registered using cogl_onscreen_add_frame_callback().
+ *
+ * If a destroy callback was passed to
+ * cogl_onscreen_add_frame_callback() to destroy the user data then
+ * this will get called.
+ *
+ * Since: 1.14
+ * Stability: unstable
+ */
+void
+cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
+                                     CoglFrameClosure *closure);
 
 typedef void (*CoglSwapBuffersNotify) (CoglFramebuffer *framebuffer,
                                        void *user_data);
@@ -360,6 +504,7 @@ typedef void (*CoglSwapBuffersNotify) (CoglFramebuffer *framebuffer,
  *               the callback later.
  * Since: 1.10
  * Stability: unstable
+ * Deprecated: 1.14: Use cogl_onscreen_add_swap_complete_callback
  */
 unsigned int
 cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
@@ -376,6 +521,7 @@ cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
  *
  * Since: 1.10
  * Stability: unstable
+ * Deprecated: 1.14: Use cogl_onscreen_remove_swap_complete_callback
  */
 void
 cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
@@ -594,62 +740,6 @@ CoglFrameInfo *
 cogl_onscreen_get_frame_info (CoglOnscreen *onscreen,
                               int64_t frame_counter);
 
-/**
- * CoglFrameInfoCallback:
- * @onscreen: A #CoglOnscreen framebuffer that has updated timing information
- * @user_data: The private passed to
- *             cogl_onscreen_add_frame_info_callback()
- *
- * Is a callback type used with the
- * cogl_onscreen_add_frame_info_callback() allowing applications to be
- * notified whenever new frame timings information is available
- * via cogl_onscreen_get_frame_info().
- *
- * <note>A frame timings callback will only ever be called while dispatching
- * Cogl events from the system mainloop; so for example during
- * cogl_poll_dispatch(). This is so that callbacks shouldn't occur
- * while an application might have arbitrary locks held for
- * example.</note>
- *
- * Since: 2.0
- */
-typedef void (*CoglFrameInfoCallback) (CoglOnscreen *onscreen,
-                                       void *user_data);
-
-/**
- * cogl_onscreen_add_frame_info_callback:
- * @onscreen: A #CoglOnscreen framebuffer
- * @callback: A callback function to call when new frame timings information is available
- * @user_data: A private pointer to be passed to @callback
- *
- * Installs a @callback function that should be called whenever new data
- * is available via cogl_onscreen_get_frame_info().
- *
- * Return value: a unique identifier that can be used to remove to remove
- *               the callback later.
- * Since: 2.0
- * Stability: unstable
- */
-unsigned int
-cogl_onscreen_add_frame_info_callback (CoglOnscreen *onscreen,
-                                       CoglFrameInfoCallback callback,
-                                       void *user_data);
-
-/**
- * cogl_onscreen_remove_frame_info_callback:
- * @onscreen: A #CoglOnscreen framebuffer
- * @id: An identifier returned from cogl_onscreen_add_frame_info_callback()
- *
- * Removes a callback that was previously registered
- * using cogl_onscreen_add_frame_info_callback().
- *
- * Since: 1.10
- * Stability: unstable
- */
-void
-cogl_onscreen_remove_frame_info_callback (CoglOnscreen *onscreen,
-                                          unsigned int id);
-
 COGL_END_DECLS
 
 #endif /* __COGL_ONSCREEN_H */
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c
index ff538e2..498fb9d 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
@@ -753,6 +753,8 @@ _cogl_winsys_egl_context_init (CoglContext *context,
                                CoglError **error)
 {
   COGL_FLAGS_SET (context->features,
+                  COGL_FEATURE_ID_FRAME_SYNC, TRUE);
+  COGL_FLAGS_SET (context->features,
                   COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE);
   COGL_FLAGS_SET (context->winsys_features,
                   COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
@@ -894,7 +896,13 @@ flush_pending_swap_notify_cb (void *data,
 
       if (kms_onscreen->pending_swap_notify)
         {
-          _cogl_onscreen_notify_swap_buffers (onscreen);
+          int64_t frame_counter = cogl_onscreen_get_frame_counter (onscreen);
+          CoglFrameInfo *info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
+
+          info->complete = TRUE;
+
+          _cogl_onscreen_notify_frame_sync (onscreen, info);
+          _cogl_onscreen_notify_complete (onscreen, info);
           kms_onscreen->pending_swap_notify = FALSE;
         }
     }
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 75052a4..46e71e0 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -83,9 +83,9 @@ typedef struct _CoglOnscreenGLX
   CoglOnscreenXlib _parent;
   GLXDrawable glxwin;
   uint32_t last_swap_vsync_counter;
-  CoglBool pending_swap_notify;
+  CoglBool pending_sync_notify;
+  CoglBool pending_complete_notify;
   CoglBool pending_resize_notify;
-  CoglBool pending_frame_info_notify;
 } CoglOnscreenGLX;
 
 typedef struct _CoglTexturePixmapGLX
@@ -282,13 +282,13 @@ set_info_complete (CoglOnscreen *onscreen)
   CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
   CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
   CoglGLXDisplay *glx_display = context->display->winsys;
-  int frame_counter = cogl_onscreen_get_frame_counter (onscreen);
+  int64_t frame_counter = cogl_onscreen_get_frame_counter (onscreen);
   CoglFrameInfo *info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
 
   info->complete = TRUE;
 
-  glx_display->pending_frame_info_notify = TRUE;
-  glx_onscreen->pending_frame_info_notify = TRUE;
+  glx_display->pending_complete_notify = TRUE;
+  glx_onscreen->pending_complete_notify = TRUE;
 }
 
 static void
@@ -298,8 +298,6 @@ notify_swap_buffers (CoglContext *context, GLXBufferSwapComplete *swap_event)
   CoglDisplay *display = context->display;
   CoglGLXDisplay *glx_display = display->winsys;
   CoglOnscreenGLX *glx_onscreen;
-  int frame_counter;
-  CoglFrameInfo *info;
 
   if (!onscreen)
     return;
@@ -308,15 +306,19 @@ notify_swap_buffers (CoglContext *context, GLXBufferSwapComplete *swap_event)
   /* We only want to notify that the swap is complete when the
      application calls cogl_context_dispatch so instead of immediately
      notifying we'll set a flag to remember to notify later */
-  glx_display->pending_swap_notify = TRUE;
-  glx_onscreen->pending_swap_notify = TRUE;
+  glx_display->pending_sync_notify = TRUE;
+  glx_onscreen->pending_sync_notify = TRUE;
 
-  frame_counter = cogl_onscreen_get_frame_counter (onscreen);
-  info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
   if (swap_event->ust != 0)
-    info->presentation_time = ust_to_monotonic_time (context->display->renderer,
-                                                        glx_onscreen->glxwin,
-                                                        swap_event->ust);
+    {
+      int64_t frame_counter = cogl_onscreen_get_frame_counter (onscreen);
+      CoglFrameInfo *info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
+
+      info->presentation_time =
+        ust_to_monotonic_time (context->display->renderer,
+                               glx_onscreen->glxwin,
+                               swap_event->ust);
+    }
 
   set_info_complete (onscreen);
 }
@@ -700,9 +702,17 @@ update_winsys_features (CoglContext *context, CoglError **error)
                     COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
 
   if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
-    COGL_FLAGS_SET (context->features,
-                    COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
-                    TRUE);
+    {
+      COGL_FLAGS_SET (context->features,
+                      COGL_FEATURE_ID_FRAME_SYNC,
+                      TRUE);
+      COGL_FLAGS_SET (context->features,
+                      COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
+                      TRUE);
+      COGL_FLAGS_SET (context->features,
+                      COGL_FEATURE_ID_PRESENTATION_TIME,
+                      TRUE);
+    }
 
   return TRUE;
 }
@@ -1407,11 +1417,8 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
   if (glx_renderer->glXWaitForMsc ||
       glx_renderer->glXGetVideoSync)
     {
-      int frame_counter;
-      CoglFrameInfo *info;
-
-      frame_counter = cogl_onscreen_get_frame_counter (onscreen);
-      info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
+      int64_t frame_counter = cogl_onscreen_get_frame_counter (onscreen);
+      CoglFrameInfo *info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
 
       if (glx_renderer->glXWaitForMsc)
         {
@@ -1463,9 +1470,8 @@ set_refresh_rate_from_output (CoglOnscreen *onscreen,
   float refresh_rate = cogl_output_get_refresh_rate (output);
   if (refresh_rate != 0.0)
     {
-      int frame_counter = cogl_onscreen_get_frame_counter (onscreen);
+      int64_t frame_counter = cogl_onscreen_get_frame_counter (onscreen);
       CoglFrameInfo *info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
-
       info->refresh_rate = refresh_rate;
     }
 }
@@ -2419,9 +2425,9 @@ _cogl_winsys_poll_get_info (CoglContext *context,
 
   /* If we've already got a pending swap notify then we'll dispatch
      immediately */
-  if (glx_display->pending_swap_notify ||
+  if (glx_display->pending_sync_notify ||
       glx_display->pending_resize_notify ||
-      glx_display->pending_frame_info_notify)
+      glx_display->pending_complete_notify)
     *timeout = 0;
 }
 
@@ -2436,22 +2442,26 @@ flush_pending_notifications_cb (void *data,
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
       CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
 
-      if (glx_onscreen->pending_swap_notify)
+      if (glx_onscreen->pending_sync_notify)
         {
-          _cogl_onscreen_notify_swap_buffers (onscreen);
-          glx_onscreen->pending_swap_notify = FALSE;
+          int64_t frame_counter = cogl_onscreen_get_frame_counter (onscreen);
+          CoglFrameInfo *info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
+          _cogl_onscreen_notify_frame_sync (onscreen, info);
+          glx_onscreen->pending_sync_notify = FALSE;
         }
 
-      if (glx_onscreen->pending_resize_notify)
+      if (glx_onscreen->pending_complete_notify)
         {
-          _cogl_onscreen_notify_resize (onscreen);
-          glx_onscreen->pending_resize_notify = FALSE;
+          int64_t frame_counter = cogl_onscreen_get_frame_counter (onscreen);
+          CoglFrameInfo *info = cogl_onscreen_get_frame_info (onscreen, frame_counter);
+          _cogl_onscreen_notify_complete (onscreen, info);
+          glx_onscreen->pending_complete_notify = FALSE;
         }
 
-      if (glx_onscreen->pending_frame_info_notify)
+      if (glx_onscreen->pending_resize_notify)
         {
-          _cogl_onscreen_notify_frame_info (onscreen);
-          glx_onscreen->pending_frame_info_notify = FALSE;
+          _cogl_onscreen_notify_resize (onscreen);
+          glx_onscreen->pending_resize_notify = FALSE;
         }
     }
 }
@@ -2468,16 +2478,16 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
                                      poll_fds,
                                      n_poll_fds);
 
-  if (glx_display->pending_swap_notify ||
+  if (glx_display->pending_sync_notify ||
       glx_display->pending_resize_notify ||
-      glx_display->pending_frame_info_notify)
+      glx_display->pending_complete_notify)
     {
       g_list_foreach (context->framebuffers,
                       flush_pending_notifications_cb,
                       NULL);
-      glx_display->pending_swap_notify = FALSE;
+      glx_display->pending_sync_notify = FALSE;
       glx_display->pending_resize_notify = FALSE;
-      glx_display->pending_frame_info_notify = FALSE;
+      glx_display->pending_complete_notify = FALSE;
     }
 }
 



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