[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