Validate that the GL version is >= 1.2
authorNeil Roberts <neil@linux.intel.com>
Wed, 11 Nov 2009 13:26:54 +0000 (13:26 +0000)
committerNeil Roberts <neil@linux.intel.com>
Fri, 13 Nov 2009 15:55:48 +0000 (15:55 +0000)
There is a new internal Cogl function called _cogl_check_driver_valid
which looks at the value of the GL_VERSION string to determine whether
the driver is supported. Clutter now calls this after the stage is
realized. If it fails then the stage is marked as unrealized and a
warning is shown.

_cogl_features_init now also checks the version number before getting
the function pointers for glBlendFuncSeparate and
glBlendEquationSeparate. It is not safe to just check for the presence
of the functions because some drivers may define the function without
fully implementing the spec.

The GLES version of _cogl_check_driver_valid just always returns TRUE
because there are no version requirements yet.

Eventually the function could also check for mandatory extensions if
there were any.

http://bugzilla.openedhand.com/show_bug.cgi?id=1875

clutter/clutter-backend.c
clutter/clutter-private.h
clutter/clutter-stage.c
clutter/cogl/cogl/cogl.c
clutter/cogl/cogl/cogl.h.in
clutter/cogl/cogl/driver/gl/cogl.c
clutter/cogl/cogl/driver/gles/cogl.c

index ca4fd3c..3e70e25 100644 (file)
@@ -324,11 +324,19 @@ _clutter_backend_create_context (ClutterBackend  *backend,
 }
 
 void
+_clutter_backend_ensure_context_internal (ClutterBackend  *backend,
+                                          ClutterStage    *stage)
+{
+  ClutterBackendClass *klass = CLUTTER_BACKEND_GET_CLASS (backend);
+  if (G_LIKELY (klass->ensure_context))
+    klass->ensure_context (backend, stage);
+}
+
+void
 _clutter_backend_ensure_context (ClutterBackend *backend,
                                  ClutterStage   *stage)
 {
   static ClutterStage *current_context_stage = NULL;
-  ClutterBackendClass *klass;
 
   g_return_if_fail (CLUTTER_IS_BACKEND (backend));
   g_return_if_fail (CLUTTER_IS_STAGE (stage));
@@ -354,9 +362,7 @@ _clutter_backend_ensure_context (ClutterBackend *backend,
                         new_stage);
         }
 
-      klass = CLUTTER_BACKEND_GET_CLASS (backend);
-      if (G_LIKELY (klass->ensure_context))
-        klass->ensure_context (backend, new_stage);
+      _clutter_backend_ensure_context_internal (backend, new_stage);
 
       /* XXX: Until Cogl becomes fully responsible for backend windows
        * Clutter need to manually keep it informed of the current window size
index 4fdffee..db9a6d2 100644 (file)
@@ -193,6 +193,9 @@ ClutterStageWindow *_clutter_backend_create_stage   (ClutterBackend  *backend,
                                                GError         **error);
 void          _clutter_backend_ensure_context (ClutterBackend  *backend,
                                                ClutterStage    *stage);
+void          _clutter_backend_ensure_context_internal
+                                              (ClutterBackend  *backend,
+                                               ClutterStage    *stage);
 gboolean      _clutter_backend_create_context (ClutterBackend  *backend,
                                                GError         **error);
 
index 7a84cd4..3057338 100644 (file)
@@ -310,8 +310,26 @@ clutter_stage_realize (ClutterActor *self)
    */
   if (is_realized)
     {
-      CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
-      clutter_stage_ensure_current (CLUTTER_STAGE (self));
+      GError *error = NULL;
+      ClutterBackend *backend = clutter_get_default_backend ();
+
+      /* We want to select the context without calling
+         clutter_backend_ensure_context so that it doesn't call any
+         Cogl functions. Otherwise it would create the Cogl context
+         before we get a chance to check whether the GL version is
+         valid */
+      _clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self));
+
+      /* Make sure Cogl can support the driver */
+      if (!_cogl_check_driver_valid (&error))
+        {
+          g_warning ("The GL driver is not supported: %s",
+                     error->message);
+          g_clear_error (&error);
+          CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
+        }
+      else
+        CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
     }
   else
     CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
index b4ce487..ff5f679 100644 (file)
@@ -942,3 +942,8 @@ _cogl_get_clip_state (void)
   return _cogl_draw_buffer_get_clip_state (draw_buffer);
 }
 
+GQuark
+_cogl_driver_error_quark (void)
+{
+  return g_quark_from_static_string ("cogl-driver-error-quark");
+}
index 69e6533..5fb5df0 100644 (file)
@@ -969,8 +969,17 @@ void            cogl_flush_gl_state         (int      flags);
 #endif
 
 /* private */
+#define COGL_DRIVER_ERROR (_cogl_driver_error_quark ())
+
+typedef enum { /*< prefix=COGL_DRIVER_ERROR >*/
+  COGL_DRIVER_ERROR_UNKNOWN_VERSION,
+  COGL_DRIVER_ERROR_INVALID_VERSION
+} CoglDriverError;
+
 void            _cogl_set_indirect_context  (gboolean indirect);
 void            _cogl_set_viewport (int x, int y, int width, int height);
+gboolean        _cogl_check_driver_valid (GError **error);
+GQuark          _cogl_driver_error_quark (void);
 
 void
 _cogl_onscreen_clutter_backend_set_size (int width, int height);
index e81ec37..9403b94 100644 (file)
 #include "cogl-internal.h"
 #include "cogl-context.h"
 
+#define COGL_CHECK_GL_VERSION(driver_major, driver_minor, \
+                              target_major, target_minor) \
+  ((driver_major) > (target_major) || \
+   ((driver_major) == (target_major) && (driver_minor) >= (target_minor)))
+
 typedef struct _CoglGLSymbolTableEntry
 {
   const char *name;
@@ -109,6 +114,70 @@ really_enable_npot (void)
 }
 #endif
 
+static gboolean
+_cogl_get_gl_version (int *major_out, int *minor_out)
+{
+  const char *version_string, *major_end, *minor_end;
+  int major = 0, minor = 0;
+
+  /* Get the OpenGL version number */
+  if ((version_string = (const char *) glGetString (GL_VERSION)) == NULL)
+    return FALSE;
+
+  /* Extract the major number */
+  for (major_end = version_string; *major_end >= '0'
+        && *major_end <= '9'; major_end++)
+    major = (major * 10) + *major_end - '0';
+  /* If there were no digits or the major number isn't followed by a
+     dot then it is invalid */
+  if (major_end == version_string || *major_end != '.')
+    return FALSE;
+
+  /* Extract the minor number */
+  for (minor_end = major_end + 1; *minor_end >= '0'
+        && *minor_end <= '9'; minor_end++)
+    minor = (minor * 10) + *minor_end - '0';
+  /* If there were no digits or there is an unexpected character then
+     it is invalid */
+  if (minor_end == major_end + 1
+      || (*minor_end && *minor_end != ' ' && *minor_end != '.'))
+    return FALSE;
+
+  *major_out = major;
+  *minor_out = minor;
+
+  return TRUE;
+}
+
+gboolean
+_cogl_check_driver_valid (GError **error)
+{
+  int major, minor;
+
+  if (!_cogl_get_gl_version (&major, &minor))
+    {
+      g_set_error (error,
+                   COGL_DRIVER_ERROR,
+                   COGL_DRIVER_ERROR_UNKNOWN_VERSION,
+                   "The OpenGL version could not be determined");
+      return FALSE;
+    }
+
+  /* OpenGL 1.2 is required */
+  if (!COGL_CHECK_GL_VERSION (major, minor, 1, 2))
+    {
+      g_set_error (error,
+                   COGL_DRIVER_ERROR,
+                   COGL_DRIVER_ERROR_INVALID_VERSION,
+                   "The OpenGL version of your driver (%i.%i) "
+                   "is not compatible with Cogl",
+                   major, minor);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
 void
 _cogl_features_init (void)
 {
@@ -119,9 +188,12 @@ _cogl_features_init (void)
   gboolean          fbo_ARB = FALSE;
   gboolean          fbo_EXT = FALSE;
   const char       *suffix;
+  int               gl_major = 0, gl_minor = 0;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  _cogl_get_gl_version (&gl_major, &gl_minor);
+
   flags = COGL_FEATURE_TEXTURE_READ_PIXELS;
 
   gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS);
@@ -427,17 +499,18 @@ _cogl_features_init (void)
          cogl_get_proc_address ("glBlendColor");
 
   /* Available in 1.4 */
-  ctx->drv.pf_glBlendFuncSeparate =
-        (COGL_PFNGLBLENDFUNCSEPARATEPROC)
-        cogl_get_proc_address ("glBlendFuncSeparate");
+  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4))
+    ctx->drv.pf_glBlendFuncSeparate =
+      (COGL_PFNGLBLENDFUNCSEPARATEPROC)
+      cogl_get_proc_address ("glBlendFuncSeparate");
 
   /* Available in 2.0 */
-  ctx->drv.pf_glBlendEquationSeparate =
-        (COGL_PFNGLBLENDEQUATIONSEPARATEPROC)
-        cogl_get_proc_address ("glBlendEquationSeparate");
+  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0))
+    ctx->drv.pf_glBlendEquationSeparate =
+      (COGL_PFNGLBLENDEQUATIONSEPARATEPROC)
+      cogl_get_proc_address ("glBlendEquationSeparate");
 
   /* Cache features */
   ctx->feature_flags = flags;
   ctx->features_cached = TRUE;
 }
-
index 565ff0f..c17736f 100644 (file)
@@ -82,6 +82,12 @@ _cogl_resolve_gl_symbols (CoglGLSymbolTableEntry *symbol_table,
   return status;
 }
 
+gboolean
+_cogl_check_driver_valid (GError **error)
+{
+  /* The GLES backend doesn't have any particular version requirements */
+  return TRUE;
+}
 
 void
 _cogl_features_init (void)