[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