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>

(cherry picked from commit 85c5a9ba419b2247bd768284c79ee69164a0c098)

Conflicts:
	cogl/cogl-private.h
This commit is contained in:
Neil Roberts 2013-05-14 13:39:48 +01:00
parent 45e18e0fb7
commit d0944b8fbd
14 changed files with 458 additions and 93 deletions

View File

@ -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
@ -197,6 +197,7 @@ struct _CoglContext
int next_swap_callback_id;
CoglOnscreenEventList onscreen_events_queue;
CoglOnscreenQueuedDirtyList onscreen_dirty_queue;
CoglClosure *onscreen_dispatch_idle;
CoglGLES2Context *current_gles2_context;

View File

@ -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
@ -313,6 +313,7 @@ cogl_context_new (CoglDisplay *display,
g_hash_table_new (g_direct_hash, g_direct_equal);
COGL_TAILQ_INIT (&context->onscreen_events_queue);
COGL_TAILQ_INIT (&context->onscreen_dirty_queue);
g_queue_init (&context->gles2_context_stack);

View File

@ -684,6 +684,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;
@ -701,10 +702,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))

View File

@ -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
@ -99,6 +113,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 */

View File

@ -50,6 +50,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);
@ -121,6 +122,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);
@ -138,6 +140,111 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
g_free (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,
@ -153,15 +260,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
@ -501,50 +600,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)
{
@ -580,6 +635,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
@ -629,6 +688,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)
{

View File

@ -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
@ -814,6 +814,117 @@ void
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

View File

@ -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,11 @@ 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_OES_EGL_SYNC = 1L<<24
COGL_PRIVATE_FEATURE_OES_EGL_SYNC = 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

View File

@ -325,6 +325,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;
}
@ -437,6 +447,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;
@ -486,6 +498,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

View File

@ -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;
}
@ -303,6 +320,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;
}

View File

@ -63,7 +63,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
@ -557,6 +557,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;
}
@ -835,6 +855,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;
}

View File

@ -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
@ -246,25 +246,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
@ -281,6 +283,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;
}
@ -298,6 +313,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);
}

View File

@ -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);

View File

@ -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;
}
@ -682,6 +706,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;
}

View File

@ -611,6 +611,13 @@ CoglFrameClosure
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