Add api for queuing idle callback internally

This adds a _cogl_poll_renderer_add_idle api that can be used internally
for queuing an idle callback without needing to make any assumption
about the system mainloop that is being used. This is now used to avoid
having the _cogl_poll_renderer_dispatch() directly check for all kinds of
events to dispatch, and to avoid having the winsys dispatch vfuncs need
to directly know about CoglContext. This means we can now avoid having a
back reference from CoglRenderer to the CoglContext.

Reviewed-by: Neil Roberts <neil@linux.intel.com>

(cherry picked from commit a1e169f18f4257caec58760adccfe4ec09b9805d)
This commit is contained in:
Robert Bragg 2013-04-18 14:19:43 +01:00
parent 04a1655804
commit e3975d1711
16 changed files with 356 additions and 340 deletions

View File

@ -81,7 +81,8 @@ _cogl_closure_list_add (CoglClosureList *list,
* @cb_type: The name of a typedef for the closure callback function signature
* @...: The the arguments to pass to the callback
*
* A convenience macro to invoke a closure list.
* A convenience macro to invoke a closure list with a variable number
* of arguments that will be passed to the closure callback functions.
*
* Note that the arguments will be evaluated multiple times so it is
* not safe to pass expressions that have side-effects.
@ -101,4 +102,15 @@ _cogl_closure_list_add (CoglClosureList *list,
} \
} G_STMT_END
#define _cogl_closure_list_invoke_no_args(list) \
G_STMT_START { \
CoglClosure *_c, *_tmp; \
\
COGL_LIST_FOREACH_SAFE (_c, (list), list_node, _tmp) \
{ \
void (*_cb)(void *) = _c->function; \
_cb (_c->user_data); \
} \
} G_STMT_END
#endif /* _COGL_CLOSURE_LIST_PRIVATE_H_ */

View File

@ -195,6 +195,7 @@ struct _CoglContext
int next_swap_callback_id;
CoglOnscreenEventList onscreen_events_queue;
CoglClosure *onscreen_dispatch_idle;
CoglGLES2Context *current_gles2_context;
GQueue gles2_context_stack;

View File

@ -206,18 +206,6 @@ cogl_context_new (CoglDisplay *display,
context->display = display;
/* Add a back reference to the context from the renderer because
* event dispatching is handled by the renderer and we don't
* currently have a generalized way of registering idle functions
* and such things internally so cogl_poll_renderer_dispatch()
* needs to poke inside the context if one is available to check
* if there are pending onscreen framebuffer events.
*
* FIXME: once we have a generalized way of registering idle
* functions then we can remove this back-reference.
*/
display->renderer->context = context;
/* This is duplicated data, but it's much more convenient to have
the driver attached to the context and the value is accessed a
lot throughout Cogl */

View File

@ -54,12 +54,7 @@ typedef struct _CoglGLXRenderer
/* GModule pointing to libGL which we use to get glX functions out of */
GModule *libgl_module;
/* Events get dispatched from the CoglRenderer and these are
* high-level flags that let us quickly check if there are any
* pending events to dispatch. */
CoglBool pending_sync_notify;
CoglBool pending_complete_notify;
CoglBool pending_resize_notify;
CoglClosure *flush_notifications_idle;
/* Copy of the winsys features that are based purely on the
* information we can get without using a GL context. We want to

View File

@ -34,6 +34,7 @@
#include "cogl-object-private.h"
#include "cogl1-context.h"
#include "cogl-closure-list-private.h"
#include "cogl-poll-private.h"
static void _cogl_onscreen_free (CoglOnscreen *onscreen);
@ -151,6 +152,16 @@ _cogl_onscreen_queue_event (CoglOnscreen *onscreen,
event->type = type;
COGL_TAILQ_INSERT_TAIL (&ctx->onscreen_events_queue, event, list_node);
if (!ctx->onscreen_dispatch_idle)
{
ctx->onscreen_dispatch_idle =
_cogl_poll_renderer_add_idle (ctx->display->renderer,
(CoglIdleCallback)
_cogl_dispatch_onscreen_events,
ctx,
NULL);
}
}
void
@ -503,6 +514,9 @@ _cogl_dispatch_onscreen_events (CoglContext *context)
COGL_TAILQ_CONCAT (&queue, &context->onscreen_events_queue, list_node);
COGL_TAILQ_INIT (&context->onscreen_events_queue);
_cogl_closure_disconnect (context->onscreen_dispatch_idle);
context->onscreen_dispatch_idle = NULL;
COGL_TAILQ_FOREACH_SAFE (event,
&queue,
list_node,

View File

@ -25,6 +25,10 @@
#ifndef __COGL_POLL_PRIVATE_H__
#define __COGL_POLL_PRIVATE_H__
#include "cogl-poll.h"
#include "cogl-renderer.h"
#include "cogl-closure-list-private.h"
void
_cogl_poll_renderer_remove_fd (CoglRenderer *renderer, int fd);
@ -33,4 +37,12 @@ _cogl_poll_renderer_add_fd (CoglRenderer *renderer,
int fd,
CoglPollFDEvent events);
typedef void (*CoglIdleCallback) (void *user_data);
CoglClosure *
_cogl_poll_renderer_add_idle (CoglRenderer *renderer,
CoglIdleCallback idle_cb,
void *user_data,
CoglUserDataDestroyCallback destroy_cb);
#endif /* __COGL_POLL_PRIVATE_H__ */

View File

@ -49,16 +49,10 @@ cogl_poll_renderer_get_info (CoglRenderer *renderer,
*poll_fds = (void *)renderer->poll_fds->data;
*n_poll_fds = renderer->poll_fds->len;
/* NB: This will be NULL until the renderer has been connected,
* associated with a CoglDisplay and then a CoglContext is
* created from that display. */
if (renderer->context)
if (!COGL_LIST_EMPTY (&renderer->idle_closures))
{
if (!COGL_TAILQ_EMPTY (&renderer->context->onscreen_events_queue))
{
*timeout = 0;
return renderer->poll_fds_age;
}
*timeout = 0;
return renderer->poll_fds_age;
}
winsys = renderer->winsys_vtable;
@ -80,17 +74,7 @@ cogl_poll_renderer_dispatch (CoglRenderer *renderer,
_COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
/* FIXME: arbitrary cogl components should just be able to queue
* idle functions so that we don't have to explicitly poke into
* CoglContext here and understand about the CoglOnscreen event
* queue... */
if (renderer->context)
{
CoglContext *context = renderer->context;
if (!COGL_TAILQ_EMPTY (&context->onscreen_events_queue))
_cogl_dispatch_onscreen_events (context);
}
_cogl_closure_list_invoke_no_args (&renderer->idle_closures);
winsys = renderer->winsys_vtable;
@ -141,3 +125,15 @@ _cogl_poll_renderer_add_fd (CoglRenderer *renderer,
g_array_append_val (renderer->poll_fds, pollfd);
renderer->poll_fds_age++;
}
CoglClosure *
_cogl_poll_renderer_add_idle (CoglRenderer *renderer,
CoglIdleCallback idle_cb,
void *user_data,
CoglUserDataDestroyCallback destroy_cb)
{
return _cogl_closure_list_add (&renderer->idle_closures,
idle_cb,
user_data,
destroy_cb);
}

View File

@ -31,6 +31,7 @@
#include "cogl-driver.h"
#include "cogl-texture-driver.h"
#include "cogl-context.h"
#include "cogl-closure-list-private.h"
#ifdef COGL_HAS_XLIB_SUPPORT
#include <X11/Xlib.h>
@ -54,20 +55,7 @@ struct _CoglRenderer
GArray *poll_fds;
int poll_fds_age;
/* NB: Currently a CoglContext can only be associated with 1
* CoglDisplay which itself can only be associated with 1
* CoglRenderer.
*
* We currently do event dispatching from the renderer but once we
* have fully setup a context then we need to refer to the context
* to dispatch context events.
*
* This gives us a back-reference to the CoglContext that can be
* referenced during event dispatching.
*
* We always need to consider that this may be NULL.
*/
CoglContext *context;
CoglClosureList idle_closures;
GList *outputs;

View File

@ -155,6 +155,8 @@ _cogl_renderer_free (CoglRenderer *renderer)
{
const CoglWinsysVtable *winsys = _cogl_renderer_get_winsys (renderer);
_cogl_closure_list_disconnect_all (&renderer->idle_closures);
if (winsys)
winsys->renderer_disconnect (renderer);
@ -185,6 +187,8 @@ cogl_renderer_new (void)
renderer->poll_fds = g_array_new (FALSE, TRUE, sizeof (CoglPollFD));
COGL_LIST_INIT (&renderer->idle_closures);
#ifdef COGL_HAS_XLIB_SUPPORT
renderer->xlib_enable_event_retrieval = TRUE;
#endif

View File

@ -68,19 +68,13 @@ cogl_sdl_context_new (int type, CoglError **error)
void
cogl_sdl_handle_event (CoglContext *context, SDL_Event *event)
{
const CoglWinsysVtable *winsys;
CoglRenderer *renderer;
_COGL_RETURN_IF_FAIL (cogl_is_context (context));
renderer = context->display->renderer;
winsys = renderer->winsys_vtable;
_cogl_renderer_handle_native_event (renderer, event);
if (winsys->poll_dispatch)
winsys->poll_dispatch (renderer, NULL, 0);
}
static void
@ -96,14 +90,16 @@ _cogl_sdl_push_wakeup_event (CoglContext *context)
void
cogl_sdl_idle (CoglContext *context)
{
_cogl_dispatch_onscreen_events (context);
CoglRenderer *renderer = context->display->renderer;
cogl_poll_renderer_dispatch (renderer, NULL, 0);
/* It is expected that this will be called from the application
* immediately before blocking in SDL_WaitEvent. However,
* dispatching the onscreen events may cause more events to be
* queued. If that happens we need to make sure the blocking returns
* immediately. We'll post our dummy event to make sure that
* happens */
if (!COGL_TAILQ_EMPTY (&context->onscreen_events_queue))
* dispatching cause more work to be queued. If that happens we need
* to make sure the blocking returns immediately. We'll post our
* dummy event to make sure that happens
*/
if (!COGL_LIST_EMPTY (&renderer->idle_closures))
_cogl_sdl_push_wakeup_event (context);
}

View File

@ -63,8 +63,7 @@ typedef struct _CoglRendererKMS
{
int fd;
struct gbm_device *gbm;
CoglBool pending_swap_notify;
CoglClosure *swap_notify_idle;
} CoglRendererKMS;
typedef struct _CoglOutputKMS
@ -603,6 +602,48 @@ free_current_bo (CoglOnscreen *onscreen)
}
}
static void
flush_pending_swap_notify_cb (void *data,
void *user_data)
{
CoglFramebuffer *framebuffer = data;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
if (kms_onscreen->pending_swap_notify)
{
CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos);
_cogl_onscreen_notify_frame_sync (onscreen, info);
_cogl_onscreen_notify_complete (onscreen, info);
kms_onscreen->pending_swap_notify = FALSE;
cogl_object_unref (info);
}
}
}
static void
flush_pending_swap_notify_idle (void *user_data)
{
CoglContext *context = user_data;
CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
/* This needs to be disconnected before invoking the callbacks in
* case the callbacks cause it to be queued again */
_cogl_closure_disconnect (kms_renderer->swap_notify_idle);
kms_renderer->swap_notify_idle = NULL;
g_list_foreach (context->framebuffers,
flush_pending_swap_notify_cb,
NULL);
}
static void
page_flip_handler (int fd,
unsigned int frame,
@ -627,9 +668,16 @@ page_flip_handler (int fd,
/* 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 */
kms_renderer->pending_swap_notify = TRUE;
* immediately notifying we queue an idle callback */
if (!kms_renderer->swap_notify_idle)
{
kms_renderer->swap_notify_idle =
_cogl_poll_renderer_add_idle (renderer,
flush_pending_swap_notify_idle,
context,
NULL);
}
kms_onscreen->pending_swap_notify = TRUE;
free_current_bo (onscreen);
@ -867,42 +915,6 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
onscreen->winsys = NULL;
}
static int64_t
_cogl_winsys_get_dispatch_timeout (CoglRenderer *renderer)
{
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
/* If we've already got a pending swap notify then we'll dispatch
* immediately */
return kms_renderer->pending_swap_notify ? 0 : -1;
}
static void
flush_pending_swap_notify_cb (void *data,
void *user_data)
{
CoglFramebuffer *framebuffer = data;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
if (kms_onscreen->pending_swap_notify)
{
CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos);
_cogl_onscreen_notify_frame_sync (onscreen, info);
_cogl_onscreen_notify_complete (onscreen, info);
kms_onscreen->pending_swap_notify = FALSE;
cogl_object_unref (info);
}
}
}
static void
_cogl_winsys_poll_dispatch (CoglRenderer *renderer,
const CoglPollFD *poll_fds,
@ -920,23 +932,6 @@ _cogl_winsys_poll_dispatch (CoglRenderer *renderer,
break;
}
/* FIXME: instead of requiring event dispatching which is handled at
* the CoglRenderer level to have to know about CoglContext we
* should have a generalized way of queuing an idle function */
if (renderer->context &&
kms_renderer->pending_swap_notify)
{
CoglContext *context = renderer->context;
/* This needs to be cleared before invoking the callbacks in
* case the callbacks cause it to be set again */
kms_renderer->pending_swap_notify = FALSE;
g_list_foreach (context->framebuffers,
flush_pending_swap_notify_cb,
NULL);
}
}
static const CoglWinsysEGLVtable
@ -976,7 +971,6 @@ _cogl_winsys_egl_kms_get_vtable (void)
vtable.onscreen_swap_region = NULL;
vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers;
vtable.get_dispatch_timeout = _cogl_winsys_get_dispatch_timeout;
vtable.poll_dispatch = _cogl_winsys_poll_dispatch;
vtable_inited = TRUE;

View File

@ -82,7 +82,7 @@ typedef struct _CoglRendererEGL
EGLint egl_version_major;
EGLint egl_version_minor;
CoglBool pending_resize_notify;
CoglClosure *resize_notify_idle;
/* Data specific to the EGL platform */
void *platform;

View File

@ -43,6 +43,7 @@
#include "cogl-texture-pixmap-x11-private.h"
#include "cogl-texture-2d-private.h"
#include "cogl-error-private.h"
#include "cogl-poll-private.h"
#define COGL_ONSCREEN_X11_EVENT_MASK StructureNotifyMask
@ -90,6 +91,42 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid)
return NULL;
}
static void
flush_pending_resize_notifications_cb (void *data,
void *user_data)
{
CoglFramebuffer *framebuffer = data;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
if (egl_onscreen->pending_resize_notify)
{
_cogl_onscreen_notify_resize (onscreen);
egl_onscreen->pending_resize_notify = FALSE;
}
}
}
static void
flush_pending_resize_notifications_idle (void *user_data)
{
CoglContext *context = user_data;
CoglRenderer *renderer = context->display->renderer;
CoglRendererEGL *egl_renderer = renderer->winsys;
/* This needs to be disconnected before invoking the callbacks in
* case the callbacks cause it to be queued again */
_cogl_closure_disconnect (egl_renderer->resize_notify_idle);
egl_renderer->resize_notify_idle = NULL;
g_list_foreach (context->framebuffers,
flush_pending_resize_notifications_cb,
NULL);
}
static void
notify_resize (CoglContext *context,
Window drawable,
@ -111,8 +148,16 @@ notify_resize (CoglContext *context,
/* We only want to notify that a resize happened when the
* application calls cogl_context_dispatch so instead of immediately
* notifying we'll set a flag to remember to notify later */
egl_renderer->pending_resize_notify = TRUE;
* notifying we queue an idle callback */
if (!egl_renderer->resize_notify_idle)
{
egl_renderer->resize_notify_idle =
_cogl_poll_renderer_add_idle (renderer,
flush_pending_resize_notifications_idle,
context,
NULL);
}
egl_onscreen->pending_resize_notify = TRUE;
}
@ -626,60 +671,17 @@ _cogl_winsys_xlib_get_visual_info (void)
static int64_t
_cogl_winsys_get_dispatch_timeout (CoglRenderer *renderer)
{
CoglRendererEGL *egl_renderer = renderer->winsys;
if (egl_renderer->pending_resize_notify)
return 0;
return _cogl_xlib_renderer_get_dispatch_timeout (renderer);
}
static void
flush_pending_notifications_cb (void *data,
void *user_data)
{
CoglFramebuffer *framebuffer = data;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
if (egl_onscreen->pending_resize_notify)
{
_cogl_onscreen_notify_resize (onscreen);
egl_onscreen->pending_resize_notify = FALSE;
}
}
}
static void
_cogl_winsys_poll_dispatch (CoglRenderer *renderer,
const CoglPollFD *poll_fds,
int n_poll_fds)
{
CoglRendererEGL *egl_renderer = renderer->winsys;
_cogl_xlib_renderer_poll_dispatch (renderer,
poll_fds,
n_poll_fds);
/* FIXME: instead of requiring event dispatching which is handled at
* the CoglRenderer level to have to know about CoglContext we
* should have a generalized way of queuing an idle function */
if (renderer->context &&
egl_renderer->pending_resize_notify)
{
CoglContext *context = renderer->context;
/* This needs to be cleared before invoking the callbacks in
* case the callbacks cause it to be set again */
egl_renderer->pending_resize_notify = FALSE;
g_list_foreach (context->framebuffers,
flush_pending_notifications_cb,
NULL);
}
}
#ifdef EGL_KHR_image_pixmap

View File

@ -50,6 +50,7 @@
#include "cogl-util.h"
#include "cogl-winsys-glx-private.h"
#include "cogl-error-private.h"
#include "cogl-poll-private.h"
#include <stdlib.h>
#include <sys/types.h>
@ -303,14 +304,86 @@ _cogl_winsys_get_clock_time (CoglContext *context)
return 0;
}
static void
flush_pending_notifications_cb (void *data,
void *user_data)
{
CoglFramebuffer *framebuffer = data;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
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 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);
}
if (pending_complete_notify)
{
CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos);
_cogl_onscreen_notify_complete (onscreen, info);
cogl_object_unref (info);
}
if (glx_onscreen->pending_resize_notify)
{
_cogl_onscreen_notify_resize (onscreen);
glx_onscreen->pending_resize_notify = FALSE;
}
}
}
static void
flush_pending_notifications_idle (void *user_data)
{
CoglContext *context = user_data;
CoglRenderer *renderer = context->display->renderer;
CoglGLXRenderer *glx_renderer = renderer->winsys;
/* This needs to be disconnected before invoking the callbacks in
* case the callbacks cause it to be queued again */
_cogl_closure_disconnect (glx_renderer->flush_notifications_idle);
glx_renderer->flush_notifications_idle = NULL;
g_list_foreach (context->framebuffers,
flush_pending_notifications_cb,
NULL);
}
static void
set_sync_pending (CoglOnscreen *onscreen)
{
CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
CoglRenderer *renderer = context->display->renderer;
CoglGLXRenderer *glx_renderer = renderer->winsys;
/* We only want to dispatch sync events when the application calls
* cogl_context_dispatch so instead of immediately notifying we
* queue an idle callback */
if (!glx_renderer->flush_notifications_idle)
{
glx_renderer->flush_notifications_idle =
_cogl_poll_renderer_add_idle (renderer,
flush_pending_notifications_idle,
context,
NULL);
}
glx_renderer->pending_sync_notify = TRUE;
glx_onscreen->pending_sync_notify = TRUE;
}
@ -319,9 +392,21 @@ set_complete_pending (CoglOnscreen *onscreen)
{
CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
CoglRenderer *renderer = context->display->renderer;
CoglGLXRenderer *glx_renderer = renderer->winsys;
/* We only want to notify swap completion when the application calls
* cogl_context_dispatch so instead of immediately notifying we
* queue an idle callback */
if (!glx_renderer->flush_notifications_idle)
{
glx_renderer->flush_notifications_idle =
_cogl_poll_renderer_add_idle (renderer,
flush_pending_notifications_idle,
context,
NULL);
}
glx_renderer->pending_complete_notify = TRUE;
glx_onscreen->pending_complete_notify = TRUE;
}
@ -388,7 +473,8 @@ notify_resize (CoglContext *context,
CoglOnscreen *onscreen = find_onscreen_for_xid (context,
configure_event->window);
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
CoglRenderer *renderer = context->display->renderer;
CoglGLXRenderer *glx_renderer = renderer->winsys;
CoglOnscreenGLX *glx_onscreen;
CoglOnscreenXlib *xlib_onscreen;
@ -403,9 +489,17 @@ notify_resize (CoglContext *context,
configure_event->height);
/* We only want to notify that a resize happened when the
application calls cogl_context_dispatch so instead of immediately
notifying we'll set a flag to remember to notify later */
glx_renderer->pending_resize_notify = TRUE;
* application calls cogl_context_dispatch so instead of immediately
* notifying we queue an idle callback */
if (!glx_renderer->flush_notifications_idle)
{
glx_renderer->flush_notifications_idle =
_cogl_poll_renderer_add_idle (renderer,
flush_pending_notifications_idle,
context,
NULL);
}
glx_onscreen->pending_resize_notify = TRUE;
if (!xlib_onscreen->is_foreign_xwin)
@ -2512,94 +2606,15 @@ _cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap)
static int64_t
_cogl_winsys_get_dispatch_timeout (CoglRenderer *renderer)
{
CoglGLXRenderer *glx_renderer = renderer->winsys;
/* If we've already got a pending swap notify then we'll dispatch
* immediately */
if (glx_renderer->pending_sync_notify ||
glx_renderer->pending_resize_notify ||
glx_renderer->pending_complete_notify)
return 0;
return _cogl_xlib_renderer_get_dispatch_timeout (renderer);
}
static void
flush_pending_notifications_cb (void *data,
void *user_data)
{
CoglFramebuffer *framebuffer = data;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
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 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);
}
if (pending_complete_notify)
{
CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos);
_cogl_onscreen_notify_complete (onscreen, info);
cogl_object_unref (info);
}
if (glx_onscreen->pending_resize_notify)
{
_cogl_onscreen_notify_resize (onscreen);
glx_onscreen->pending_resize_notify = FALSE;
}
}
}
static void
_cogl_winsys_poll_dispatch (CoglRenderer *renderer,
const CoglPollFD *poll_fds,
int n_poll_fds)
{
CoglGLXRenderer *glx_renderer = renderer->winsys;
_cogl_xlib_renderer_poll_dispatch (renderer,
poll_fds,
n_poll_fds);
/* FIXME: instead of requiring event dispatching which is handled at
* the CoglRenderer level to have to know about CoglContext we
* should have a generalized way of queuing an idle function */
if (renderer->context)
{
CoglContext *context = renderer->context;
if (glx_renderer->pending_sync_notify ||
glx_renderer->pending_resize_notify ||
glx_renderer->pending_complete_notify)
{
/* These need to be cleared before invoking the callbacks in
* case the callbacks cause them to be set again */
glx_renderer->pending_sync_notify = FALSE;
glx_renderer->pending_resize_notify = FALSE;
glx_renderer->pending_complete_notify = FALSE;
g_list_foreach (context->framebuffers,
flush_pending_notifications_cb,
NULL);
}
}
_cogl_xlib_renderer_poll_dispatch (renderer, poll_fds, n_poll_fds);
}
static CoglWinsysVtable _cogl_winsys_vtable =

View File

@ -38,10 +38,11 @@
#include "cogl-onscreen-private.h"
#include "cogl-winsys-sdl-private.h"
#include "cogl-error-private.h"
#include "cogl-poll-private.h"
typedef struct _CoglRendererSdl
{
CoglBool pending_resize_notify;
CoglClosure *resize_notify_idle;
} CoglRendererSdl;
typedef struct _CoglDisplaySdl
@ -209,6 +210,23 @@ error:
return FALSE;
}
static void
flush_pending_resize_notification_idle (void *user_data)
{
CoglContext *context = user_data;
CoglRenderer *renderer = context->display->renderer;
CoglRendererSdl *sdl_renderer = renderer->winsys;
CoglDisplaySdl *sdl_display = context->display->winsys;
CoglOnscreen *onscreen = sdl_display->onscreen;
/* This needs to be disconnected before invoking the callbacks in
* case the callbacks cause it to be queued again */
_cogl_closure_disconnect (sdl_renderer->resize_notify_idle);
sdl_renderer->resize_notify_idle = NULL;
_cogl_onscreen_notify_resize (onscreen);
}
static CoglFilterReturn
sdl_event_filter_cb (SDL_Event *event, void *data)
{
@ -217,7 +235,8 @@ sdl_event_filter_cb (SDL_Event *event, void *data)
CoglContext *context = data;
CoglDisplay *display = context->display;
CoglDisplaySdl *sdl_display = display->winsys;
CoglRendererSdl *sdl_renderer = display->renderer->winsys;
CoglRenderer *renderer = display->renderer;
CoglRendererSdl *sdl_renderer = renderer->winsys;
float width = event->resize.w;
float height = event->resize.h;
CoglFramebuffer *framebuffer;
@ -234,9 +253,15 @@ sdl_event_filter_cb (SDL_Event *event, void *data)
/* We only want to notify that a resize happened when the
* application calls cogl_context_dispatch so instead of
* immediately notifying we'll set a flag to remember to notify
* later */
sdl_renderer->pending_resize_notify = TRUE;
* immediately notifying we queue an idle callback */
if (!sdl_renderer->resize_notify_idle)
{
sdl_renderer->resize_notify_idle =
_cogl_poll_renderer_add_idle (renderer,
flush_pending_resize_notification_idle,
context,
NULL);
}
return COGL_FILTER_CONTINUE;
}
@ -378,31 +403,6 @@ _cogl_winsys_onscreen_set_resizable (CoglOnscreen *onscreen,
sdl_display->video_mode_flags);
}
static void
_cogl_winsys_poll_dispatch (CoglRenderer *renderer,
const CoglPollFD *poll_fds,
int n_poll_fds)
{
CoglRendererSdl *sdl_renderer = renderer->winsys;
/* FIXME: instead of requiring event dispatching which is handled at
* the CoglRenderer level to have to know about CoglContext we
* should have a generalized way of queuing an idle function */
if (renderer->context &&
sdl_renderer->pending_resize_notify)
{
CoglContext *context = renderer->context;
CoglDisplaySdl *sdl_display = context->display->winsys;
CoglOnscreen *onscreen = sdl_display->onscreen;
g_return_if_fail (onscreen != NULL);
_cogl_onscreen_notify_resize (onscreen);
sdl_renderer->pending_resize_notify = FALSE;
}
}
const CoglWinsysVtable *
_cogl_winsys_sdl_get_vtable (void)
{
@ -436,8 +436,6 @@ _cogl_winsys_sdl_get_vtable (void)
vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility;
vtable.onscreen_set_resizable = _cogl_winsys_onscreen_set_resizable;
vtable.poll_dispatch = _cogl_winsys_poll_dispatch;
vtable_inited = TRUE;
}

View File

@ -38,6 +38,7 @@
#include "cogl-onscreen-private.h"
#include "cogl-winsys-sdl-private.h"
#include "cogl-error-private.h"
#include "cogl-poll-private.h"
#include "cogl-sdl.h"
typedef struct _CoglContextSdl2
@ -47,7 +48,7 @@ typedef struct _CoglContextSdl2
typedef struct _CoglRendererSdl2
{
CoglBool pending_resize_notify;
CoglClosure *resize_notify_idle;
} CoglRendererSdl2;
typedef struct _CoglDisplaySdl2
@ -265,6 +266,42 @@ error:
return FALSE;
}
static void
flush_pending_notifications_cb (void *data,
void *user_data)
{
CoglFramebuffer *framebuffer = data;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenSdl2 *sdl_onscreen = onscreen->winsys;
if (sdl_onscreen->pending_resize_notify)
{
_cogl_onscreen_notify_resize (onscreen);
sdl_onscreen->pending_resize_notify = FALSE;
}
}
}
static void
flush_pending_resize_notifications_idle (void *user_data)
{
CoglContext *context = user_data;
CoglRenderer *renderer = context->display->renderer;
CoglRendererSdl2 *sdl_renderer = renderer->winsys;
/* This needs to be disconnected before invoking the callbacks in
* case the callbacks cause it to be queued again */
_cogl_closure_disconnect (sdl_renderer->resize_notify_idle);
sdl_renderer->resize_notify_idle = NULL;
g_list_foreach (context->framebuffers,
flush_pending_notifications_cb,
NULL);
}
static CoglFilterReturn
sdl_event_filter_cb (SDL_Event *event, void *data)
{
@ -273,7 +310,8 @@ sdl_event_filter_cb (SDL_Event *event, void *data)
{
CoglContext *context = data;
CoglDisplay *display = context->display;
CoglRendererSdl2 *sdl_renderer = display->renderer->winsys;
CoglRenderer *renderer = display->renderer;
CoglRendererSdl2 *sdl_renderer = renderer->winsys;
float width = event->window.data1;
float height = event->window.data2;
CoglFramebuffer *framebuffer;
@ -292,13 +330,19 @@ sdl_event_filter_cb (SDL_Event *event, void *data)
_cogl_framebuffer_winsys_update_size (framebuffer, width, height);
sdl_onscreen = COGL_ONSCREEN (framebuffer)->winsys;
/* We only want to notify that a resize happened when the
* application calls cogl_context_dispatch so instead of
* immediately notifying we'll set a flag to remember to notify
* later */
sdl_renderer->pending_resize_notify = TRUE;
* immediately notifying we queue an idle callback */
if (!sdl_renderer->resize_notify_idle)
{
sdl_renderer->resize_notify_idle =
_cogl_poll_renderer_add_idle (renderer,
flush_pending_resize_notifications_idle,
context,
NULL);
}
sdl_onscreen = COGL_ONSCREEN (framebuffer)->winsys;
sdl_onscreen->pending_resize_notify = TRUE;
return COGL_FILTER_CONTINUE;
@ -486,47 +530,6 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
SDL_HideWindow (sdl_onscreen->window);
}
static void
flush_pending_notifications_cb (void *data,
void *user_data)
{
CoglFramebuffer *framebuffer = data;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenSdl2 *sdl_onscreen = onscreen->winsys;
if (sdl_onscreen->pending_resize_notify)
{
_cogl_onscreen_notify_resize (onscreen);
sdl_onscreen->pending_resize_notify = FALSE;
}
}
}
static void
_cogl_winsys_poll_dispatch (CoglRenderer *renderer,
const CoglPollFD *poll_fds,
int n_poll_fds)
{
CoglRendererSdl2 *sdl_renderer = renderer->winsys;
/* FIXME: instead of requiring event dispatching which is handled at
* the CoglRenderer level to have to know about CoglContext we
* should have a generalized way of queuing an idle function */
if (renderer->context &&
sdl_renderer->pending_resize_notify)
{
CoglContext *context = renderer->context;
g_list_foreach (context->framebuffers,
flush_pending_notifications_cb,
NULL);
sdl_renderer->pending_resize_notify = FALSE;
}
}
SDL_Window *
cogl_sdl_onscreen_get_window (CoglOnscreen *onscreen)
{
@ -574,8 +577,6 @@ _cogl_winsys_sdl_get_vtable (void)
_cogl_winsys_onscreen_update_swap_throttled;
vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility;
vtable.poll_dispatch = _cogl_winsys_poll_dispatch;
vtable_inited = TRUE;
}