From aa1246e8917f0977bd03b97c206d4c2a01ff8599 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 13 May 2009 22:21:48 +0100 Subject: [PATCH] [backend] Abstract the GL context creation This is the another step into abstracting the backend operations that are currently spread all across the board back into the backend implementations where they belong. The GL context creation, for instance, is demanded to the stage realization which makes it a critical path for every operation that is GL-context bound. This usually does not make any difference since we realize the default stage, but at some point we might start looking into avoiding the default stage realization in order to make the Clutter startup faster. It also makes the code maintainable because every part is self contained and can be reworked with the minimum amount of pain. --- clutter/clutter-backend.c | 16 +++++++ clutter/clutter-backend.h | 3 ++ clutter/clutter-private.h | 3 ++ clutter/glx/clutter-backend-glx.c | 54 +++++++++++++++++++++- clutter/glx/clutter-stage-glx.c | 76 ++++++++++++++----------------- 5 files changed, 110 insertions(+), 42 deletions(-) diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index d827719bc..e423edb21 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -300,6 +300,22 @@ _clutter_backend_redraw (ClutterBackend *backend, klass->redraw (backend, stage); } +gboolean +_clutter_backend_create_context (ClutterBackend *backend, + gboolean is_offscreen, + GError **error) +{ + ClutterBackendClass *klass; + + g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE); + + klass = CLUTTER_BACKEND_GET_CLASS (backend); + if (klass->create_context) + return klass->create_context (backend, is_offscreen, error); + + return TRUE; +} + void _clutter_backend_ensure_context (ClutterBackend *backend, ClutterStage *stage) diff --git a/clutter/clutter-backend.h b/clutter/clutter-backend.h index 12f138af7..6529100c4 100644 --- a/clutter/clutter-backend.h +++ b/clutter/clutter-backend.h @@ -77,6 +77,9 @@ struct _ClutterBackendClass ClutterFeatureFlags (* get_features) (ClutterBackend *backend); void (* redraw) (ClutterBackend *backend, ClutterStage *stage); + gboolean (* create_context) (ClutterBackend *backend, + gboolean is_offscreen, + GError **error); void (* ensure_context) (ClutterBackend *backend, ClutterStage *stage); diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 30870ee62..fe0c9b39a 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -184,6 +184,9 @@ ClutterActor *_clutter_backend_create_stage (ClutterBackend *backend, GError **error); void _clutter_backend_ensure_context (ClutterBackend *backend, ClutterStage *stage); +gboolean _clutter_backend_create_context (ClutterBackend *backend, + gboolean is_offscreen, + GError **error); void _clutter_backend_add_options (ClutterBackend *backend, GOptionGroup *group); diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index c255aeacc..edad15894 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -354,6 +354,57 @@ clutter_backend_glx_get_features (ClutterBackend *backend) return flags; } +static gboolean +clutter_backend_glx_create_context (ClutterBackend *backend, + gboolean is_offscreen, + GError **error) +{ + ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend); + ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); + + if (backend_glx->gl_context == None) + { + XVisualInfo *xvisinfo; + + xvisinfo = + clutter_backend_x11_get_visual_info (backend_x11, is_offscreen); + + CLUTTER_NOTE (GL, "Creating GL Context (display: %p, %s)", + backend_x11->xdpy, + is_offscreen ? "offscreen" : "onscreen"); + + backend_glx->gl_context = glXCreateContext (backend_x11->xdpy, + xvisinfo, + 0, + is_offscreen ? False : True); + + XFree (xvisinfo); + + if (backend_glx->gl_context == None) + { + g_set_error (error, CLUTTER_INIT_ERROR, + CLUTTER_INIT_ERROR_BACKEND, + "Unable to create suitable %s GL context", + is_offscreen ? "offscreen" : "onscreen"); + return FALSE; + } + + if (!is_offscreen) + { + gboolean is_direct; + + is_direct = glXIsDirect (backend_x11->xdpy, + backend_glx->gl_context); + + CLUTTER_NOTE (GL, "Setting %s context", + is_direct ? "direct" : "indirect"); + _cogl_set_indirect_context (!is_direct); + } + } + + return TRUE; +} + static void clutter_backend_glx_ensure_context (ClutterBackend *backend, ClutterStage *stage) @@ -469,7 +520,7 @@ clutter_backend_glx_redraw (ClutterBackend *backend, } } -static ClutterActor* +static ClutterActor * clutter_backend_glx_create_stage (ClutterBackend *backend, ClutterStage *wrapper, GError **error) @@ -563,6 +614,7 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass) backend_class->add_options = clutter_backend_glx_add_options; backend_class->get_features = clutter_backend_glx_get_features; backend_class->redraw = clutter_backend_glx_redraw; + backend_class->create_context = clutter_backend_glx_create_context; backend_class->ensure_context = clutter_backend_glx_ensure_context; backendx11_class->get_visual_info = clutter_backend_glx_get_visual_info; diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index fb47ae9da..7e139e777 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -97,6 +97,12 @@ clutter_stage_glx_unrealize (ClutterActor *actor) stage_x11->xwin = None; } + if (stage_x11->xvisinfo != None) + { + XFree (stage_x11->xvisinfo); + stage_x11->xvisinfo = None; + } + XSync (stage_x11->xdpy, False); clutter_x11_untrap_x_errors (); @@ -109,6 +115,7 @@ clutter_stage_glx_realize (ClutterActor *actor) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); + ClutterBackend *backend; ClutterBackendGLX *backend_glx; ClutterBackendX11 *backend_x11; gboolean is_offscreen; @@ -119,19 +126,17 @@ clutter_stage_glx_realize (ClutterActor *actor) g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL); - backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ()); - backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); + backend = clutter_get_default_backend (); + backend_glx = CLUTTER_BACKEND_GLX (backend); + backend_x11 = CLUTTER_BACKEND_X11 (backend); if (G_LIKELY (!is_offscreen)) { - if (stage_x11->xvisinfo != None) - { - XFree (stage_x11->xvisinfo); - stage_x11->xvisinfo = None; - } + GError *error; stage_x11->xvisinfo = clutter_backend_x11_get_visual_info (backend_x11, FALSE); + if (stage_x11->xvisinfo == None) { g_critical ("Unable to find suitable GL visual."); @@ -197,22 +202,14 @@ clutter_stage_glx_realize (ClutterActor *actor) clutter_stage_x11_fix_window_size (stage_x11); clutter_stage_x11_set_wm_protocols (stage_x11); - if (G_UNLIKELY (backend_glx->gl_context == None)) + /* ask for a context; a no-op, if a context already exists */ + error = NULL; + _clutter_backend_create_context (backend, FALSE, &error); + if (error) { - CLUTTER_NOTE (GL, "Creating GL Context"); - backend_glx->gl_context = glXCreateContext (stage_x11->xdpy, - stage_x11->xvisinfo, - 0, - True); - - if (backend_glx->gl_context == None) - { - g_critical ("Unable to create suitable GL context."); - goto fail; - } - - _cogl_set_indirect_context (!glXIsDirect (stage_x11->xdpy, - backend_glx->gl_context)); + g_critical ("Unable to realize stage: %s", error->message); + g_error_free (error); + goto fail; } CLUTTER_NOTE (BACKEND, "Marking stage as realized"); @@ -220,6 +217,8 @@ clutter_stage_glx_realize (ClutterActor *actor) } else { + GError *error; + if (stage_x11->xvisinfo != None) { XFree (stage_x11->xvisinfo); @@ -228,13 +227,13 @@ clutter_stage_glx_realize (ClutterActor *actor) stage_x11->xvisinfo = clutter_backend_x11_get_visual_info (backend_x11, TRUE); + if (stage_x11->xvisinfo == None) { g_critical ("Unable to find suitable GL visual."); goto fail; } - stage_x11->xpixmap = XCreatePixmap (stage_x11->xdpy, stage_x11->xwin_root, stage_x11->xwin_width, @@ -246,25 +245,20 @@ clutter_stage_glx_realize (ClutterActor *actor) stage_x11->xvisinfo, stage_x11->xpixmap); - if (backend_glx->gl_context == None) + /* ask for a context; a no-op, if a context already exists + * + * FIXME: we probably need a seperate offscreen context here + * - though it likely makes most sense to drop offscreen stages + * and rely on FBO's instead and GLXPixmaps seems mostly broken + * anyway.. + */ + error = NULL; + _clutter_backend_create_context (backend, TRUE, &error); + if (error) { - CLUTTER_NOTE (GL, "Creating GL Context"); - - /* FIXME: we probably need a seperate offscreen context here - * - though it likely makes most sense to drop offscreen stages - * and rely on FBO's instead and GLXPixmaps seems mostly broken - * anyway.. - */ - backend_glx->gl_context = glXCreateContext (stage_x11->xdpy, - stage_x11->xvisinfo, - 0, - False); - - if (backend_glx->gl_context == None) - { - g_critical ("Unable to create suitable GL context."); - goto fail; - } + g_critical ("Unable to realize stage: %s", error->message); + g_error_free (error); + goto fail; } CLUTTER_NOTE (BACKEND, "Marking stage as realized");