[Cogl] [PATCH 1/3] Make it possible to call swap_buffers within a frame event callback
Robert Bragg
robert at sixbynine.org
Thu Jan 31 13:00:04 PST 2013
This looks good to land to me:
Reviewed-by: Robert Bragg <robert at linux.intel.com>
thanks,
- Robert
On Thu, Jan 31, 2013 at 4:53 PM, Neil Roberts <neil at linux.intel.com> wrote:
> It seems like it would be quite a reasonable design for an application
> to immediately paint the buffer and call swap_buffers within the
> handler for the sync event. This previously wouldn't work.
>
> When using the GLX winsys if swap_region is called then it immediately
> tries to set the pending notification flag. However if this is called
> from the event callback then when the callback is complete it will
> clear the flag again and the pending notification will be lost. This
> patch just makes it clear the pending flag before invoking the
> callback so that it can be safely queued again.
>
> With any winsys that doesn't directly handle the sync event
> notification it would almost work except that it was iterating the
> live list of pending events. If the callback causes another event to
> be added to this list by issuing a buffer swap then the iteration
> would never complete and cogl_poll_dispatch would never return. This
> patch just makes it steal the list before iterating so that any
> additions will be dispatched by a later call to cogl_poll_dispatch
> instead.
> ---
> cogl/cogl-onscreen.c | 14 +++++++++++---
> cogl/winsys/cogl-winsys-glx.c | 23 ++++++++++++++++-------
> 2 files changed, 27 insertions(+), 10 deletions(-)
>
> diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c
> index afa4f63..e79bf22 100644
> --- a/cogl/cogl-onscreen.c
> +++ b/cogl/cogl-onscreen.c
> @@ -3,7 +3,7 @@
> *
> * An object oriented GL/GLES Abstraction/Utility Layer
> *
> - * Copyright (C) 2011 Intel Corporation.
> + * Copyright (C) 2011, 2013 Intel Corporation.
> *
> * This library is free software; you can redistribute it and/or
> * modify it under the terms of the GNU Lesser General Public
> @@ -418,9 +418,18 @@ void
> _cogl_dispatch_onscreen_events (CoglContext *context)
> {
> CoglOnscreenEvent *event, *tmp;
> + CoglOnscreenEventList queue;
> +
> + /* Dispatching the event callback may cause another frame to be
> + * drawn which in may cause another event to be queued immediately.
> + * To make sure this loop will only dispatch one set of events we'll
> + * steal the queue and iterate that separately */
> + COGL_TAILQ_INIT (&queue);
> + COGL_TAILQ_CONCAT (&queue, &context->onscreen_events_queue, list_node);
> + COGL_TAILQ_INIT (&context->onscreen_events_queue);
>
> COGL_TAILQ_FOREACH_SAFE (event,
> - &context->onscreen_events_queue,
> + &queue,
> list_node,
> tmp)
> {
> @@ -432,7 +441,6 @@ _cogl_dispatch_onscreen_events (CoglContext *context)
> cogl_object_unref (onscreen);
> cogl_object_unref (info);
>
> - COGL_TAILQ_REMOVE (&context->onscreen_events_queue, event, list_node);
> g_slice_free (CoglOnscreenEvent, event);
> }
> }
> diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
> index eb13e03..ac5ea8f 100644
> --- a/cogl/winsys/cogl-winsys-glx.c
> +++ b/cogl/winsys/cogl-winsys-glx.c
> @@ -2536,21 +2536,27 @@ flush_pending_notifications_cb (void *data,
> {
> CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
> CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
> + CoglBool pending_sync_notify = glx_onscreen->pending_sync_notify;
> + CoglBool pending_complete_notify = glx_onscreen->pending_complete_notify;
>
> - if (glx_onscreen->pending_sync_notify)
> + /* If swap_region is called then notifying the sync event could
> + * potentially immediately queue a subsequent pending notify so
> + * we need to clear the flag before invoking the callback */
> + glx_onscreen->pending_sync_notify = FALSE;
> + glx_onscreen->pending_complete_notify = FALSE;
> +
> + if (pending_sync_notify)
> {
> CoglFrameInfo *info = g_queue_peek_head (&onscreen->pending_frame_infos);
>
> _cogl_onscreen_notify_frame_sync (onscreen, info);
> - glx_onscreen->pending_sync_notify = FALSE;
> }
>
> - if (glx_onscreen->pending_complete_notify)
> + if (pending_complete_notify)
> {
> CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos);
>
> _cogl_onscreen_notify_complete (onscreen, info);
> - glx_onscreen->pending_complete_notify = FALSE;
>
> cogl_object_unref (info);
> }
> @@ -2579,12 +2585,15 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
> glx_display->pending_resize_notify ||
> glx_display->pending_complete_notify)
> {
> - g_list_foreach (context->framebuffers,
> - flush_pending_notifications_cb,
> - NULL);
> + /* These need to be cleared before invoking the callbacks in
> + * case the callbacks cause them to be set again */
> glx_display->pending_sync_notify = FALSE;
> glx_display->pending_resize_notify = FALSE;
> glx_display->pending_complete_notify = FALSE;
> +
> + g_list_foreach (context->framebuffers,
> + flush_pending_notifications_cb,
> + NULL);
> }
> }
>
> --
> 1.7.11.3.g3c3efa5
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl
More information about the Cogl
mailing list