[Cogl] [PATCH 2/3] Add a callback to get dirty events from a CoglOnscreen
Robert Bragg
robert at sixbynine.org
Tue May 28 04:42:16 PDT 2013
One minor thing I noticed was that the @callback argument for
cogl_onscreen_add_dirty_callback was a copy & paste from
cogl_onscreen_add_frame_callback and could do with a slight tweak.
Otherwise this patch looks good to land to me:
Reviewed-by: Robert Bragg <robert at linux.intel.com>
thanks,
- Robert
On Tue, May 14, 2013 at 5:03 PM, Neil Roberts <neil at linux.intel.com> wrote:
> This adds a callback that can be registered with
> cogl_onscreen_add_dirty_callback which will get called whenever the
> window system determines that the contents of the window is dirty and
> needs to be redrawn. Under the two X-based winsys's, this is reported
> off the back of the Expose events, under SDL it is reported from
> SDL_VIDEOEXPOSE or SDL_WINDOWEVENT_EXPOSED and under Windows from the
> WM_PAINT messages.
>
> There is a private feature flag to specify whether dirty events are
> supported. If the winsys does not set this then Cogl will simulate
> dirty events by emitting one when the window is first allocated and
> when it is resized. For example, under the Wayland this should end up
> doing the right thing because it will cause the application to paint
> when the window is first created, but it shouldn't need to paint again
> when the window is hidden and shown.
> ---
> cogl/cogl-context-private.h | 3 +-
> cogl/cogl-context.c | 3 +-
> cogl/cogl-framebuffer.c | 9 +-
> cogl/cogl-onscreen-private.h | 23 +++-
> cogl/cogl-onscreen.c | 186 +++++++++++++++++++++++----------
> cogl/cogl-onscreen.h | 113 +++++++++++++++++++-
> cogl/cogl-private.h | 9 +-
> cogl/winsys/cogl-winsys-egl-x11.c | 25 ++++-
> cogl/winsys/cogl-winsys-glx.c | 26 ++++-
> cogl/winsys/cogl-winsys-sdl.c | 37 +++++--
> cogl/winsys/cogl-winsys-sdl2.c | 70 +++++++++----
> cogl/winsys/cogl-winsys-wgl.c | 28 +++++
> doc/reference/cogl2/cogl2-sections.txt | 7 ++
> 13 files changed, 446 insertions(+), 93 deletions(-)
>
> diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
> index cf41c88..3512486 100644
> --- a/cogl/cogl-context-private.h
> +++ b/cogl/cogl-context-private.h
> @@ -3,7 +3,7 @@
> *
> * An object oriented GL/GLES Abstraction/Utility Layer
> *
> - * Copyright (C) 2007,2008,2009 Intel Corporation.
> + * Copyright (C) 2007,2008,2009,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
> @@ -174,6 +174,7 @@ struct _CoglContext
> CoglOffscreenAllocateFlags last_offscreen_allocate_flags;
>
> CoglOnscreenEventList onscreen_events_queue;
> + CoglOnscreenQueuedDirtyList onscreen_dirty_queue;
> CoglClosure *onscreen_dispatch_idle;
>
> CoglGLES2Context *current_gles2_context;
> diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
> index e4714be..13fb585 100644
> --- a/cogl/cogl-context.c
> +++ b/cogl/cogl-context.c
> @@ -3,7 +3,7 @@
> *
> * An object oriented GL/GLES Abstraction/Utility Layer
> *
> - * Copyright (C) 2007,2008,2009 Intel Corporation.
> + * Copyright (C) 2007,2008,2009,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
> @@ -288,6 +288,7 @@ cogl_context_new (CoglDisplay *display,
> context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;
>
> COGL_TAILQ_INIT (&context->onscreen_events_queue);
> + COGL_TAILQ_INIT (&context->onscreen_dirty_queue);
>
> g_queue_init (&context->gles2_context_stack);
>
> diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
> index ceb7916..3ac0e03 100644
> --- a/cogl/cogl-framebuffer.c
> +++ b/cogl/cogl-framebuffer.c
> @@ -642,6 +642,7 @@ cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
> {
> CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
> const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
> + CoglContext *ctx = framebuffer->context;
>
> if (framebuffer->allocated)
> return TRUE;
> @@ -659,10 +660,16 @@ cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
>
> if (!winsys->onscreen_init (onscreen, error))
> return FALSE;
> +
> + /* If the winsys doesn't support dirty events then we'll report
> + * one on allocation so that if the application only paints in
> + * response to dirty events then it will at least paint once to
> + * start */
> + if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_DIRTY_EVENTS))
> + _cogl_onscreen_queue_full_dirty (onscreen);
> }
> else
> {
> - CoglContext *ctx = framebuffer->context;
> CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer);
>
> if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
> diff --git a/cogl/cogl-onscreen-private.h b/cogl/cogl-onscreen-private.h
> index 4c2ce94..e960dc3 100644
> --- a/cogl/cogl-onscreen-private.h
> +++ b/cogl/cogl-onscreen-private.h
> @@ -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
> @@ -48,6 +48,18 @@ struct _CoglOnscreenEvent
> CoglFrameEvent type;
> };
>
> +typedef struct _CoglOnscreenQueuedDirty CoglOnscreenQueuedDirty;
> +
> +COGL_TAILQ_HEAD (CoglOnscreenQueuedDirtyList, CoglOnscreenQueuedDirty);
> +
> +struct _CoglOnscreenQueuedDirty
> +{
> + COGL_TAILQ_ENTRY (CoglOnscreenQueuedDirty) list_node;
> +
> + CoglOnscreen *onscreen;
> + CoglOnscreenDirtyInfo info;
> +};
> +
> struct _CoglOnscreen
> {
> CoglFramebuffer _parent;
> @@ -73,6 +85,8 @@ struct _CoglOnscreen
> CoglBool resizable;
> CoglClosureList resize_closures;
>
> + CoglClosureList dirty_closures;
> +
> int64_t frame_counter;
> int64_t swap_frame_counter; /* frame counter at last all to
> * cogl_onscreen_swap_region() or
> @@ -96,6 +110,11 @@ void
> _cogl_onscreen_notify_resize (CoglOnscreen *onscreen);
>
> void
> -_cogl_dispatch_onscreen_events (CoglContext *context);
> +_cogl_onscreen_queue_dirty (CoglOnscreen *onscreen,
> + const CoglOnscreenDirtyInfo *info);
> +
> +
> +void
> +_cogl_onscreen_queue_full_dirty (CoglOnscreen *onscreen);
>
> #endif /* __COGL_ONSCREEN_PRIVATE_H */
> diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c
> index 03c4849..d19748f 100644
> --- a/cogl/cogl-onscreen.c
> +++ b/cogl/cogl-onscreen.c
> @@ -49,6 +49,7 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
>
> COGL_LIST_INIT (&onscreen->frame_closures);
> COGL_LIST_INIT (&onscreen->resize_closures);
> + COGL_LIST_INIT (&onscreen->dirty_closures);
>
> framebuffer->config = onscreen_template->config;
> cogl_object_ref (framebuffer->config.swap_chain);
> @@ -92,6 +93,7 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
>
> _cogl_closure_list_disconnect_all (&onscreen->resize_closures);
> _cogl_closure_list_disconnect_all (&onscreen->frame_closures);
> + _cogl_closure_list_disconnect_all (&onscreen->dirty_closures);
>
> while ((frame_info = g_queue_pop_tail (&onscreen->pending_frame_infos)))
> cogl_object_unref (frame_info);
> @@ -107,6 +109,111 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
> }
>
> static void
> +notify_event (CoglOnscreen *onscreen,
> + CoglFrameEvent event,
> + CoglFrameInfo *info)
> +{
> + _cogl_closure_list_invoke (&onscreen->frame_closures,
> + CoglFrameCallback,
> + onscreen, event, info);
> +}
> +
> +static void
> +_cogl_dispatch_onscreen_cb (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_closure_disconnect (context->onscreen_dispatch_idle);
> + context->onscreen_dispatch_idle = NULL;
> +
> + COGL_TAILQ_FOREACH_SAFE (event,
> + &queue,
> + list_node,
> + tmp)
> + {
> + CoglOnscreen *onscreen = event->onscreen;
> + CoglFrameInfo *info = event->info;
> +
> + notify_event (onscreen, event->type, info);
> +
> + cogl_object_unref (onscreen);
> + cogl_object_unref (info);
> +
> + g_slice_free (CoglOnscreenEvent, event);
> + }
> +
> + while (!COGL_TAILQ_EMPTY (&context->onscreen_dirty_queue))
> + {
> + CoglOnscreenQueuedDirty *qe =
> + COGL_TAILQ_FIRST (&context->onscreen_dirty_queue);
> +
> + COGL_TAILQ_REMOVE (&context->onscreen_dirty_queue, qe, list_node);
> +
> + _cogl_closure_list_invoke (&qe->onscreen->dirty_closures,
> + CoglOnscreenDirtyCallback,
> + qe->onscreen,
> + &qe->info);
> +
> + cogl_object_unref (qe->onscreen);
> +
> + g_slice_free (CoglOnscreenQueuedDirty, qe);
> + }
> +}
> +
> +static void
> +_cogl_onscreen_queue_dispatch_idle (CoglOnscreen *onscreen)
> +{
> + CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
> +
> + if (!ctx->onscreen_dispatch_idle)
> + {
> + ctx->onscreen_dispatch_idle =
> + _cogl_poll_renderer_add_idle (ctx->display->renderer,
> + (CoglIdleCallback)
> + _cogl_dispatch_onscreen_cb,
> + ctx,
> + NULL);
> + }
> +}
> +
> +void
> +_cogl_onscreen_queue_dirty (CoglOnscreen *onscreen,
> + const CoglOnscreenDirtyInfo *info)
> +{
> + CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
> + CoglOnscreenQueuedDirty *qe = g_slice_new (CoglOnscreenQueuedDirty);
> +
> + qe->onscreen = cogl_object_ref (onscreen);
> + qe->info = *info;
> + COGL_TAILQ_INSERT_TAIL (&ctx->onscreen_dirty_queue, qe, list_node);
> +
> + _cogl_onscreen_queue_dispatch_idle (onscreen);
> +}
> +
> +void
> +_cogl_onscreen_queue_full_dirty (CoglOnscreen *onscreen)
> +{
> + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
> + CoglOnscreenDirtyInfo info;
> +
> + info.x = 0;
> + info.y = 0;
> + info.width = framebuffer->width;
> + info.height = framebuffer->height;
> +
> + _cogl_onscreen_queue_dirty (onscreen, &info);
> +}
> +
> +static void
> _cogl_onscreen_queue_event (CoglOnscreen *onscreen,
> CoglFrameEvent type,
> CoglFrameInfo *info)
> @@ -121,15 +228,7 @@ _cogl_onscreen_queue_event (CoglOnscreen *onscreen,
>
> 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);
> - }
> + _cogl_onscreen_queue_dispatch_idle (onscreen);
> }
>
> void
> @@ -393,50 +492,6 @@ cogl_onscreen_hide (CoglOnscreen *onscreen)
> }
> }
>
> -static void
> -notify_event (CoglOnscreen *onscreen,
> - CoglFrameEvent event,
> - CoglFrameInfo *info)
> -{
> - _cogl_closure_list_invoke (&onscreen->frame_closures,
> - CoglFrameCallback,
> - onscreen, event, info);
> -}
> -
> -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_closure_disconnect (context->onscreen_dispatch_idle);
> - context->onscreen_dispatch_idle = NULL;
> -
> - COGL_TAILQ_FOREACH_SAFE (event,
> - &queue,
> - list_node,
> - tmp)
> - {
> - CoglOnscreen *onscreen = event->onscreen;
> - CoglFrameInfo *info = event->info;
> -
> - notify_event (onscreen, event->type, info);
> -
> - cogl_object_unref (onscreen);
> - cogl_object_unref (info);
> -
> - g_slice_free (CoglOnscreenEvent, event);
> - }
> -}
> -
> void
> _cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info)
> {
> @@ -472,6 +527,10 @@ _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
> framebuffer->height = height;
>
> cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height);
> +
> + if (!(framebuffer->context->private_feature_flags &
> + COGL_PRIVATE_FEATURE_DIRTY_EVENTS))
> + _cogl_onscreen_queue_full_dirty (COGL_ONSCREEN (framebuffer));
> }
>
> void
> @@ -521,6 +580,27 @@ cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen,
> _cogl_closure_disconnect (closure);
> }
>
> +CoglOnscreenDirtyClosure *
> +cogl_onscreen_add_dirty_callback (CoglOnscreen *onscreen,
> + CoglOnscreenDirtyCallback callback,
> + void *user_data,
> + CoglUserDataDestroyCallback destroy)
> +{
> + return _cogl_closure_list_add (&onscreen->dirty_closures,
> + callback,
> + user_data,
> + destroy);
> +}
> +
> +void
> +cogl_onscreen_remove_dirty_callback (CoglOnscreen *onscreen,
> + CoglOnscreenDirtyClosure *closure)
> +{
> + _COGL_RETURN_IF_FAIL (closure);
> +
> + _cogl_closure_disconnect (closure);
> +}
> +
> int64_t
> cogl_onscreen_get_frame_counter (CoglOnscreen *onscreen)
> {
> diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h
> index 54881a8..455d450 100644
> --- a/cogl/cogl-onscreen.h
> +++ b/cogl/cogl-onscreen.h
> @@ -3,7 +3,7 @@
> *
> * An object oriented GL/GLES Abstraction/Utility Layer
> *
> - * Copyright (C) 2011,2012 Intel Corporation.
> + * Copyright (C) 2011,2012,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
> @@ -776,6 +776,117 @@ cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen,
> CoglOnscreenResizeClosure *closure);
>
> /**
> + * CoglOnscreenDirtyInfo:
> + * @x: Left edge of the dirty rectangle
> + * @y: Top edge of the dirty rectangle, measured from the top of the window
> + * @width: Width of the dirty rectangle
> + * @height: Height of the dirty rectangle
> + *
> + * A structure passed to callbacks registered using
> + * cogl_onscreen_add_dirty_callback(). The members describe a
> + * rectangle within the onscreen buffer that should be redrawn.
> + *
> + * Since: 1.16
> + * Stability: unstable
> + */
> +typedef struct _CoglOnscreenDirtyInfo CoglOnscreenDirtyInfo;
> +
> +struct _CoglOnscreenDirtyInfo
> +{
> + int x, y;
> + int width, height;
> +};
> +
> +/**
> + * CoglOnscreenDirtyCallback:
> + * @onscreen: The onscreen that the frame is associated with
> + * @info: A #CoglOnscreenDirtyInfo struct containing the details of the
> + * dirty area
> + * @user_data: The user pointer passed to
> + * cogl_onscreen_add_frame_callback()
> + *
> + * Is a callback that can be registered via
> + * cogl_onscreen_add_dirty_callback() to be called when the windowing
> + * system determines that a region of the onscreen window has been
> + * lost and the application should redraw it.
> + *
> + * Since: 1.16
> + * Stability: unstable
> + */
> +typedef void (*CoglOnscreenDirtyCallback) (CoglOnscreen *onscreen,
> + const CoglOnscreenDirtyInfo *info,
> + void *user_data);
> +
> +/**
> + * CoglOnscreenDirtyClosure:
> + *
> + * An opaque type that tracks a #CoglOnscreenDirtyCallback and associated
> + * user data. A #CoglOnscreenDirtyClosure pointer will be returned from
> + * cogl_onscreen_add_dirty_callback() and it allows you to remove a
> + * callback later using cogl_onscreen_remove_dirty_callback().
> + *
> + * Since: 1.16
> + * Stability: unstable
> + */
> +typedef struct _CoglClosure CoglOnscreenDirtyClosure;
> +
> +/**
> + * cogl_onscreen_add_dirty_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 whenever the
> + * window system has lost the contents of a region of the onscreen
> + * buffer and the application should redraw it to repair the buffer.
> + * For example this may happen in a window system without a compositor
> + * if a window that was previously covering up the onscreen window has
> + * been moved causing a region of the onscreen to be exposed.
> + *
> + * The @callback will be passed a #CoglOnscreenDirtyInfo struct which
> + * decribes a rectangle containing the newly dirtied region. Note that
> + * this may be called multiple times to describe a non-rectangular
> + * region composed of multiple smaller rectangles.
> + *
> + * The dirty events are separate from %COGL_FRAME_EVENT_SYNC events so
> + * the application should also listen for this event before rendering
> + * the dirty region to ensure that the framebuffer is actually ready
> + * for rendering.
> + *
> + * Return value: a #CoglOnscreenDirtyClosure pointer that can be used to
> + * remove the callback and associated @user_data later.
> + * Since: 1.16
> + * Stability: unstable
> + */
> +CoglOnscreenDirtyClosure *
> +cogl_onscreen_add_dirty_callback (CoglOnscreen *onscreen,
> + CoglOnscreenDirtyCallback callback,
> + void *user_data,
> + CoglUserDataDestroyCallback destroy);
> +
> +/**
> + * cogl_onscreen_remove_dirty_callback:
> + * @onscreen: A #CoglOnscreen
> + * @closure: A #CoglOnscreenDirtyClosure returned from
> + * cogl_onscreen_add_dirty_callback()
> + *
> + * Removes a callback and associated user data that were previously
> + * registered using cogl_onscreen_add_dirty_callback().
> + *
> + * If a destroy callback was passed to
> + * cogl_onscreen_add_dirty_callback() to destroy the user data then
> + * this will also get called.
> + *
> + * Since: 1.16
> + * Stability: unstable
> + */
> +void
> +cogl_onscreen_remove_dirty_callback (CoglOnscreen *onscreen,
> + CoglOnscreenDirtyClosure *closure);
> +
> +/**
> * cogl_is_onscreen:
> * @object: A #CoglObject pointer
> *
> diff --git a/cogl/cogl-private.h b/cogl/cogl-private.h
> index 08ee775..cbe8ca2 100644
> --- a/cogl/cogl-private.h
> +++ b/cogl/cogl-private.h
> @@ -3,7 +3,7 @@
> *
> * An object oriented GL/GLES Abstraction/Utility Layer
> *
> - * Copyright (C) 2010 Intel Corporation.
> + * Copyright (C) 2010,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
> @@ -57,7 +57,12 @@ typedef enum
> COGL_PRIVATE_FEATURE_ALPHA_TEXTURES = 1L<<21,
> COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE = 1L<<22,
> COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL = 1L<<23,
> - COGL_PRIVATE_FEATURE_ARBFP = 1L<<24
> + COGL_PRIVATE_FEATURE_ARBFP = 1L<<24,
> +
> + /* If this is set then the winsys is responsible for queueing dirty
> + * events. Otherwise a dirty event will be queued when the onscreen
> + * is first allocated or when it is shown or resized */
> + COGL_PRIVATE_FEATURE_DIRTY_EVENTS = 1L<<25
> } CoglPrivateFeatureFlags;
>
> /* Sometimes when evaluating pipelines, either during comparisons or
> diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/winsys/cogl-winsys-egl-x11.c
> index 5bc1d9f..24e45bf 100644
> --- a/cogl/winsys/cogl-winsys-egl-x11.c
> +++ b/cogl/winsys/cogl-winsys-egl-x11.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
> @@ -45,7 +45,7 @@
> #include "cogl-error-private.h"
> #include "cogl-poll-private.h"
>
> -#define COGL_ONSCREEN_X11_EVENT_MASK StructureNotifyMask
> +#define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask)
>
> static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
>
> @@ -173,6 +173,23 @@ event_filter_cb (XEvent *xevent, void *data)
> xevent->xconfigure.width,
> xevent->xconfigure.height);
> }
> + else if (xevent->type == Expose)
> + {
> + CoglOnscreen *onscreen =
> + find_onscreen_for_xid (context, xevent->xexpose.window);
> +
> + if (onscreen)
> + {
> + CoglOnscreenDirtyInfo info;
> +
> + info.x = xevent->xexpose.x;
> + info.y = xevent->xexpose.y;
> + info.width = xevent->xexpose.width;
> + info.height = xevent->xexpose.height;
> +
> + _cogl_onscreen_queue_dirty (onscreen, &info);
> + }
> + }
>
> return COGL_FILTER_CONTINUE;
> }
> @@ -302,6 +319,10 @@ _cogl_winsys_egl_context_init (CoglContext *context,
> COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
> TRUE);
>
> + /* We'll manually handle queueing dirty events in response to
> + * Expose events from X */
> + context->private_feature_flags |= COGL_PRIVATE_FEATURE_DIRTY_EVENTS;
> +
> return TRUE;
> }
>
> diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
> index d800cdd..5d436ee 100644
> --- a/cogl/winsys/cogl-winsys-glx.c
> +++ b/cogl/winsys/cogl-winsys-glx.c
> @@ -64,7 +64,7 @@
> #include <GL/glx.h>
> #include <X11/Xlib.h>
>
> -#define COGL_ONSCREEN_X11_EVENT_MASK StructureNotifyMask
> +#define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask)
> #define MAX_GLX_CONFIG_ATTRIBS 30
>
> typedef struct _CoglContextGLX
> @@ -555,6 +555,26 @@ glx_event_filter_cb (XEvent *xevent, void *data)
> }
> #endif /* GLX_INTEL_swap_event */
>
> + if (xevent->type == Expose)
> + {
> + CoglOnscreen *onscreen =
> + find_onscreen_for_xid (context, xevent->xexpose.window);
> +
> + if (onscreen)
> + {
> + CoglOnscreenDirtyInfo info;
> +
> + info.x = xevent->xexpose.x;
> + info.y = xevent->xexpose.y;
> + info.width = xevent->xexpose.width;
> + info.height = xevent->xexpose.height;
> +
> + _cogl_onscreen_queue_dirty (onscreen, &info);
> + }
> +
> + return COGL_FILTER_CONTINUE;
> + }
> +
> return COGL_FILTER_CONTINUE;
> }
>
> @@ -824,6 +844,10 @@ update_winsys_features (CoglContext *context, CoglError **error)
> TRUE);
> }
>
> + /* We'll manually handle queueing dirty events in response to
> + * Expose events from X */
> + context->private_feature_flags |= COGL_PRIVATE_FEATURE_DIRTY_EVENTS;
> +
> return TRUE;
> }
>
> diff --git a/cogl/winsys/cogl-winsys-sdl.c b/cogl/winsys/cogl-winsys-sdl.c
> index ed8212e..14a55c8 100644
> --- a/cogl/winsys/cogl-winsys-sdl.c
> +++ b/cogl/winsys/cogl-winsys-sdl.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
> @@ -230,25 +230,27 @@ flush_pending_resize_notification_idle (void *user_data)
> static CoglFilterReturn
> sdl_event_filter_cb (SDL_Event *event, void *data)
> {
> + CoglContext *context = data;
> + CoglDisplay *display = context->display;
> + CoglDisplaySdl *sdl_display = display->winsys;
> + CoglFramebuffer *framebuffer;
> +
> + if (!sdl_display->onscreen)
> + return COGL_FILTER_CONTINUE;
> +
> + framebuffer = COGL_FRAMEBUFFER (sdl_display->onscreen);
> +
> if (event->type == SDL_VIDEORESIZE)
> {
> - CoglContext *context = data;
> - CoglDisplay *display = context->display;
> - CoglDisplaySdl *sdl_display = display->winsys;
> CoglRenderer *renderer = display->renderer;
> CoglRendererSdl *sdl_renderer = renderer->winsys;
> float width = event->resize.w;
> float height = event->resize.h;
> - CoglFramebuffer *framebuffer;
> -
> - if (!sdl_display->onscreen)
> - return COGL_FILTER_CONTINUE;
>
> sdl_display->surface = SDL_SetVideoMode (width, height,
> 0, /* bitsperpixel */
> sdl_display->video_mode_flags);
>
> - framebuffer = COGL_FRAMEBUFFER (sdl_display->onscreen);
> _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
>
> /* We only want to notify that a resize happened when the
> @@ -265,6 +267,19 @@ sdl_event_filter_cb (SDL_Event *event, void *data)
>
> return COGL_FILTER_CONTINUE;
> }
> + else if (event->type == SDL_VIDEOEXPOSE)
> + {
> + CoglOnscreenDirtyInfo info;
> +
> + /* Sadly SDL doesn't seem to report the rectangle of the expose
> + * event so we'll just queue the whole window */
> + info.x = 0;
> + info.y = 0;
> + info.width = framebuffer->width;
> + info.height = framebuffer->height;
> +
> + _cogl_onscreen_queue_dirty (COGL_ONSCREEN (framebuffer), &info);
> + }
>
> return COGL_FILTER_CONTINUE;
> }
> @@ -282,6 +297,10 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error)
> (CoglNativeFilterFunc)sdl_event_filter_cb,
> context);
>
> + /* We'll manually handle queueing dirty events in response to
> + * SDL_VIDEOEXPOSE events */
> + context->private_feature_flags |= COGL_PRIVATE_FEATURE_DIRTY_EVENTS;
> +
> return _cogl_context_update_features (context, error);
> }
>
> diff --git a/cogl/winsys/cogl-winsys-sdl2.c b/cogl/winsys/cogl-winsys-sdl2.c
> index 5595f46..58666cb 100644
> --- a/cogl/winsys/cogl-winsys-sdl2.c
> +++ b/cogl/winsys/cogl-winsys-sdl2.c
> @@ -3,7 +3,7 @@
> *
> * An object oriented GL/GLES Abstraction/Utility Layer
> *
> - * Copyright (C) 2011, 2012 Intel Corporation.
> + * Copyright (C) 2011, 2012, 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
> @@ -303,30 +303,30 @@ flush_pending_resize_notifications_idle (void *user_data)
> }
>
> static CoglFilterReturn
> -sdl_event_filter_cb (SDL_Event *event, void *data)
> +sdl_window_event_filter (SDL_WindowEvent *event,
> + CoglContext *context)
> {
> - if (event->type == SDL_WINDOWEVENT &&
> - event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
> + SDL_Window *window;
> + CoglFramebuffer *framebuffer;
> +
> + window = SDL_GetWindowFromID (event->windowID);
> +
> + if (window == NULL)
> + return COGL_FILTER_CONTINUE;
> +
> + framebuffer = SDL_GetWindowData (window, COGL_SDL_WINDOW_DATA_KEY);
> +
> + if (framebuffer == NULL || framebuffer->context != context)
> + return COGL_FILTER_CONTINUE;
> +
> + if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED)
> {
> - CoglContext *context = data;
> CoglDisplay *display = context->display;
> CoglRenderer *renderer = display->renderer;
> CoglRendererSdl2 *sdl_renderer = renderer->winsys;
> - float width = event->window.data1;
> - float height = event->window.data2;
> - CoglFramebuffer *framebuffer;
> + float width = event->data1;
> + float height = event->data2;
> CoglOnscreenSdl2 *sdl_onscreen;
> - SDL_Window *window;
> -
> - window = SDL_GetWindowFromID (event->window.windowID);
> -
> - if (window == NULL)
> - return COGL_FILTER_CONTINUE;
> -
> - framebuffer = SDL_GetWindowData (window, COGL_SDL_WINDOW_DATA_KEY);
> -
> - if (framebuffer == NULL || framebuffer->context != context)
> - return COGL_FILTER_CONTINUE;
>
> _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
>
> @@ -344,13 +344,39 @@ sdl_event_filter_cb (SDL_Event *event, void *data)
>
> sdl_onscreen = COGL_ONSCREEN (framebuffer)->winsys;
> sdl_onscreen->pending_resize_notify = TRUE;
> + }
> + else if (event->event == SDL_WINDOWEVENT_EXPOSED)
> + {
> + CoglOnscreenDirtyInfo info;
>
> - return COGL_FILTER_CONTINUE;
> + /* Sadly SDL doesn't seem to report the rectangle of the expose
> + * event so we'll just queue the whole window */
> + info.x = 0;
> + info.y = 0;
> + info.width = framebuffer->width;
> + info.height = framebuffer->height;
> +
> + _cogl_onscreen_queue_dirty (COGL_ONSCREEN (framebuffer), &info);
> }
>
> return COGL_FILTER_CONTINUE;
> }
>
> +static CoglFilterReturn
> +sdl_event_filter_cb (SDL_Event *event, void *data)
> +{
> + CoglContext *context = data;
> +
> + switch (event->type)
> + {
> + case SDL_WINDOWEVENT:
> + return sdl_window_event_filter (&event->window, context);
> +
> + default:
> + return COGL_FILTER_CONTINUE;
> + }
> +}
> +
> static CoglBool
> _cogl_winsys_context_init (CoglContext *context, CoglError **error)
> {
> @@ -370,6 +396,10 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error)
> COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE,
> TRUE);
>
> + /* We'll manually handle queueing dirty events in response to
> + * SDL_WINDOWEVENT_EXPOSED events */
> + context->private_feature_flags |= COGL_PRIVATE_FEATURE_DIRTY_EVENTS;
> +
> _cogl_renderer_add_native_filter (renderer,
> (CoglNativeFilterFunc) sdl_event_filter_cb,
> context);
> diff --git a/cogl/winsys/cogl-winsys-wgl.c b/cogl/winsys/cogl-winsys-wgl.c
> index ecaf346..1e7fe4c 100644
> --- a/cogl/winsys/cogl-winsys-wgl.c
> +++ b/cogl/winsys/cogl-winsys-wgl.c
> @@ -235,6 +235,30 @@ win32_event_filter_cb (MSG *msg, void *data)
> }
> }
> }
> + else if (msg->message == WM_PAINT)
> + {
> + CoglOnscreen *onscreen =
> + find_onscreen_for_hwnd (context, msg->hwnd);
> + RECT rect;
> +
> + if (onscreen && GetUpdateRect (msg->hwnd, &rect, FALSE))
> + {
> + CoglOnscreenDirtyInfo info;
> +
> + /* Apparently this removes the dirty region from the window
> + * so that it won't be included in the next WM_PAINT
> + * message. This is also what SDL does to emit dirty
> + * events */
> + ValidateRect (msg->hwnd, &rect);
> +
> + info.x = rect.left;
> + info.y = rect.top;
> + info.width = rect.right - rect.left;
> + info.height = rect.bottom - rect.top;
> +
> + _cogl_onscreen_queue_dirty (onscreen, &info);
> + }
> + }
>
> return COGL_FILTER_CONTINUE;
> }
> @@ -680,6 +704,10 @@ update_winsys_features (CoglContext *context, CoglError **error)
> g_strfreev (split_extensions);
> }
>
> + /* We'll manually handle queueing dirty events in response to
> + * WM_PAINT messages */
> + context->private_feature_flags |= COGL_PRIVATE_FEATURE_DIRTY_EVENTS;
> +
> return TRUE;
> }
>
> diff --git a/doc/reference/cogl2/cogl2-sections.txt b/doc/reference/cogl2/cogl2-sections.txt
> index 59f40bd..7b00c04 100644
> --- a/doc/reference/cogl2/cogl2-sections.txt
> +++ b/doc/reference/cogl2/cogl2-sections.txt
> @@ -556,6 +556,13 @@ cogl_onscreen_add_frame_callback
> cogl_onscreen_remove_frame_callback
>
> <SUBSECTION>
> +CoglOnscreenDirtyInfo
> +CoglOnscreenDirtyCallback
> +CoglOnscreenDirtyClosure
> +cogl_onscreen_add_dirty_callback
> +cogl_onscreen_remove_dirty_callback
> +
> +<SUBSECTION>
> CoglOnscreenResizeCallback
> CoglOnscreenResizeClosure
> cogl_onscreen_add_resize_callback
> --
> 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