[cogl] Add a callback to get dirty events from a CoglOnscreen



commit 85c5a9ba419b2247bd768284c79ee69164a0c098
Author: Neil Roberts <neil linux intel com>
Date:   Tue May 14 13:39:48 2013 +0100

    Add a callback to get dirty events from a CoglOnscreen
    
    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. The Wayland winsys doesn't really have the concept
    of dirtying the buffer but in order to allow applications to work the
    same way on all platforms it will emit the event when the surface is
    first shown and whenever it is resized.
    
    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. The only winsys's that don't set this flag are
    things like KMS or the EGL null winsys where there is no windowing
    system and showing and hiding the onscreen doesn't really make any
    sense. In that case Cogl can assume the buffer will only become dirty
    once when it is first allocated.
    
    Reviewed-by: Robert Bragg <robert linux intel com>

 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                    |    8 +-
 cogl/winsys/cogl-winsys-egl-wayland.c  |   13 +++
 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 ++
 14 files changed, 458 insertions(+), 93 deletions(-)
---
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 2028094..5eeea80 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
@@ -176,6 +176,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 461d0f3..e3fae59 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 4faad61..e53c6bf 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -645,6 +645,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;
@@ -662,10 +663,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 9f4a215..f686b14 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
@@ -395,50 +494,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)
 {
@@ -474,6 +529,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
@@ -523,6 +582,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 2646d40..d9582fa 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
@@ -787,6 +787,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 dirty 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 15fafd7..52588db 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
@@ -58,7 +58,11 @@ typedef enum
   COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE = 1L<<22,
   COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL = 1L<<23,
   COGL_PRIVATE_FEATURE_ARBFP = 1L<<24,
-  COGL_PRIVATE_FEATURE_OES_EGL_SYNC = 1L<<25
+  COGL_PRIVATE_FEATURE_OES_EGL_SYNC = 1L<<25,
+  /* 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<<26
 } CoglPrivateFeatureFlags;
 
 /* Sometimes when evaluating pipelines, either during comparisons or
diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c
index 6732547..0df5639 100644
--- a/cogl/winsys/cogl-winsys-egl-wayland.c
+++ b/cogl/winsys/cogl-winsys-egl-wayland.c
@@ -324,6 +324,16 @@ _cogl_winsys_egl_context_init (CoglContext *context,
                   COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
                   TRUE);
 
+  /* We'll manually handle queueing dirty events when the surface is
+   * first shown or when it is resized. Note that this is slightly
+   * different from the emulated behaviour that CoglFramebuffer would
+   * provide if we didn't set this flag because we want to emit the
+   * event on show instead of on allocation. The Wayland protocol
+   * delays setting the surface type until the next buffer is attached
+   * so attaching a buffer before setting the type would not cause
+   * anything to be displayed */
+  context->private_feature_flags |= COGL_PRIVATE_FEATURE_DIRTY_EVENTS;
+
   return TRUE;
 }
 
@@ -436,6 +446,8 @@ flush_pending_resize (CoglOnscreen *onscreen)
                                             wayland_onscreen->pending_width,
                                             wayland_onscreen->pending_height);
 
+      _cogl_onscreen_queue_full_dirty (onscreen);
+
       wayland_onscreen->pending_dx = 0;
       wayland_onscreen->pending_dy = 0;
       wayland_onscreen->has_pending = FALSE;
@@ -485,6 +497,7 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
     {
       wl_shell_surface_set_toplevel (wayland_onscreen->wayland_shell_surface);
       wayland_onscreen->shell_surface_type_set = TRUE;
+      _cogl_onscreen_queue_full_dirty (onscreen);
     }
 
   /* FIXME: We should also do something here to hide the surface when
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 6e9a7d8..6a32e63 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 670ca8c..db67805 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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]