diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index ca4fd3c26..3e70e255c 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -323,12 +323,20 @@ _clutter_backend_create_context (ClutterBackend *backend, return TRUE; } +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 diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 4fdffee37..db9a6d2d0 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -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); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 7a84cd447..305733878 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -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); diff --git a/clutter/cogl/cogl/cogl.c b/clutter/cogl/cogl/cogl.c index b4ce48718..ff5f67963 100644 --- a/clutter/cogl/cogl/cogl.c +++ b/clutter/cogl/cogl/cogl.c @@ -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"); +} diff --git a/clutter/cogl/cogl/cogl.h.in b/clutter/cogl/cogl/cogl.h.in index 69e653325..5fb5df0ce 100644 --- a/clutter/cogl/cogl/cogl.h.in +++ b/clutter/cogl/cogl/cogl.h.in @@ -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); diff --git a/clutter/cogl/cogl/driver/gl/cogl.c b/clutter/cogl/cogl/driver/gl/cogl.c index e81ec377c..9403b94e3 100644 --- a/clutter/cogl/cogl/driver/gl/cogl.c +++ b/clutter/cogl/cogl/driver/gl/cogl.c @@ -32,6 +32,11 @@ #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; } - diff --git a/clutter/cogl/cogl/driver/gles/cogl.c b/clutter/cogl/cogl/driver/gles/cogl.c index 565ff0fa7..c17736f58 100644 --- a/clutter/cogl/cogl/driver/gles/cogl.c +++ b/clutter/cogl/cogl/driver/gles/cogl.c @@ -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)