[Cogl] [PATCH 3/4] onscreen: Provide more general CoglFrameCallback api

Robert Bragg robert at sixbynine.org
Fri Jan 11 08:40:44 PST 2013


From: Robert Bragg <robert at linux.intel.com>

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       |    2 +-
 cogl/cogl-context.h               |    8 ++-
 cogl/cogl-onscreen-private.h      |   15 +++--
 cogl/cogl-onscreen.c              |   96 +++++++++++++-------------
 cogl/cogl-onscreen.h              |  133 ++++++++++++++++++++++++++-----------
 cogl/winsys/cogl-winsys-egl-kms.c |    2 +
 cogl/winsys/cogl-winsys-glx.c     |   11 ++-
 7 files changed, 170 insertions(+), 97 deletions(-)

diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index da114ba..4070932 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -184,7 +184,7 @@ struct _CoglContext
   gboolean have_last_offscreen_allocate_flags;
   CoglOffscreenAllocateFlags last_offscreen_allocate_flags;
 
-  int next_swap_complete_callback_id;
+  int next_frame_callback_id;
 
   CoglGLES2Context *current_gles2_context;
   GQueue gles2_context_stack;
diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h
index 0c6f0b5..ecfe990 100644
--- a/cogl/cogl-context.h
+++ b/cogl/cogl-context.h
@@ -206,7 +206,11 @@ cogl_is_context (void *object);
  *     for swap buffer completions.
  * @COGL_FEATURE_ID_GLES2_CONTEXT: Whether creating new GLES2 contexts is
  *    suported.
- *
+ * @COGL_FEATURE_ID_FRAME_SYNC: Whether %COGL_FRAME_EVENT_SYNC events
+ *    will be sent to registered #CoglFrameCallback functions.
+ * @COGL_FEATURE_ID_PRESENTATION_EVENTS: Whether
+ *    %COGL_FRAME_EVENT_PRESENTED events will be sent to registered
+ *    #CoglFrameCallback functions.
  *
  * All the capabilities that can vary between different GPUs supported
  * by Cogl. Applications that depend on any of these features should explicitly
@@ -235,6 +239,8 @@ typedef enum _CoglFeatureID
   COGL_FEATURE_ID_MIRRORED_REPEAT,
   COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
   COGL_FEATURE_ID_GLES2_CONTEXT,
+  COGL_FEATURE_ID_FRAME_SYNC,
+  COGL_FEATURE_ID_PRESENTATION_EVENTS,
 
   /*< private > */
   _COGL_N_FEATURE_IDS
diff --git a/cogl/cogl-onscreen-private.h b/cogl/cogl-onscreen-private.h
index 057c022..d9c9945 100644
--- a/cogl/cogl-onscreen-private.h
+++ b/cogl/cogl-onscreen-private.h
@@ -33,16 +33,19 @@
 #include <windows.h>
 #endif
 
-typedef struct _CoglSwapCompleteNotifyEntry CoglSwapCompleteNotifyEntry;
+typedef struct _CoglFrameCallbackEntry CoglFrameCallbackEntry;
 
-COGL_TAILQ_HEAD (CoglSwapCompleteNotifyList, CoglSwapCompleteNotifyEntry);
+COGL_TAILQ_HEAD (CoglFrameCallbackList, CoglFrameCallbackEntry);
 
-struct _CoglSwapCompleteNotifyEntry
+struct _CoglFrameCallbackEntry
 {
-  COGL_TAILQ_ENTRY (CoglSwapCompleteNotifyEntry) list_node;
+  COGL_TAILQ_ENTRY (CoglFrameCallbackEntry) list_node;
+
+  CoglFrameCallback callback;
 
-  CoglSwapCompleteNotify callback;
   void *user_data;
+  CoglUserDataDestroyCallback destroy;
+
   unsigned int id;
 };
 
@@ -75,7 +78,7 @@ struct _CoglOnscreen
 
   CoglBool swap_throttled;
 
-  CoglSwapCompleteNotifyList swap_callbacks;
+  CoglFrameCallbackList frame_callbacks;
 
   CoglBool resizable;
   CoglResizeNotifyList resize_callbacks;
diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c
index f3e5b5a..6efcdb9 100644
--- a/cogl/cogl-onscreen.c
+++ b/cogl/cogl-onscreen.c
@@ -46,7 +46,7 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
 
-  COGL_TAILQ_INIT (&onscreen->swap_callbacks);
+  COGL_TAILQ_INIT (&onscreen->frame_callbacks);
   COGL_TAILQ_INIT (&onscreen->resize_callbacks);
 
   framebuffer->config = onscreen_template->config;
@@ -116,7 +116,7 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
   CoglResizeNotifyEntry *resize_entry;
-  CoglSwapCompleteNotifyEntry *swap_entry;
+  CoglFrameCallbackEntry *frame_entry;
   CoglFrameInfo *frame_info;
 
   while ((resize_entry = COGL_TAILQ_FIRST (&onscreen->resize_callbacks)))
@@ -125,10 +125,14 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
       g_slice_free (CoglResizeNotifyEntry, resize_entry);
     }
 
-  while ((swap_entry = COGL_TAILQ_FIRST (&onscreen->swap_callbacks)))
+  while ((frame_entry = COGL_TAILQ_FIRST (&onscreen->frame_callbacks)))
     {
-      COGL_TAILQ_REMOVE (&onscreen->swap_callbacks, swap_entry, list_node);
-      g_slice_free (CoglSwapCompleteNotifyEntry, swap_entry);
+      COGL_TAILQ_REMOVE (&onscreen->frame_callbacks, frame_entry, list_node);
+
+      if (frame_entry->destroy)
+        frame_entry->destroy (frame_entry->user_data);
+
+      g_slice_free (CoglFrameCallbackEntry, frame_entry);
     }
 
   while ((frame_info = g_queue_pop_tail (&onscreen->pending_frame_infos)))
@@ -289,49 +293,41 @@ cogl_win32_onscreen_get_window (CoglOnscreen *onscreen)
 #endif /* COGL_HAS_WIN32_SUPPORT */
 
 unsigned int
-cogl_onscreen_add_swap_complete_callback (CoglOnscreen *onscreen,
-                                          CoglSwapCompleteNotify callback,
-                                          void *user_data)
+cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
+                                  CoglFrameCallback callback,
+                                  void *user_data,
+                                  CoglUserDataDestroyCallback destroy)
 {
-  CoglSwapCompleteNotifyEntry *entry = g_slice_new0 (CoglSwapCompleteNotifyEntry);
+  CoglFrameCallbackEntry *entry = g_slice_new0 (CoglFrameCallbackEntry);
   CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
 
   entry->callback = callback;
   entry->user_data = user_data;
-  entry->id = ctx->next_swap_complete_callback_id++;
+  entry->destroy = destroy;
+  entry->id = ctx->next_frame_callback_id++;
 
-  COGL_TAILQ_INSERT_TAIL (&onscreen->swap_callbacks, entry, list_node);
+  COGL_TAILQ_INSERT_TAIL (&onscreen->frame_callbacks, entry, list_node);
 
   return entry->id;
 }
 
-static CoglSwapCompleteNotifyEntry *
-remove_swap_complete_notify_entry (CoglOnscreen *onscreen,
-                                   unsigned int id)
+void
+cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
+                                     unsigned int id)
 {
-  CoglSwapCompleteNotifyEntry *entry;
+  CoglFrameCallbackEntry *entry;
 
-  COGL_TAILQ_FOREACH (entry, &onscreen->swap_callbacks, list_node)
+  COGL_TAILQ_FOREACH (entry, &onscreen->frame_callbacks, list_node)
     {
       if (entry->id == id)
         {
-          COGL_TAILQ_REMOVE (&onscreen->swap_callbacks, entry, list_node);
-          return entry;
+          COGL_TAILQ_REMOVE (&onscreen->frame_callbacks, entry, list_node);
+          if (entry->destroy)
+            entry->destroy (entry->user_data);
+          g_slice_free (CoglFrameCallbackEntry, entry);
+          return;
         }
     }
-
-  return NULL;
-}
-
-void
-cogl_onscreen_remove_swap_complete_callback (CoglOnscreen *onscreen,
-                                             unsigned int id)
-{
-  CoglSwapCompleteNotifyEntry *entry =
-    remove_swap_complete_notify_entry (onscreen, id);
-
-  if (entry)
-    g_slice_free (CoglSwapCompleteNotifyEntry, entry);
 }
 
 typedef struct _SwapBufferCallbackState
@@ -341,13 +337,21 @@ typedef struct _SwapBufferCallbackState
 } 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;
 
-  state->callback (COGL_FRAMEBUFFER (onscreen), state->user_data);
+  if (event == COGL_FRAME_EVENT_PRESENTED)
+    state->callback (COGL_FRAMEBUFFER (onscreen), state->user_data);
 }
 
 unsigned int
@@ -360,23 +364,17 @@ cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
   state->callback = callback;
   state->user_data = user_data;
 
-  return cogl_onscreen_add_swap_complete_callback (onscreen,
-                                                   shim_swap_buffers_callback,
-                                                   state);
+  return cogl_onscreen_add_frame_callback (onscreen,
+                                           shim_swap_buffers_callback,
+                                           state,
+                                           destroy_swap_buffers_callback_state);
 }
 
 void
 cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
                                             unsigned int id)
 {
-  CoglSwapCompleteNotifyEntry *entry =
-    remove_swap_complete_notify_entry (onscreen, id);
-
-  if (entry)
-    {
-      g_slice_free (SwapBufferCallbackState, entry->user_data);
-      g_slice_free (CoglSwapCompleteNotifyEntry, entry);
-    }
+  cogl_onscreen_remove_frame_callback (onscreen, id);
 }
 
 void
@@ -427,17 +425,19 @@ cogl_onscreen_hide (CoglOnscreen *onscreen)
 void
 _cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen)
 {
-  CoglSwapCompleteNotifyEntry *entry, *tmp;
+  CoglFrameCallbackEntry *entry, *tmp;
+  CoglFrameInfo *info = g_queue_pop_tail (&onscreen->pending_frame_infos);
 
   COGL_TAILQ_FOREACH_SAFE (entry,
-                           &onscreen->swap_callbacks,
+                           &onscreen->frame_callbacks,
                            list_node,
                            tmp)
     {
-      CoglFrameInfo *info = g_queue_pop_tail (&onscreen->pending_frame_infos);
-
-      entry->callback (onscreen, info, entry->user_data);
+      entry->callback (onscreen, COGL_FRAME_EVENT_PRESENTED, info,
+                       entry->user_data);
     }
+
+  cogl_object_unref (info);
 }
 
 void
diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h
index c36113d..501819d 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>
 #include <glib.h>
 
 G_BEGIN_DECLS
@@ -334,69 +335,125 @@ cogl_onscreen_swap_region (CoglOnscreen *onscreen,
                            int n_rectangles);
 
 /**
- * CoglSwapCompleteNotify:
- * @onscreen: The onscreen framebuffer who's swap has completed
- * @info: Meta information, such as timing information, about the
- *        completed swap
+ * 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_PRESENTED: Notifies that a frame has become
+ *                              visible to the user. Only delivered
+ *                              if the
+ *                              %COGL_FEATURE_ID_PRESENTATION_EVENTS
+ *                              feature is supported.
+ *
+ * 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.
+ *
+ * <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>
+ *
+ * Since: 1.14
+ * Stability: unstable
+ */
+typedef enum _CoglFrameEvent
+{
+  COGL_FRAME_EVENT_SYNC = 1,
+  COGL_FRAME_EVENT_PRESENTED
+} 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_swap_complete_callback()
+ *             cogl_onscreen_add_frame_callback()
  *
  * Is a callback that can be registered via
- * cogl_onscreen_add_swap_complete_callback() to be notified when a
- * swap buffers request made with cogl_onscreen_swap_buffers() has
- * completed and to be able to receive meta information about the
- * completed swap, such as timing information.
+ * 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 (*CoglSwapCompleteNotify) (CoglOnscreen *onscreen,
-                                        CoglFrameInfo *info,
-                                        void *user_data);
+typedef void (*CoglFrameCallback) (CoglOnscreen *onscreen,
+                                   CoglFrameEvent event,
+                                   CoglFrameInfo *info,
+                                   void *user_data);
 
 /**
- * cogl_onscreen_add_swap_complete_callback:
+ * cogl_onscreen_add_frame_callback:
  * @onscreen: A #CoglOnscreen framebuffer
- * @callback: A callback function to call when a swap has completed
+ * @callback: A callback function to call for frame events
  * @user_data: A private pointer to be passed to @callback
- *
- * Installs a @callback function that should be called whenever a swap buffers
- * request (made using cogl_onscreen_swap_buffers()) for the given
- * @onscreen completes.
- *
- * <note>Applications should check for the %COGL_FEATURE_ID_SWAP_BUFFERS_EVENT
- * feature before using this API. It's currently undefined when and if
- * registered callbacks will be called if this feature is not supported.</note>
- *
- * We recommend using this mechanism when available to manually throttle your
- * applications (in conjunction with  cogl_onscreen_set_swap_throttled()) so
- * your application will be able to avoid long blocks in the driver caused by
- * throttling when you request to swap buffers too quickly.
- *
- * Return value: a unique identifier that can be used to remove to remove
- *               the callback later.
+ * @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 unique identifier that can be used to remove to
+ *               remove the callback later.
  * Since: 1.14
  * Stability: unstable
  */
 unsigned int
-cogl_onscreen_add_swap_complete_callback (CoglOnscreen *onscreen,
-                                          CoglSwapCompleteNotify callback,
-                                          void *user_data);
+cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
+                                  CoglFrameCallback callback,
+                                  void *user_data,
+                                  CoglUserDataDestroyCallback destroy);
 
 /**
- * cogl_onscreen_remove_swap_complete_callback:
+ * cogl_onscreen_remove_frame_callback:
  * @onscreen: A #CoglOnscreen
- * @id: An identifier returned from cogl_onscreen_add_swap_complete_callback()
+ * @id: An identifier returned from cogl_onscreen_add_frame_callback()
  *
  * Removes a callback that was previously registered
- * using cogl_onscreen_add_swap_complete_callback().
+ * using cogl_onscreen_add_frame_callback().
  *
  * Since: 1.14
  * Stability: unstable
  */
 void
-cogl_onscreen_remove_swap_complete_callback (CoglOnscreen *onscreen,
-                                             unsigned int id);
+cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
+                                     unsigned int id);
 
 typedef void (*CoglSwapBuffersNotify) (CoglFramebuffer *framebuffer,
                                        void *user_data);
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c
index e1d098e..4a3480c 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,
 {
   COGL_FLAGS_SET (context->features,
                   COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE);
+  COGL_FLAGS_SET (context->features,
+                  COGL_FEATURE_ID_PRESENTATION_EVENTS, TRUE);
   COGL_FLAGS_SET (context->winsys_features,
                   COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
                   TRUE);
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 83dacf5..f8114c6 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -684,9 +684,14 @@ update_winsys_features (CoglContext *context, GError **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_SWAP_BUFFERS_EVENT,
+                      TRUE);
+      COGL_FLAGS_SET (context->features,
+                      COGL_FEATURE_ID_PRESENTATION_EVENTS,
+                      TRUE);
+    }
 
   return TRUE;
 }
-- 
1.7.7.6



More information about the Cogl mailing list