[clutter] win32: Use the Cogl WGL winsys
- From: Neil Roberts <nroberts src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter] win32: Use the Cogl WGL winsys
- Date: Tue, 10 May 2011 16:58:26 +0000 (UTC)
commit f5ace7b2a5ed177271a44536351d0780df982fef
Author: Neil Roberts <neil linux intel com>
Date: Thu Apr 21 16:52:54 2011 +0100
win32: Use the Cogl WGL winsys
Cogl now has a full WGL winsys so Clutter doesn't need to directly
deal with WGL itself.
clutter/win32/clutter-backend-win32.c | 348 ++++++++-------------------------
clutter/win32/clutter-backend-win32.h | 6 +-
clutter/win32/clutter-event-win32.c | 8 +
clutter/win32/clutter-stage-win32.c | 59 ++++---
clutter/win32/clutter-stage-win32.h | 3 +-
5 files changed, 125 insertions(+), 299 deletions(-)
---
diff --git a/clutter/win32/clutter-backend-win32.c b/clutter/win32/clutter-backend-win32.c
index 04e469d..da61ea3 100644
--- a/clutter/win32/clutter-backend-win32.c
+++ b/clutter/win32/clutter-backend-win32.c
@@ -54,6 +54,15 @@ static HINSTANCE clutter_hinst = NULL;
/* various flags corresponding to pre init setup calls */
static gboolean _no_event_retrieval = FALSE;
+G_CONST_RETURN gchar *
+_clutter_backend_win32_get_vblank (void)
+{
+ if (clutter_vblank_name && strcmp (clutter_vblank_name, "0") == 0)
+ return "none";
+ else
+ return clutter_vblank_name;
+}
+
gboolean
clutter_backend_win32_pre_parse (ClutterBackend *backend,
GError **error)
@@ -125,6 +134,7 @@ clutter_backend_win32_finalize (GObject *gobject)
static void
clutter_backend_win32_dispose (GObject *gobject)
{
+ ClutterBackend *backend = CLUTTER_BACKEND (gobject);
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject);
ClutterStageManager *stage_manager;
@@ -139,26 +149,13 @@ clutter_backend_win32_dispose (GObject *gobject)
/* Unrealize all shaders, since the GL context is going away */
_clutter_shader_release_all ();
- if (backend_win32->gl_context)
- {
- wglMakeCurrent (NULL, NULL);
- wglDeleteContext (backend_win32->gl_context);
- backend_win32->gl_context = NULL;
- }
-
- if (backend_win32->dummy_dc)
- {
- ReleaseDC (backend_win32->dummy_hwnd, backend_win32->dummy_dc);
- backend_win32->dummy_dc = NULL;
- }
+ G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject);
- if (backend_win32->dummy_hwnd)
+ if (backend->cogl_context)
{
- DestroyWindow (backend_win32->dummy_hwnd);
- backend_win32->dummy_hwnd = NULL;
+ cogl_object_unref (backend->cogl_context);
+ backend->cogl_context = NULL;
}
-
- G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject);
}
static GObject *
@@ -185,296 +182,110 @@ clutter_backend_win32_constructor (GType gtype,
return g_object_ref (backend_singleton);
}
-static gboolean
-check_vblank_env (const char *name)
-{
- return clutter_vblank_name && !g_ascii_strcasecmp (clutter_vblank_name, name);
-}
-
ClutterFeatureFlags
clutter_backend_win32_get_features (ClutterBackend *backend)
{
- ClutterFeatureFlags flags;
- const gchar *extensions;
- SwapIntervalProc swap_interval;
- ClutterBackendWin32 *backend_win32;
-
- /* this will make sure that the GL context exists and is bound to a
- drawable */
- backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
- g_return_val_if_fail (backend_win32->gl_context != NULL, 0);
- g_return_val_if_fail (wglGetCurrentDC () != NULL, 0);
-
- extensions = (const gchar *) glGetString (GL_EXTENSIONS);
-
- CLUTTER_NOTE (BACKEND,
- "Checking features\n"
- " GL_VENDOR: %s\n"
- " GL_RENDERER: %s\n"
- " GL_VERSION: %s\n"
- " GL_EXTENSIONS: %s\n",
- glGetString (GL_VENDOR),
- glGetString (GL_RENDERER),
- glGetString (GL_VERSION),
- extensions);
-
- flags = CLUTTER_FEATURE_STAGE_USER_RESIZE
- | CLUTTER_FEATURE_STAGE_CURSOR
- | CLUTTER_FEATURE_STAGE_MULTIPLE;
-
- /* If the VBlank should be left at the default or it has been
- disabled elsewhere (eg NVIDIA) then don't bother trying to check
- for the swap control extension */
- if (getenv ("__GL_SYNC_TO_VBLANK") || check_vblank_env ("default"))
- CLUTTER_NOTE (BACKEND, "vblank sync: left at default at user request");
- else if (cogl_clutter_check_extension ("WGL_EXT_swap_control", extensions)
- && (swap_interval = (SwapIntervalProc)
- wglGetProcAddress ((LPCSTR) "wglSwapIntervalEXT")))
- {
- /* According to the specification for the WGL_EXT_swap_control
- extension the default swap interval is 1 anyway, so if no
- vblank is requested then we should explicitly set it to
- zero */
- if (check_vblank_env ("none"))
- {
- if (swap_interval (0))
- CLUTTER_NOTE (BACKEND, "vblank sync: successfully disabled");
- else
- CLUTTER_NOTE (BACKEND, "vblank sync: disabling failed");
- }
- else
- {
- if (swap_interval (1))
- {
- flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
- CLUTTER_NOTE (BACKEND, "vblank sync: wglSwapIntervalEXT "
- "vblank setup success");
- }
- else
- CLUTTER_NOTE (BACKEND, "vblank sync: wglSwapIntervalEXT "
- "vblank setup failed");
- }
- }
- else
- CLUTTER_NOTE (BACKEND, "no use-able vblank mechanism found");
-
- CLUTTER_NOTE (BACKEND, "backend features checked");
+ ClutterBackendClass *parent_class;
+ ClutterFeatureFlags flags;
- return flags;
-}
+ parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_win32_parent_class);
-static ATOM
-clutter_backend_win32_get_dummy_window_class ()
-{
- static ATOM klass = 0;
+ flags = CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR;
- if (klass == 0)
+ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
{
- WNDCLASSW wndclass;
- memset (&wndclass, 0, sizeof (wndclass));
- wndclass.lpfnWndProc = DefWindowProc;
- wndclass.hInstance = GetModuleHandleW (NULL);
- wndclass.lpszClassName = L"ClutterBackendWin32DummyWindow";
- klass = RegisterClassW (&wndclass);
+ CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers");
+ flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
}
-
- return klass;
-}
-
-static gboolean
-clutter_backend_win32_pixel_format_is_better (const PIXELFORMATDESCRIPTOR *pfa,
- const PIXELFORMATDESCRIPTOR *pfb)
-{
- /* Always prefer a format with a stencil buffer */
- if (pfa->cStencilBits == 0)
+ else
{
- if (pfb->cStencilBits > 0)
- return TRUE;
+ CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer");
+ flags |= CLUTTER_FEATURE_STAGE_STATIC;
}
- else if (pfb->cStencilBits == 0)
- return FALSE;
- /* Prefer a bigger color buffer */
- if (pfb->cColorBits > pfa->cColorBits)
- return TRUE;
- else if (pfb->cColorBits < pfa->cColorBits)
- return FALSE;
-
- /* Prefer a bigger depth buffer */
- return pfb->cDepthBits > pfa->cDepthBits;
-}
-
-static int
-clutter_backend_win32_choose_pixel_format (HDC dc, PIXELFORMATDESCRIPTOR *pfd)
-{
- int i, num_formats, best_pf = 0;
- PIXELFORMATDESCRIPTOR best_pfd;
-
- num_formats = DescribePixelFormat (dc, 0, sizeof (best_pfd), NULL);
-
- for (i = 1; i <= num_formats; i++)
+ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
{
- memset (pfd, 0, sizeof (*pfd));
-
- if (DescribePixelFormat (dc, i, sizeof (best_pfd), pfd)
- /* Check whether this format is useable by Clutter */
- && ((pfd->dwFlags & (PFD_SUPPORT_OPENGL
- | PFD_DRAW_TO_WINDOW
- | PFD_DOUBLEBUFFER
- | PFD_GENERIC_FORMAT))
- == (PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW))
- && pfd->iPixelType == PFD_TYPE_RGBA
- && pfd->cColorBits >= 16 && pfd->cColorBits <= 32
- && pfd->cDepthBits >= 16 && pfd->cDepthBits <= 32
- /* Check whether this is a better format than one we've
- already found */
- && (best_pf == 0
- || clutter_backend_win32_pixel_format_is_better (&best_pfd, pfd)))
- {
- best_pf = i;
- best_pfd = *pfd;
- }
+ CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
+ flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
}
+ else
+ CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
- *pfd = best_pfd;
+ CLUTTER_NOTE (BACKEND, "backend features checked");
- return best_pf;
+ return flags;
}
static gboolean
clutter_backend_win32_create_context (ClutterBackend *backend,
GError **error)
{
- ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
+ CoglSwapChain *swap_chain;
+ CoglOnscreenTemplate *onscreen_template;
- /* COGL assumes that there is always a GL context selected; in order
- * to make sure that a WGL context exists and is made current, we
- * use a small dummy window that never gets shown to which we can
- * always fall back if no stage is available
- */
- if (backend_win32->dummy_hwnd == NULL)
- {
- ATOM window_class = clutter_backend_win32_get_dummy_window_class ();
-
- if (window_class == 0)
- {
- g_critical ("Unable to register window class");
- return FALSE;
- }
-
- backend_win32->dummy_hwnd =
- CreateWindowW ((LPWSTR) MAKEINTATOM (window_class),
- L".",
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- 1, 1,
- NULL, NULL,
- GetModuleHandle (NULL),
- NULL);
-
- if (backend_win32->dummy_hwnd == NULL)
- {
- g_critical ("Unable to create dummy window");
- return FALSE;
- }
- }
+ if (backend->cogl_context)
+ return TRUE;
- if (backend_win32->dummy_dc == NULL)
- {
- PIXELFORMATDESCRIPTOR pfd;
- int pf;
+ backend->cogl_renderer = cogl_renderer_new ();
+ if (!cogl_renderer_connect (backend->cogl_renderer, error))
+ goto error;
- backend_win32->dummy_dc = GetDC (backend_win32->dummy_hwnd);
+ swap_chain = cogl_swap_chain_new ();
- pf = clutter_backend_win32_choose_pixel_format (backend_win32->dummy_dc,
- &pfd);
+ onscreen_template = cogl_onscreen_template_new (swap_chain);
+ cogl_object_unref (swap_chain);
- if (pf == 0 || !SetPixelFormat (backend_win32->dummy_dc, pf, &pfd))
- {
- g_critical ("Unable to find suitable GL pixel format");
- ReleaseDC (backend_win32->dummy_hwnd, backend_win32->dummy_dc);
- backend_win32->dummy_dc = NULL;
- return FALSE;
- }
- }
+ if (!cogl_renderer_check_onscreen_template (backend->cogl_renderer,
+ onscreen_template,
+ error))
+ goto error;
- if (backend_win32->gl_context == NULL)
- {
- backend_win32->gl_context = wglCreateContext (backend_win32->dummy_dc);
+ backend->cogl_display = cogl_display_new (backend->cogl_renderer,
+ onscreen_template);
+ cogl_object_unref (backend->cogl_renderer);
+ cogl_object_unref (onscreen_template);
- if (backend_win32->gl_context == NULL)
- {
- g_critical ("Unable to create suitable GL context");
- return FALSE;
- }
- }
+ if (!cogl_display_setup (backend->cogl_display, error))
+ goto error;
- CLUTTER_NOTE (BACKEND, "Selecting dummy 0x%x for the WGL context",
- (unsigned int) backend_win32->dummy_hwnd);
+ backend->cogl_context = cogl_context_new (backend->cogl_display, error);
+ if (!backend->cogl_context)
+ goto error;
- wglMakeCurrent (backend_win32->dummy_dc, backend_win32->gl_context);
+ /* XXX: eventually this should go away but a lot of Cogl code still
+ * depends on a global default context. */
+ cogl_set_default_context (backend->cogl_context);
return TRUE;
+
+error:
+ if (backend->cogl_display)
+ {
+ cogl_object_unref (backend->cogl_display);
+ backend->cogl_display = NULL;
+ }
+
+ if (onscreen_template)
+ cogl_object_unref (onscreen_template);
+ if (swap_chain)
+ cogl_object_unref (swap_chain);
+
+ if (backend->cogl_renderer)
+ {
+ cogl_object_unref (backend->cogl_renderer);
+ backend->cogl_renderer = NULL;
+ }
+ return FALSE;
}
static void
clutter_backend_win32_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
- ClutterStageWindow *impl;
-
- if (stage == NULL ||
- CLUTTER_ACTOR_IN_DESTRUCTION (stage) ||
- ((impl = _clutter_stage_get_window (stage)) == NULL))
- {
- CLUTTER_NOTE (MULTISTAGE, "Clearing all context");
+ ClutterStageWin32 *stage_win32 =
+ CLUTTER_STAGE_WIN32 (_clutter_stage_get_window (stage));
- wglMakeCurrent (NULL, NULL);
- }
- else
- {
- ClutterBackendWin32 *backend_win32;
- ClutterStageWin32 *stage_win32;
-
- g_return_if_fail (impl != NULL);
-
- CLUTTER_NOTE (MULTISTAGE, "Setting context for stage of type %s [%p]",
- g_type_name (G_OBJECT_TYPE (impl)),
- impl);
-
- backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
- stage_win32 = CLUTTER_STAGE_WIN32 (impl);
-
- /* no GL context to set */
- if (backend_win32->gl_context == NULL)
- return;
-
- /* we might get here inside the final dispose cycle, so we
- * need to handle this gracefully
- */
- if (stage_win32->client_dc == NULL)
- {
- CLUTTER_NOTE (MULTISTAGE,
- "Received a stale stage, clearing all context");
-
- if (backend_win32->dummy_dc != NULL)
- wglMakeCurrent (backend_win32->dummy_dc,
- backend_win32->gl_context);
- else
- wglMakeCurrent (NULL, NULL);
- }
- else
- {
- CLUTTER_NOTE (BACKEND,
- "MakeCurrent window %p (%s), context %p",
- stage_win32->hwnd,
- stage_win32->is_foreign_win ? "foreign" : "native",
- backend_win32->gl_context);
- wglMakeCurrent (stage_win32->client_dc,
- backend_win32->gl_context);
- }
- }
+ cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_win32->onscreen));
}
static ClutterStageWindow *
@@ -558,7 +369,6 @@ clutter_backend_win32_class_init (ClutterBackendWin32Class *klass)
static void
clutter_backend_win32_init (ClutterBackendWin32 *backend_win32)
{
- backend_win32->gl_context = NULL;
backend_win32->invisible_cursor = NULL;
/* FIXME: get from GetSystemMetric?
diff --git a/clutter/win32/clutter-backend-win32.h b/clutter/win32/clutter-backend-win32.h
index 0bcaa8f..bfa74f7 100644
--- a/clutter/win32/clutter-backend-win32.h
+++ b/clutter/win32/clutter-backend-win32.h
@@ -46,10 +46,6 @@ struct _ClutterBackendWin32
{
ClutterBackend parent_instance;
- HGLRC gl_context;
- HWND dummy_hwnd;
- HDC dummy_dc;
-
HCURSOR invisible_cursor;
GSource *event_source;
@@ -76,6 +72,8 @@ clutter_backend_win32_get_features (ClutterBackend *backend);
HCURSOR _clutter_backend_win32_get_invisible_cursor (ClutterBackend *backend);
+G_CONST_RETURN gchar *_clutter_backend_win32_get_vblank (void);
+
G_END_DECLS
#endif /* __CLUTTER_BACKEND_WIN32_H__ */
diff --git a/clutter/win32/clutter-event-win32.c b/clutter/win32/clutter-event-win32.c
index b97a6ab..517ef14 100644
--- a/clutter/win32/clutter-event-win32.c
+++ b/clutter/win32/clutter-event-win32.c
@@ -348,6 +348,7 @@ get_key_modifier_state (const BYTE *key_states)
gboolean
clutter_win32_handle_event (const MSG *msg)
{
+ ClutterBackend *backend;
ClutterBackendWin32 *backend_win32;
ClutterStageWin32 *stage_win32;
ClutterDeviceManager *manager;
@@ -365,6 +366,13 @@ clutter_win32_handle_event (const MSG *msg)
impl = _clutter_stage_get_window (stage);
stage_win32 = CLUTTER_STAGE_WIN32 (impl);
backend_win32 = stage_win32->backend;
+ backend = CLUTTER_BACKEND (backend_win32);
+
+ /* Give Cogl a chance to handle the message first */
+ if (backend->cogl_renderer != NULL &&
+ cogl_renderer_handle_native_event (backend->cogl_renderer,
+ (void *) msg) == COGL_FILTER_REMOVE)
+ return TRUE;
manager = clutter_device_manager_get_default ();
core_pointer =
diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c
index 8eb3567..0cdeae9 100644
--- a/clutter/win32/clutter-stage-win32.c
+++ b/clutter/win32/clutter-stage-win32.c
@@ -392,14 +392,24 @@ static gboolean
clutter_stage_win32_realize (ClutterStageWindow *stage_window)
{
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
+ ClutterBackend *backend;
ClutterBackendWin32 *backend_win32;
- PIXELFORMATDESCRIPTOR pfd;
- int pf;
+ CoglFramebuffer *framebuffer;
+ gfloat width;
+ gfloat height;
GError *error = NULL;
+ const char *clutter_vblank;
CLUTTER_NOTE (MISC, "Realizing main stage");
- backend_win32 = CLUTTER_BACKEND_WIN32 (clutter_get_default_backend ());
+ backend = CLUTTER_BACKEND (stage_win32->backend);
+ backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
+
+ clutter_actor_get_size (CLUTTER_ACTOR (stage_win32->wrapper),
+ &width, &height);
+
+ stage_win32->onscreen = cogl_onscreen_new (backend->cogl_context,
+ width, height);
if (stage_win32->hwnd == NULL)
{
@@ -457,26 +467,29 @@ clutter_stage_win32_realize (ClutterStageWindow *stage_window)
SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) stage_win32);
}
- if (stage_win32->client_dc)
- ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
+ cogl_onscreen_win32_set_foreign_window (stage_win32->onscreen,
+ stage_win32->hwnd);
- stage_win32->client_dc = GetDC (stage_win32->hwnd);
+ clutter_vblank = _clutter_backend_win32_get_vblank ();
+ if (clutter_vblank && strcmp (clutter_vblank, "none") == 0)
+ cogl_onscreen_set_swap_throttled (stage_win32->onscreen, FALSE);
- /* Create a context. This will be a no-op if we already have one */
- if (!_clutter_backend_create_context (CLUTTER_BACKEND (backend_win32),
- &error))
+ framebuffer = COGL_FRAMEBUFFER (stage_win32->onscreen);
+ if (!cogl_framebuffer_allocate (framebuffer, &error))
{
- g_critical ("Unable to realize stage: %s", error->message);
+ g_warning ("Failed to allocate stage: %s", error->message);
g_error_free (error);
+ cogl_object_unref (stage_win32->onscreen);
+ stage_win32->onscreen = NULL;
goto fail;
}
- /* Use the same pixel format as the dummy DC */
- pf = GetPixelFormat (backend_win32->dummy_dc);
- DescribePixelFormat (backend_win32->dummy_dc, pf, sizeof (pfd), &pfd);
- if (!SetPixelFormat (stage_win32->client_dc, pf, &pfd))
+ /* Create a context. This will be a no-op if we already have one */
+ if (!_clutter_backend_create_context (CLUTTER_BACKEND (backend_win32),
+ &error))
{
- g_critical ("Unable to find suitable GL pixel format");
+ g_critical ("Unable to realize stage: %s", error->message);
+ g_error_free (error);
goto fail;
}
@@ -491,12 +504,6 @@ clutter_stage_win32_realize (ClutterStageWindow *stage_window)
static void
clutter_stage_win32_unprepare_window (ClutterStageWin32 *stage_win32)
{
- if (stage_win32->client_dc)
- {
- ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
- stage_win32->client_dc = NULL;
- }
-
if (!stage_win32->is_foreign_win && stage_win32->hwnd)
{
/* Drop the pointer to this stage in the window so that any
@@ -527,8 +534,8 @@ clutter_stage_win32_redraw (ClutterStageWindow *stage_window)
_clutter_stage_do_paint (stage_win32->wrapper, NULL);
cogl_flush ();
- if (stage_win32->client_dc)
- SwapBuffers (stage_win32->client_dc);
+ if (stage_win32->onscreen)
+ cogl_framebuffer_swap_buffers (COGL_FRAMEBUFFER (stage_win32->onscreen));
}
static void
@@ -543,7 +550,10 @@ clutter_stage_win32_dispose (GObject *gobject)
clutter_stage_win32_unprepare_window (stage_win32);
if (stage_win32->wtitle)
- g_free (stage_win32->wtitle);
+ {
+ g_free (stage_win32->wtitle);
+ stage_win32->wtitle = NULL;
+ }
G_OBJECT_CLASS (clutter_stage_win32_parent_class)->dispose (gobject);
}
@@ -560,7 +570,6 @@ static void
clutter_stage_win32_init (ClutterStageWin32 *stage)
{
stage->hwnd = NULL;
- stage->client_dc = NULL;
stage->win_width = 640;
stage->win_height = 480;
stage->backend = NULL;
diff --git a/clutter/win32/clutter-stage-win32.h b/clutter/win32/clutter-stage-win32.h
index ac330f8..2418936 100644
--- a/clutter/win32/clutter-stage-win32.h
+++ b/clutter/win32/clutter-stage-win32.h
@@ -44,8 +44,9 @@ struct _ClutterStageWin32
{
ClutterGroup parent_instance;
+ CoglOnscreen *onscreen;
+
HWND hwnd;
- HDC client_dc;
gint win_width;
gint win_height;
gint scroll_pos;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]