[backend] Abstract the GL context creation
authorEmmanuele Bassi <ebassi@linux.intel.com>
Wed, 13 May 2009 21:21:48 +0000 (22:21 +0100)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Wed, 13 May 2009 21:21:48 +0000 (22:21 +0100)
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
clutter/clutter-backend.h
clutter/clutter-private.h
clutter/glx/clutter-backend-glx.c
clutter/glx/clutter-stage-glx.c

index d827719..e423edb 100644 (file)
@@ -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)
index 12f138a..6529100 100644 (file)
@@ -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);
 
index 30870ee..fe0c9b3 100644 (file)
@@ -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);
index c255aea..edad158 100644 (file)
@@ -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;
index fb47ae9..7e139e7 100644 (file)
@@ -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");