[cogl/cogl-1.14: 37/174] Add a GL 3 driver



commit 2616ae0fa9e0e3a0ab43698cb8434facaabad254
Author: Neil Roberts <neil linux intel com>
Date:   Wed Sep 26 20:32:36 2012 +0100

    Add a GL 3 driver
    
    This adds a new CoglDriver for GL 3 called COGL_DRIVER_GL3. When
    requested, the GLX, EGL and SDL2 winsyss will set the necessary
    attributes to request a forward-compatible core profile 3.1 context.
    That means it will have no deprecated features.
    
    To simplify the explosion of checks for specific combinations of
    context->driver, many of these conditionals have now been replaced
    with private feature flags that are checked instead. The GL and GLES
    drivers now initialise these private feature flags depending on which
    driver is used.
    
    The fixed function backends now explicitly check whether the fixed
    function private feature is available which means the GL3 driver will
    fall back to always using the GLSL progend. Since Rob's latest patches
    the GLSL progend no longer uses any fixed function API anyway so it
    should just work.
    
    The driver is currently lower priority than COGL_DRIVER_GL so it will
    not be used unless it is specificly requested. We may want to change
    this priority at some point because apparently Mesa can make some
    memory savings if a core profile context is used.
    
    In GL 3, getting the combined extensions string with glGetString is
    deprecated so this patch changes it to use glGetStringi to build up an
    array of extensions instead. _cogl_context_get_gl_extensions now
    returns this array instead of trying to return a const string. The
    caller is expected to free the array.
    
    Some issues with this patch:
    
    â GL 3 does not support GL_ALPHA format textures. We should probably
      make this a feature flag or something. Cogl uses this to render text
      which currently just throws a GL error and breaks so it's pretty
      important to do something about this before considering the GL3
      driver to be stable.
    
    â GL 3 doesn't support client side vertex buffers. This probably
      doesn't matter because CoglBuffer won't normally use malloc'd
      buffers if VBOs are available, but it might but worth making
      malloc'd buffers a private feature and forcing it not to use them.
    
    â GL 3 doesn't support the default vertex array object. This patch
      just makes it create and bind a single non-default vertex array
      object which gets used just like the normal default object. Ideally
      it would be good to use vertex array objects properly and attach
      them to a CoglPrimitive to cache the state.
    
    Reviewed-by: Robert Bragg <robert linux intel com>
    
    (cherry picked from commit 66c9db993595b3a22e63f4c201ea468bc9b88cb6)

 cogl-pango/cogl-pango-display-list.c               |    2 +-
 cogl/cogl-blend-string.c                           |   35 ++----
 cogl/cogl-clutter.c                                |   22 ++++-
 cogl/cogl-context-private.h                        |   10 ++-
 cogl/cogl-context.c                                |  118 +++++++++++---------
 cogl/cogl-feature-private.c                        |   10 +-
 cogl/cogl-feature-private.h                        |    4 +-
 cogl/cogl-framebuffer.c                            |    6 +-
 cogl/cogl-internal.h                               |   15 ++-
 cogl/cogl-journal.c                                |    4 +-
 cogl/cogl-matrix-stack.c                           |    6 +-
 cogl/cogl-pipeline-state.c                         |    2 +-
 cogl/cogl-pipeline.c                               |    8 +-
 cogl/cogl-private.h                                |    2 +-
 cogl/cogl-renderer.c                               |   13 ++-
 cogl/cogl-renderer.h                               |    2 +
 cogl/cogl-shader.c                                 |    3 +-
 cogl/cogl-texture.c                                |    2 +-
 cogl/cogl.c                                        |   28 ++----
 cogl/driver/gl/cogl-attribute-gl.c                 |    8 +-
 cogl/driver/gl/cogl-clip-stack-gl.c                |    1 +
 cogl/driver/gl/cogl-framebuffer-gl.c               |    4 +-
 cogl/driver/gl/cogl-pipeline-fragend-glsl.c        |   17 ++--
 cogl/driver/gl/cogl-pipeline-opengl.c              |    9 +-
 cogl/driver/gl/cogl-pipeline-progend-fixed.c       |    2 +-
 cogl/driver/gl/cogl-pipeline-vertend-glsl.c        |    6 +-
 cogl/driver/gl/cogl-texture-2d-gl.c                |    3 +-
 cogl/driver/gl/gl/cogl-driver-gl.c                 |   73 +++++++++----
 .../gl/gl/cogl-pipeline-progend-fixed-arbfp.c      |    2 +-
 cogl/driver/gl/gles/cogl-driver-gles.c             |   44 +++++---
 cogl/gl-prototypes/cogl-all-functions.h            |   26 ++++-
 cogl/gl-prototypes/cogl-in-gles-core-functions.h   |    6 +-
 cogl/gl-prototypes/cogl-in-gles2-core-functions.h  |    8 +-
 cogl/winsys/cogl-winsys-egl-feature-functions.h    |    7 +
 cogl/winsys/cogl-winsys-egl-private.h              |    3 +-
 cogl/winsys/cogl-winsys-egl.c                      |   61 +++++++---
 cogl/winsys/cogl-winsys-glx-feature-functions.h    |   14 +++
 cogl/winsys/cogl-winsys-glx.c                      |   56 ++++++++--
 cogl/winsys/cogl-winsys-sdl.c                      |    6 +
 cogl/winsys/cogl-winsys-sdl2.c                     |   26 +++++
 cogl/winsys/cogl-winsys-wgl.c                      |   17 ++-
 tests/conform/run-tests.sh                         |   11 ++-
 tests/conform/test-utils.c                         |    3 +-
 43 files changed, 477 insertions(+), 228 deletions(-)
---
diff --git a/cogl-pango/cogl-pango-display-list.c b/cogl-pango/cogl-pango-display-list.c
index eda3c07..bc781f9 100644
--- a/cogl-pango/cogl-pango-display-list.c
+++ b/cogl-pango/cogl-pango-display-list.c
@@ -342,7 +342,7 @@ emit_vertex_buffer_geometry (CoglPangoDisplayListNode *node)
                                                  2 /* n_attributes */);
 
 #ifdef CLUTTER_COGL_HAS_GL
-      if (ctx->driver == COGL_DRIVER_GL)
+      if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_QUADS))
         cogl_primitive_set_mode (prim, GL_QUADS);
       else
 #endif
diff --git a/cogl/cogl-blend-string.c b/cogl/cogl-blend-string.c
index a0f10a5..4313ab9 100644
--- a/cogl/cogl-blend-string.c
+++ b/cogl/cogl-blend-string.c
@@ -216,30 +216,14 @@ validate_blend_statements (CoglBlendStringStatement *statements,
 
   _COGL_GET_CONTEXT (ctx, 0);
 
-  if (ctx->driver == COGL_DRIVER_GL)
+  if (n_statements == 2 &&
+      !ctx->glBlendEquationSeparate &&
+      statements[0].function->type != statements[1].function->type)
     {
-      if (n_statements == 2)
-        {
-          /* glBlendEquationSeperate is GL 2.0 only */
-          if (!ctx->glBlendEquationSeparate &&
-              statements[0].function->type != statements[1].function->type)
-            {
-              error_string = "Separate blend functions for the RGB an A "
-                "channels isn't supported by the driver";
-              detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
-              goto error;
-            }
-        }
-    }
-  else if (ctx->driver == COGL_DRIVER_GLES1)
-    {
-      if (n_statements != 1)
-        {
-          error_string = "Separate blend functions for the RGB an A "
-            "channels isn't supported by the GLES 1";
-          detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
-          goto error;
-        }
+      error_string = "Separate blend functions for the RGB an A "
+        "channels isn't supported by the driver";
+      detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
+      goto error;
     }
 
   for (i = 0; i < n_statements; i++)
@@ -262,12 +246,13 @@ validate_blend_statements (CoglBlendStringStatement *statements,
             goto error;
           }
 
-        if (ctx->driver == COGL_DRIVER_GLES1 &&
+        if (!(ctx->private_feature_flags &
+              COGL_PRIVATE_FEATURE_BLEND_CONSTANT) &&
             arg->factor.is_color &&
             (arg->factor.source.info->type ==
              COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT))
           {
-            error_string = "GLES Doesn't support constant blend factors";
+            error_string = "Driver doesn't support constant blend factors";
             detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
             goto error;
           }
diff --git a/cogl/cogl-clutter.c b/cogl/cogl-clutter.c
index fddff09..b00e510 100644
--- a/cogl/cogl-clutter.c
+++ b/cogl/cogl-clutter.c
@@ -29,6 +29,7 @@
 #endif
 
 #include <glib.h>
+#include <string.h>
 
 #include "cogl-util.h"
 #include "cogl-types.h"
@@ -46,7 +47,26 @@
 CoglBool
 cogl_clutter_check_extension (const char *name, const char *ext)
 {
-  return _cogl_check_extension (name, ext);
+  char *end;
+  int name_len, n;
+
+  if (name == NULL || ext == NULL)
+    return FALSE;
+
+  end = (char*)(ext + strlen(ext));
+
+  name_len = strlen(name);
+
+  while (ext < end)
+    {
+      n = strcspn(ext, " ");
+
+      if ((name_len == n) && (!strncmp(name, ext, n)))
+	return TRUE;
+      ext += (n + 1);
+    }
+
+  return FALSE;
 }
 
 CoglBool
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index a28fe4f..7321455 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -356,7 +356,15 @@ void
 _cogl_context_set_current_modelview_entry (CoglContext *context,
                                            CoglMatrixEntry *entry);
 
-const char *
+/*
+ * _cogl_context_get_gl_extensions:
+ * @context: A CoglContext
+ *
+ * Return value: a NULL-terminated array of strings representing the
+ *   supported extensions by the current driver. This array is owned
+ *   by the caller and should be freed with g_strfreev().
+ */
+char **
 _cogl_context_get_gl_extensions (CoglContext *context);
 
 const char *
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 549569a..8bf4430 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -261,9 +261,7 @@ cogl_context_new (CoglDisplay *display,
   context->texture_units =
     g_array_new (FALSE, FALSE, sizeof (CoglTextureUnit));
 
-  if (context->driver == COGL_DRIVER_GL ||
-      context->driver == COGL_DRIVER_GLES1 ||
-      context->driver == COGL_DRIVER_GLES2)
+  if ((context->private_feature_flags & COGL_PRIVATE_FEATURE_ANY_GL))
     {
       /* See cogl-pipeline.c for more details about why we leave texture unit 1
        * active by default... */
@@ -368,8 +366,7 @@ cogl_context_new (CoglDisplay *display,
   context->blit_texture_pipeline = NULL;
 
 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
-  if (context->driver == COGL_DRIVER_GL ||
-      context->driver == COGL_DRIVER_GLES1)
+  if ((context->private_feature_flags & COGL_PRIVATE_FEATURE_ALPHA_TEST))
     /* The default for GL_ALPHA_TEST is to always pass which is equivalent to
      * the test being disabled therefore we assume that for all drivers there
      * will be no performance impact if we always leave the test enabled which
@@ -379,6 +376,22 @@ cogl_context_new (CoglDisplay *display,
     GE (context, glEnable (GL_ALPHA_TEST));
 #endif
 
+#if defined (HAVE_COGL_GL)
+  if ((context->driver == COGL_DRIVER_GL3))
+    {
+      GLuint vertex_array;
+
+      /* In a forward compatible context, GL 3 doesn't support rendering
+       * using the default vertex array object. Cogl doesn't use vertex
+       * array objects yet so for now we just create a dummy array
+       * object that we will use as our own default object. Eventually
+       * it could be good to attach the vertex array objects to
+       * CoglPrimitives */
+      context->glGenVertexArrays (1, &vertex_array);
+      context->glBindVertexArray (vertex_array);
+    }
+#endif
+
   context->current_modelview_entry = NULL;
   context->current_projection_entry = NULL;
   _cogl_matrix_entry_identity_init (&context->identity_entry);
@@ -430,13 +443,13 @@ cogl_context_new (CoglDisplay *display,
   context->buffer_map_fallback_in_use = FALSE;
 
   /* As far as I can tell, GL_POINT_SPRITE doesn't have any effect
-     unless GL_COORD_REPLACE is enabled for an individual
-     layer. Therefore it seems like it should be ok to just leave it
-     enabled all the time instead of having to have a set property on
-     each pipeline to track whether any layers have point sprite
-     coords enabled. We don't need to do this for GLES2 because point
+     unless GL_COORD_REPLACE is enabled for an individual layer.
+     Therefore it seems like it should be ok to just leave it enabled
+     all the time instead of having to have a set property on each
+     pipeline to track whether any layers have point sprite coords
+     enabled. We don't need to do this for GL3 or GLES2 because point
      sprites are handled using a builtin varying in the shader. */
-  if (context->driver != COGL_DRIVER_GLES2 &&
+  if ((context->private_feature_flags & COGL_PRIVATE_FEATURE_FIXED_FUNCTION) &&
       cogl_has_feature (context, COGL_FEATURE_ID_POINT_SPRITE))
     GE (context, glEnable (GL_POINT_SPRITE));
 
@@ -610,38 +623,45 @@ _cogl_context_set_current_modelview_entry (CoglContext *context,
   context->current_modelview_entry = entry;
 }
 
-const char *
+char **
 _cogl_context_get_gl_extensions (CoglContext *context)
 {
   const char *env_disabled_extensions;
+  char **ret;
 
-  if ((env_disabled_extensions = g_getenv ("COGL_DISABLE_GL_EXTENSIONS"))
-      || _cogl_config_disable_gl_extensions)
+  /* In GL 3, querying GL_EXTENSIONS is deprecated so we have to build
+   * the array using glGetStringi instead */
+  if (context->driver == COGL_DRIVER_GL3)
     {
-      static CoglUserDataKey extensions_key;
-      const char *enabled_extensions;
-      char **split_enabled_extensions;
-      char **split_env_disabled_extensions;
-      char **split_conf_disabled_extensions;
-      char **e;
-      GString *result;
+      int num_extensions, i;
 
-      /* We need to return a const string so we'll attach the results
-       * to the CoglContext to avoid leaking the generated string.
-       * This string is only used rarely so we are using
-       * cogl_object_set_user_data instead of adding an explicit
-       * member to CoglContext to avoid making the struct bigger */
+      context->glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions);
 
-      enabled_extensions =
-        cogl_object_get_user_data (COGL_OBJECT (context), &extensions_key);
-      if (enabled_extensions)
-        return enabled_extensions;
+      ret = g_malloc (sizeof (char *) * (num_extensions + 1));
+
+      for (i = 0; i < num_extensions; i++)
+        {
+          const char *ext =
+            (const char *) context->glGetStringi (GL_EXTENSIONS, i);
+          ret[i] = g_strdup (ext);
+        }
+
+      ret[num_extensions] = NULL;
+    }
+  else
+    {
+      const char *all_extensions =
+        (const char *) context->glGetString (GL_EXTENSIONS);
 
-      enabled_extensions = (const char *) context->glGetString (GL_EXTENSIONS);
+      ret = g_strsplit (all_extensions, " ", 0 /* max tokens */);
+    }
 
-      split_enabled_extensions = g_strsplit (enabled_extensions,
-                                             " ",
-                                             0 /* no max tokens */);
+  if ((env_disabled_extensions = g_getenv ("COGL_DISABLE_GL_EXTENSIONS"))
+      || _cogl_config_disable_gl_extensions)
+    {
+      char **split_env_disabled_extensions;
+      char **split_conf_disabled_extensions;
+      char **src, **dst;
 
       if (env_disabled_extensions)
         split_env_disabled_extensions =
@@ -659,46 +679,38 @@ _cogl_context_get_gl_extensions (CoglContext *context)
       else
         split_conf_disabled_extensions = NULL;
 
-      result = g_string_new (NULL);
-
-      for (e = split_enabled_extensions; *e; e++)
+      for (dst = ret, src = ret;
+           *src;
+           src++)
         {
           char **d;
 
           if (split_env_disabled_extensions)
             for (d = split_env_disabled_extensions; *d; d++)
-              if (!strcmp (*e, *d))
+              if (!strcmp (*src, *d))
                 goto disabled;
           if (split_conf_disabled_extensions)
             for (d = split_conf_disabled_extensions; *d; d++)
-              if (!strcmp (*e, *d))
+              if (!strcmp (*src, *d))
                 goto disabled;
 
-          if (result->len > 0)
-            g_string_append_c (result, ' ');
-          g_string_append (result, *e);
+          *(dst++) = *src;
+          continue;
 
         disabled:
+          g_free (*src);
           continue;
         }
 
-      enabled_extensions = g_string_free (result, FALSE);
+      *dst = NULL;
 
-      g_strfreev (split_enabled_extensions);
       if (split_env_disabled_extensions)
         g_strfreev (split_env_disabled_extensions);
       if (split_conf_disabled_extensions)
         g_strfreev (split_conf_disabled_extensions);
-
-      cogl_object_set_user_data (COGL_OBJECT (context),
-                                 &extensions_key,
-                                 (void *) enabled_extensions,
-                                 (CoglUserDataDestroyCallback) g_free);
-
-      return enabled_extensions;
     }
-  else
-    return (const char *) context->glGetString (GL_EXTENSIONS);
+
+  return ret;
 }
 
 const char *
diff --git a/cogl/cogl-feature-private.c b/cogl/cogl-feature-private.c
index 7883b3c..b8e4000 100644
--- a/cogl/cogl-feature-private.c
+++ b/cogl/cogl-feature-private.c
@@ -31,6 +31,7 @@
 
 #include "cogl-feature-private.h"
 #include "cogl-renderer-private.h"
+#include "cogl-private.h"
 
 CoglBool
 _cogl_feature_check (CoglRenderer *renderer,
@@ -39,7 +40,7 @@ _cogl_feature_check (CoglRenderer *renderer,
                      int gl_major,
                      int gl_minor,
                      CoglDriver driver,
-                     const char *extensions_string,
+                     char * const *extensions,
                      void *function_table)
 
 {
@@ -49,7 +50,8 @@ _cogl_feature_check (CoglRenderer *renderer,
 
   /* First check whether the functions should be directly provided by
      GL */
-  if ((driver == COGL_DRIVER_GL &&
+  if (((driver == COGL_DRIVER_GL ||
+        driver == COGL_DRIVER_GL3) &&
        COGL_CHECK_GL_VERSION (gl_major, gl_minor,
                               data->min_gl_major, data->min_gl_minor)) ||
       (driver == COGL_DRIVER_GLES1 &&
@@ -97,7 +99,7 @@ _cogl_feature_check (CoglRenderer *renderer,
               g_string_append_c (full_extension_name, '_');
               g_string_append (full_extension_name, extension);
               if (_cogl_check_extension (full_extension_name->str,
-                                         extensions_string))
+                                         extensions))
                 break;
             }
 
@@ -192,7 +194,7 @@ void
 _cogl_feature_check_ext_functions (CoglContext *context,
                                    int gl_major,
                                    int gl_minor,
-                                   const char *gl_extensions)
+                                   char * const *gl_extensions)
 {
   int i;
 
diff --git a/cogl/cogl-feature-private.h b/cogl/cogl-feature-private.h
index ad210a5..e6f895d 100644
--- a/cogl/cogl-feature-private.h
+++ b/cogl/cogl-feature-private.h
@@ -87,13 +87,13 @@ _cogl_feature_check (CoglRenderer *renderer,
                      int gl_major,
                      int gl_minor,
                      CoglDriver driver,
-                     const char *extensions_string,
+                     char * const *extensions,
                      void *function_table);
 
 void
 _cogl_feature_check_ext_functions (CoglContext *context,
                                    int gl_major,
                                    int gl_minor,
-                                   const char *gl_extensions);
+                                   char * const *gl_extensions);
 
 #endif /* __COGL_FEATURE_PRIVATE_H */
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 5dc02f8..fd646b1 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -1556,7 +1556,8 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
      GL_RGBA/GL_UNSIGNED_BYTE and convert if necessary. We also need
      to use this intermediate buffer if the rowstride has padding
      because GLES does not support setting GL_ROW_LENGTH */
-  if ((ctx->driver != COGL_DRIVER_GL &&
+  if ((!(ctx->private_feature_flags &
+         COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT) &&
        (gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE ||
         cogl_bitmap_get_rowstride (bitmap) != 4 * width)) ||
       (required_format & ~COGL_PREMULT_BIT) != (format & ~COGL_PREMULT_BIT))
@@ -1567,7 +1568,8 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
       uint8_t *tmp_data;
       int succeeded;
 
-      if (ctx->driver == COGL_DRIVER_GL)
+      if ((ctx->private_feature_flags &
+           COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT))
         read_format = required_format;
       else
         {
diff --git a/cogl/cogl-internal.h b/cogl/cogl-internal.h
index 88fd188..c2f3879 100644
--- a/cogl/cogl-internal.h
+++ b/cogl/cogl-internal.h
@@ -104,7 +104,17 @@ typedef enum
   COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL = 1L<<8,
   COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888 = 1L<<9,
   COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE = 1L<<10,
-  COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS = 1L<<11
+  COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS = 1L<<11,
+  COGL_PRIVATE_FEATURE_FIXED_FUNCTION = 1L<<12,
+  COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT = 1L<<13,
+  COGL_PRIVATE_FEATURE_ANY_GL = 1L<<14,
+  COGL_PRIVATE_FEATURE_ALPHA_TEST = 1L<<15,
+  COGL_PRIVATE_FEATURE_FORMAT_CONVERSION = 1L<<16,
+  COGL_PRIVATE_FEATURE_QUADS = 1L<<17,
+  COGL_PRIVATE_FEATURE_BLEND_CONSTANT = 1L<<18,
+  COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS = 1L<<19,
+  COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM = 1L<<20,
+  COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS = 1L<<21
 } CoglPrivateFeatureFlags;
 
 /* Sometimes when evaluating pipelines, either during comparisons or
@@ -115,9 +125,6 @@ typedef enum _CoglPipelineEvalFlags
   COGL_PIPELINE_EVAL_FLAG_NONE = 0
 } CoglPipelineEvalFlags;
 
-CoglBool
-_cogl_check_extension (const char *name, const char *ext);
-
 uint32_t
 _cogl_driver_error_quark (void);
 
diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c
index 25422a4..e8eee79 100644
--- a/cogl/cogl-journal.c
+++ b/cogl/cogl-journal.c
@@ -303,7 +303,7 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
     draw_flags |= COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE;
 
 #ifdef HAVE_COGL_GL
-  if (ctx->driver == COGL_DRIVER_GL)
+  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_QUADS))
     {
       /* XXX: it's rather evil that we sneak in the GL_QUADS enum here... */
       _cogl_framebuffer_draw_attributes (framebuffer,
@@ -615,7 +615,7 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
                         4,
                         COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
 
-  if (ctx->driver != COGL_DRIVER_GL)
+  if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_QUADS))
     state->indices = cogl_get_rectangle_indices (ctx, batch_len);
 
   /* We only create new Attributes when the stride within the
diff --git a/cogl/cogl-matrix-stack.c b/cogl/cogl-matrix-stack.c
index 2d61a5e..de3143d 100644
--- a/cogl/cogl-matrix-stack.c
+++ b/cogl/cogl-matrix-stack.c
@@ -795,8 +795,7 @@ _cogl_matrix_flush_to_gl_builtin (CoglContext *ctx,
                                   CoglMatrix *matrix,
                                   CoglMatrixMode mode)
 {
-  g_assert (ctx->driver == COGL_DRIVER_GL ||
-            ctx->driver == COGL_DRIVER_GLES1);
+  g_assert ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FIXED_FUNCTION));
 
 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
   if (ctx->flushed_matrix_mode != mode)
@@ -836,8 +835,7 @@ _cogl_matrix_entry_flush_to_gl_builtins (CoglContext *ctx,
                                          CoglFramebuffer *framebuffer,
                                          CoglBool disable_flip)
 {
-  g_assert (ctx->driver == COGL_DRIVER_GL ||
-            ctx->driver == COGL_DRIVER_GLES1);
+  g_assert ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FIXED_FUNCTION));
 
 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
   {
diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl-pipeline-state.c
index c7f3bde..bb00568 100644
--- a/cogl/cogl-pipeline-state.c
+++ b/cogl/cogl-pipeline-state.c
@@ -1037,7 +1037,7 @@ cogl_pipeline_set_blend_constant (CoglPipeline *pipeline,
 
   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
 
-  if (ctx->driver == COGL_DRIVER_GLES1)
+  if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_BLEND_CONSTANT))
     return;
 
 #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 2ad9e14..6026ddb 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -2824,8 +2824,10 @@ _cogl_pipeline_get_layer_state_for_fragment_codegen (CoglContext *context)
      COGL_PIPELINE_LAYER_STATE_UNIT |
      COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS);
 
-  if (context->driver == COGL_DRIVER_GL ||
-      context->driver == COGL_DRIVER_GLES2)
+  /* If the driver supports GLSL then we might be using gl_PointCoord
+   * to implement the sprite coords. In that case the generated code
+   * depends on the point sprite state */
+  if (cogl_has_feature (context, COGL_FEATURE_ID_GLSL))
     state |= COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
 
   return state;
@@ -2838,7 +2840,7 @@ _cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context)
                              COGL_PIPELINE_STATE_USER_SHADER |
                              COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS);
 
-  if (context->driver == COGL_DRIVER_GLES2)
+  if (!(context->private_feature_flags & COGL_PRIVATE_FEATURE_ALPHA_TEST))
     state |= COGL_PIPELINE_STATE_ALPHA_FUNC;
 
   return state;
diff --git a/cogl/cogl-private.h b/cogl/cogl-private.h
index d167cb3..10eebac 100644
--- a/cogl/cogl-private.h
+++ b/cogl/cogl-private.h
@@ -31,7 +31,7 @@
 G_BEGIN_DECLS
 
 CoglBool
-_cogl_check_extension (const char *name, const char *ext);
+_cogl_check_extension (const char *name, char * const *ext);
 
 void
 _cogl_clear (const CoglColor *color, unsigned long buffers);
diff --git a/cogl/cogl-renderer.c b/cogl/cogl-renderer.c
index 30eb4ad..11f0ec3 100644
--- a/cogl/cogl-renderer.c
+++ b/cogl/cogl-renderer.c
@@ -286,6 +286,15 @@ _cogl_renderer_choose_driver (CoglRenderer *renderer,
       libgl_name = COGL_GL_LIBNAME;
       goto found;
     }
+
+  if (renderer->driver_override == COGL_DRIVER_GL3 ||
+      (renderer->driver_override == COGL_DRIVER_ANY &&
+       (driver_name == NULL || !g_ascii_strcasecmp (driver_name, "gl3"))))
+    {
+      renderer->driver = COGL_DRIVER_GL3;
+      libgl_name = COGL_GL_LIBNAME;
+      goto found;
+    }
 #endif
 
 #ifdef HAVE_COGL_GLES2
@@ -340,6 +349,7 @@ found:
 #ifndef HAVE_DIRECTLY_LINKED_GL_LIBRARY
 
   if (renderer->driver == COGL_DRIVER_GL ||
+      renderer->driver == COGL_DRIVER_GL3 ||
       renderer->driver == COGL_DRIVER_GLES1 ||
       renderer->driver == COGL_DRIVER_GLES2)
     {
@@ -362,6 +372,7 @@ found:
     {
 #ifdef HAVE_COGL_GL
     case COGL_DRIVER_GL:
+    case COGL_DRIVER_GL3:
       renderer->driver_vtable = &_cogl_driver_gl;
       renderer->texture_driver = &_cogl_texture_driver_gl;
       break;
@@ -579,7 +590,7 @@ cogl_renderer_get_n_fragment_texture_units (CoglRenderer *renderer)
   _COGL_GET_CONTEXT (ctx, 0);
 
 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES2)
-  if (ctx->driver == COGL_DRIVER_GL || ctx->driver == COGL_DRIVER_GLES2)
+  if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
     GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &n));
 #endif
 
diff --git a/cogl/cogl-renderer.h b/cogl/cogl-renderer.h
index b1ddb9f..383eeac 100644
--- a/cogl/cogl-renderer.h
+++ b/cogl/cogl-renderer.h
@@ -330,6 +330,7 @@ cogl_renderer_remove_constraint (CoglRenderer *renderer,
  * @COGL_DRIVER_ANY: Implies no preference for which driver is used
  * @COGL_DRIVER_NOP: A No-Op driver.
  * @COGL_DRIVER_GL: An OpenGL driver.
+ * @COGL_DRIVER_GL3: An OpenGL driver using the core GL 3.1 profile
  * @COGL_DRIVER_GLES1: An OpenGL ES 1.1 driver.
  * @COGL_DRIVER_GLES2: An OpenGL ES 2.0 driver.
  *
@@ -344,6 +345,7 @@ typedef enum
   COGL_DRIVER_ANY,
   COGL_DRIVER_NOP,
   COGL_DRIVER_GL,
+  COGL_DRIVER_GL3,
   COGL_DRIVER_GLES1,
   COGL_DRIVER_GLES2
 } CoglDriver;
diff --git a/cogl/cogl-shader.c b/cogl/cogl-shader.c
index 663661c..3c2a0b7 100644
--- a/cogl/cogl-shader.c
+++ b/cogl/cogl-shader.c
@@ -239,7 +239,8 @@ _cogl_shader_compile_real (CoglHandle handle,
 
       shader->gl_handle = ctx->glCreateShader (gl_type);
 
-      if (ctx->driver == COGL_DRIVER_GL &&
+      if ((ctx->driver == COGL_DRIVER_GL ||
+           ctx->driver == COGL_DRIVER_GL3 ) &&
           ctx->glsl_major == 1 &&
           ctx->glsl_minor >= 2)
         {
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index ebc137f..95608c6 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -206,7 +206,7 @@ _cogl_texture_prepare_for_upload (CoglBitmap      *src_bmp,
      limited number of formats so we must convert using the Cogl
      bitmap code instead */
 
-  if (ctx->driver == COGL_DRIVER_GL)
+  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FORMAT_CONVERSION))
     {
       /* If the source format does not have the same premult flag as the
          dst format then we need to copy and convert it */
diff --git a/cogl/cogl.c b/cogl/cogl.c
index 998a478..76ac717 100644
--- a/cogl/cogl.c
+++ b/cogl/cogl.c
@@ -51,6 +51,7 @@
 #include "cogl1-context.h"
 #include "cogl-offscreen.h"
 #include "cogl-attribute-gl-private.h"
+#include "cogl-clutter.h"
 
 #ifdef COGL_GL_DEBUG
 /* GL error to string conversion */
@@ -99,26 +100,13 @@ cogl_get_proc_address (const char* name)
 }
 
 CoglBool
-_cogl_check_extension (const char *name, const gchar *ext)
+_cogl_check_extension (const char *name, char * const *ext)
 {
-  char *end;
-  int name_len, n;
-
-  if (name == NULL || ext == NULL)
-    return FALSE;
-
-  end = (char*)(ext + strlen(ext));
-
-  name_len = strlen(name);
-
-  while (ext < end)
-    {
-      n = strcspn(ext, " ");
-
-      if ((name_len == n) && (!strncmp(name, ext, n)))
-	return TRUE;
-      ext += (n + 1);
-    }
+  while (*ext)
+    if (!strcmp (name, *ext))
+      return TRUE;
+    else
+      ext++;
 
   return FALSE;
 }
@@ -127,7 +115,7 @@ _cogl_check_extension (const char *name, const gchar *ext)
 CoglBool
 cogl_check_extension (const char *name, const char *ext)
 {
-  return _cogl_check_extension (name, ext);
+  return cogl_clutter_check_extension (name, ext);
 }
 
 /* XXX: it's expected that we'll deprecated this with
diff --git a/cogl/driver/gl/cogl-attribute-gl.c b/cogl/driver/gl/cogl-attribute-gl.c
index 3d93f3f..312f0ea 100644
--- a/cogl/driver/gl/cogl-attribute-gl.c
+++ b/cogl/driver/gl/cogl-attribute-gl.c
@@ -54,8 +54,8 @@ toggle_builtin_attribute_enabled_cb (int bit_num, void *user_data)
   ForeachChangedBitState *state = user_data;
   CoglContext *context = state->context;
 
-  _COGL_RETURN_VAL_IF_FAIL (context->driver == COGL_DRIVER_GL ||
-                            context->driver == COGL_DRIVER_GLES1,
+  _COGL_RETURN_VAL_IF_FAIL ((context->private_feature_flags &
+                             COGL_PRIVATE_FEATURE_FIXED_FUNCTION),
                             FALSE);
 
 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
@@ -91,8 +91,8 @@ toggle_texcood_attribute_enabled_cb (int bit_num, void *user_data)
   ForeachChangedBitState *state = user_data;
   CoglContext *context = state->context;
 
-  _COGL_RETURN_VAL_IF_FAIL (context->driver == COGL_DRIVER_GL ||
-                            context->driver == COGL_DRIVER_GLES1,
+  _COGL_RETURN_VAL_IF_FAIL ((context->private_feature_flags &
+                             COGL_PRIVATE_FEATURE_FIXED_FUNCTION),
                             FALSE);
 
 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
diff --git a/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/driver/gl/cogl-clip-stack-gl.c
index eaf46bc..db9fbd4 100644
--- a/cogl/driver/gl/cogl-clip-stack-gl.c
+++ b/cogl/driver/gl/cogl-clip-stack-gl.c
@@ -122,6 +122,7 @@ set_clip_plane (CoglFramebuffer *framebuffer,
       break;
 
     case COGL_DRIVER_GL:
+    case COGL_DRIVER_GL3:
       planed[0] = planef[0];
       planed[1] = planef[1];
       planed[2] = planef[2];
diff --git a/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/driver/gl/cogl-framebuffer-gl.c
index f2c22b2..4a6f62a 100644
--- a/cogl/driver/gl/cogl-framebuffer-gl.c
+++ b/cogl/driver/gl/cogl-framebuffer-gl.c
@@ -896,8 +896,8 @@ _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
     return;
 
 #ifdef HAVE_COGL_GL
-  if (ctx->driver == COGL_DRIVER_GL &&
-      cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
+  if ((ctx->private_feature_flags &
+       COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS) &&
       framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
     {
       GLenum attachment, pname;
diff --git a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c b/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
index 4df7199..aeb5056 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
@@ -913,10 +913,10 @@ _cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline,
   return TRUE;
 }
 
-/* GLES2 doesn't have alpha testing so we need to implement it in the
-   shader */
+/* GLES2 and GL3 don't have alpha testing so we need to implement it
+   in the shader */
 
-#ifdef HAVE_COGL_GLES2
+#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
 
 static void
 add_alpha_test_snippet (CoglPipeline *pipeline,
@@ -1046,8 +1046,8 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
         g_string_append (shader_state->source,
                          "  cogl_color_out = cogl_color_in;\n");
 
-#ifdef HAVE_COGL_GLES2
-      if (ctx->driver == COGL_DRIVER_GLES2)
+#if defined(HAVE_COGL_GLES2) || defined (HAVE_COGL_GL)
+      if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_ALPHA_TEST))
         add_alpha_test_snippet (pipeline, shader_state);
 #endif
 
@@ -1072,10 +1072,9 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
       source_strings[1] = shader_state->source->str;
 
       if (shader_state->ref_point_coord &&
-          ctx->driver == COGL_DRIVER_GL)
-        {
-          version_string = "#version 120\n";
-        }
+          (ctx->driver == COGL_DRIVER_GL ||
+           ctx->driver == COGL_DRIVER_GL3))
+        version_string = "#version 120\n";
       else
         version_string = NULL;
 
diff --git a/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/driver/gl/cogl-pipeline-opengl.c
index 103ecdb..8995541 100644
--- a/cogl/driver/gl/cogl-pipeline-opengl.c
+++ b/cogl/driver/gl/cogl-pipeline-opengl.c
@@ -452,7 +452,7 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   /* On GLES2 we'll flush the color later */
-  if (ctx->driver != COGL_DRIVER_GLES2 &&
+  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FIXED_FUNCTION) &&
       !skip_gl_color)
     {
       if ((pipelines_difference & COGL_PIPELINE_STATE_COLOR) ||
@@ -531,7 +531,7 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
 
 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
 
-  if (ctx->driver != COGL_DRIVER_GLES2)
+  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_ALPHA_TEST))
     {
       /* Under GLES2 the alpha function is implemented as part of the
          fragment shader */
@@ -675,7 +675,8 @@ get_max_activateable_texture_units (void)
       int i;
 
 #ifdef HAVE_COGL_GL
-      if (ctx->driver == COGL_DRIVER_GL)
+      if (ctx->driver == COGL_DRIVER_GL ||
+          ctx->driver == COGL_DRIVER_GL3)
         {
           /* GL_MAX_TEXTURE_COORDS is provided for both GLSL and ARBfp. It
              defines the number of texture coordinates that can be
@@ -856,7 +857,7 @@ flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data)
    * glsl progend.
    */
 #if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GL)
-  if (ctx->driver != COGL_DRIVER_GLES2 &&
+  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FIXED_FUNCTION) &&
       (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS))
     {
       CoglPipelineState change = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
diff --git a/cogl/driver/gl/cogl-pipeline-progend-fixed.c b/cogl/driver/gl/cogl-pipeline-progend-fixed.c
index b096bab..78a8c8d 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-fixed.c
+++ b/cogl/driver/gl/cogl-pipeline-progend-fixed.c
@@ -48,7 +48,7 @@ _cogl_pipeline_progend_fixed_start (CoglPipeline *pipeline)
   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
     return FALSE;
 
-  if (ctx->driver == COGL_DRIVER_GLES2)
+  if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FIXED_FUNCTION))
     return FALSE;
 
   /* Vertex snippets are only supported in the GLSL fragend */
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
index f382492..f1b1407 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
@@ -261,7 +261,8 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
                    "cogl_generated_source ()\n"
                    "{\n");
 
-  if (ctx->driver == COGL_DRIVER_GLES2)
+  if (!(ctx->private_feature_flags &
+        COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM))
     /* There is no builtin uniform for the pointsize on GLES2 so we need
        to copy it from the custom uniform in the vertex shader */
     g_string_append (shader_state->source,
@@ -460,7 +461,8 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
       shader_state->gl_shader = shader;
     }
 
-  if (ctx->driver == COGL_DRIVER_GL &&
+  if ((ctx->private_feature_flags &
+       COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM) &&
       (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE))
     {
       CoglPipeline *authority =
diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c
index 5056544..1d64d5b 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -323,7 +323,8 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
      (only level 0 we are interested in) */
 
 #if HAVE_COGL_GL
-  if (ctx->driver == COGL_DRIVER_GL)
+  if ((ctx->private_feature_flags &
+       COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS))
     {
       GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
                                          GL_TEXTURE_COMPRESSED,
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c
index bb24106..7600db2 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -291,10 +291,10 @@ _cogl_get_gl_version (CoglContext *ctx,
 
 static CoglBool
 check_gl_version (CoglContext *ctx,
+                  char **gl_extensions,
                   CoglError **error)
 {
   int major, minor;
-  const char *gl_extensions;
 
   if (!_cogl_get_gl_version (ctx, &major, &minor))
     {
@@ -309,8 +309,6 @@ check_gl_version (CoglContext *ctx,
   if (COGL_CHECK_GL_VERSION (major, minor, 1, 3))
     return TRUE;
 
-  gl_extensions = _cogl_context_get_gl_extensions (ctx);
-
   /* OpenGL 1.2 is only supported if we have the multitexturing
      extension */
   if (!_cogl_check_extension ("GL_ARB_multitexture", gl_extensions))
@@ -344,32 +342,49 @@ _cogl_driver_update_features (CoglContext *ctx,
 {
   CoglPrivateFeatureFlags private_flags = 0;
   CoglFeatureFlags flags = 0;
-  const char *gl_extensions;
+  char **gl_extensions;
   int max_clip_planes = 0;
   int num_stencil_bits = 0;
   int gl_major = 0, gl_minor = 0;
 
-  /* We have to special case getting the pointer to the glGetString
-     function because we need to use it to determine what functions we
-     can expect */
+  /* We have to special case getting the pointer to the glGetString*
+     functions because we need to use them to determine what functions
+     we can expect */
   ctx->glGetString =
     (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
                                               "glGetString",
                                               TRUE);
+  ctx->glGetStringi =
+    (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
+                                              "glGetStringi",
+                                              TRUE);
+  ctx->glGetIntegerv =
+    (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
+                                              "glGetIntegerv",
+                                              TRUE);
+
+  gl_extensions = _cogl_context_get_gl_extensions (ctx);
 
-  if (!check_gl_version (ctx, error))
+  if (!check_gl_version (ctx, gl_extensions, error))
     return FALSE;
 
-  COGL_NOTE (WINSYS,
-             "Checking features\n"
-             "  GL_VENDOR: %s\n"
-             "  GL_RENDERER: %s\n"
-             "  GL_VERSION: %s\n"
-             "  GL_EXTENSIONS: %s",
-             ctx->glGetString (GL_VENDOR),
-             ctx->glGetString (GL_RENDERER),
-             _cogl_context_get_gl_version (ctx),
-             _cogl_context_get_gl_extensions (ctx));
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS)))
+    {
+      char *all_extensions = g_strjoinv (" ", gl_extensions);
+
+      COGL_NOTE (WINSYS,
+                 "Checking features\n"
+                 "  GL_VENDOR: %s\n"
+                 "  GL_RENDERER: %s\n"
+                 "  GL_VERSION: %s\n"
+                 "  GL_EXTENSIONS: %s",
+                 ctx->glGetString (GL_VENDOR),
+                 ctx->glGetString (GL_RENDERER),
+                 _cogl_context_get_gl_version (ctx),
+                 all_extensions);
+
+      g_free (all_extensions);
+    }
 
   _cogl_get_gl_version (ctx, &gl_major, &gl_minor);
 
@@ -395,8 +410,6 @@ _cogl_driver_update_features (CoglContext *ctx,
   if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4))
     COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE);
 
-  gl_extensions = _cogl_context_get_gl_extensions (ctx);
-
   _cogl_feature_check_ext_functions (ctx,
                                      gl_major,
                                      gl_minor,
@@ -434,6 +447,7 @@ _cogl_driver_update_features (CoglContext *ctx,
     {
       flags |= COGL_FEATURE_OFFSCREEN;
       COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
+      private_flags |= COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS;
     }
 
   if (ctx->glBlitFramebuffer)
@@ -457,6 +471,10 @@ _cogl_driver_update_features (CoglContext *ctx,
       _cogl_check_extension ("GL_EXT_pixel_buffer_object", gl_extensions))
     private_flags |= COGL_PRIVATE_FEATURE_PBOS;
 
+  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4) ||
+      _cogl_check_extension ("GL_EXT_blend_color", gl_extensions))
+    private_flags |= COGL_PRIVATE_FEATURE_BLEND_CONSTANT;
+
   if (ctx->glGenPrograms)
     {
       flags |= COGL_FEATURE_SHADERS_ARBFP;
@@ -546,10 +564,25 @@ _cogl_driver_update_features (CoglContext *ctx,
   if (ctx->glGenSamplers)
     private_flags |= COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS;
 
+  if (ctx->driver == COGL_DRIVER_GL)
+    /* Features which are not available in GL 3 */
+    private_flags |= (COGL_PRIVATE_FEATURE_FIXED_FUNCTION |
+                      COGL_PRIVATE_FEATURE_ALPHA_TEST |
+                      COGL_PRIVATE_FEATURE_QUADS);
+
+  private_flags |= (COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT |
+                    COGL_PRIVATE_FEATURE_ANY_GL |
+                    COGL_PRIVATE_FEATURE_FORMAT_CONVERSION |
+                    COGL_PRIVATE_FEATURE_BLEND_CONSTANT |
+                    COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM |
+                    COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS);
+
   /* Cache features */
   ctx->private_feature_flags |= private_flags;
   ctx->feature_flags |= flags;
 
+  g_strfreev (gl_extensions);
+
   return TRUE;
 }
 
diff --git a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
index b105fa2..3975b8d 100644
--- a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
+++ b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
@@ -51,7 +51,7 @@ _cogl_pipeline_progend_fixed_arbfp_start (CoglPipeline *pipeline)
   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
     return FALSE;
 
-  if (ctx->driver == COGL_DRIVER_GLES2)
+  if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FIXED_FUNCTION))
     return FALSE;
 
   /* Vertex snippets are only supported in the GLSL fragend */
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c
index 6268b4d..dd4955b 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -192,7 +192,7 @@ _cogl_driver_update_features (CoglContext *context,
 {
   CoglPrivateFeatureFlags private_flags = 0;
   CoglFeatureFlags flags = 0;
-  const char *gl_extensions;
+  char **gl_extensions;
   int num_stencil_bits = 0;
 
   /* We have to special case getting the pointer to the glGetString
@@ -203,23 +203,30 @@ _cogl_driver_update_features (CoglContext *context,
                                               "glGetString",
                                               TRUE);
 
-  COGL_NOTE (WINSYS,
-             "Checking features\n"
-             "  GL_VENDOR: %s\n"
-             "  GL_RENDERER: %s\n"
-             "  GL_VERSION: %s\n"
-             "  GL_EXTENSIONS: %s",
-             context->glGetString (GL_VENDOR),
-             context->glGetString (GL_RENDERER),
-             _cogl_context_get_gl_version (context),
-             _cogl_context_get_gl_extensions (context));
+  gl_extensions = _cogl_context_get_gl_extensions (context);
 
-  _cogl_gpu_info_init (context, &context->gpu);
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS)))
+    {
+      char *all_extensions = g_strjoinv (" ", gl_extensions);
+
+      COGL_NOTE (WINSYS,
+                 "Checking features\n"
+                 "  GL_VENDOR: %s\n"
+                 "  GL_RENDERER: %s\n"
+                 "  GL_VERSION: %s\n"
+                 "  GL_EXTENSIONS: %s",
+                 context->glGetString (GL_VENDOR),
+                 context->glGetString (GL_RENDERER),
+                 _cogl_context_get_gl_version (context),
+                 all_extensions);
+
+      g_free (all_extensions);
+    }
 
   context->glsl_major = 1;
   context->glsl_minor = 0;
 
-  gl_extensions = _cogl_context_get_gl_extensions (context);
+  _cogl_gpu_info_init (context, &context->gpu);
 
   _cogl_feature_check_ext_functions (context,
                                      -1 /* GL major version */,
@@ -255,9 +262,16 @@ _cogl_driver_update_features (CoglContext *context,
       COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE);
       COGL_FLAGS_SET (context->features,
                       COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE);
+
+      private_flags |= COGL_PRIVATE_FEATURE_BLEND_CONSTANT;
     }
+  else if (context->driver == COGL_DRIVER_GLES1)
+    private_flags |= (COGL_PRIVATE_FEATURE_FIXED_FUNCTION |
+                      COGL_PRIVATE_FEATURE_ALPHA_TEST |
+                      COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM);
 
-  private_flags |= COGL_PRIVATE_FEATURE_VBOS;
+  private_flags |= (COGL_PRIVATE_FEATURE_VBOS |
+                    COGL_PRIVATE_FEATURE_ANY_GL);
 
   /* Both GLES 1.1 and GLES 2.0 support point sprites in core */
   flags |= COGL_FEATURE_POINT_SPRITE;
@@ -341,6 +355,8 @@ _cogl_driver_update_features (CoglContext *context,
   context->private_feature_flags |= private_flags;
   context->feature_flags |= flags;
 
+  g_strfreev (gl_extensions);
+
   return TRUE;
 }
 
diff --git a/cogl/gl-prototypes/cogl-all-functions.h b/cogl/gl-prototypes/cogl-all-functions.h
index 1fa475f..eeef4e7 100644
--- a/cogl/gl-prototypes/cogl-all-functions.h
+++ b/cogl/gl-prototypes/cogl-all-functions.h
@@ -128,7 +128,7 @@ COGL_EXT_END ()
 
 
 
-COGL_EXT_BEGIN (offscreen_blit, 255, 255,
+COGL_EXT_BEGIN (offscreen_blit, 3, 0,
                 0, /* not in either GLES */
                 "EXT\0ANGLE\0",
                 "framebuffer_blit\0")
@@ -211,7 +211,7 @@ COGL_EXT_FUNCTION (void, glFramebufferTexture2DMultisampleIMG,
                     GLsizei          samples))
 COGL_EXT_END ()
 
-COGL_EXT_BEGIN (ARB_sampler_objects, 255, 255,
+COGL_EXT_BEGIN (ARB_sampler_objects, 3, 3,
                 0, /* not in either GLES */
                 "ARB:\0",
                 "sampler_objects\0")
@@ -264,3 +264,25 @@ COGL_EXT_FUNCTION (void, glGetAttachedObjects,
                     GLsizei* count,
                     GLuint* shaders))
 COGL_EXT_END ()
+
+COGL_EXT_BEGIN (only_gl3, 3, 0,
+                0, /* not in either GLES */
+                "\0",
+                "\0")
+COGL_EXT_FUNCTION (const GLubyte *, glGetStringi,
+                   (GLenum name, GLuint index))
+COGL_EXT_END ()
+
+COGL_EXT_BEGIN (vertex_array_object, 3, 0,
+                0, /* not in either GLES */
+                "ARB\0OES\0",
+                "vertex_array_object\0")
+COGL_EXT_FUNCTION (void, glBindVertexArray,
+                   (GLuint array))
+COGL_EXT_FUNCTION (void, glDeleteVertexArrays,
+                   (GLsizei n,
+                    const GLuint *arrays))
+COGL_EXT_FUNCTION (void, glGenVertexArrays,
+                   (GLsizei n,
+                    GLuint *arrays))
+COGL_EXT_END ()
diff --git a/cogl/gl-prototypes/cogl-in-gles-core-functions.h b/cogl/gl-prototypes/cogl-in-gles-core-functions.h
index 78dec26..9c8102f 100644
--- a/cogl/gl-prototypes/cogl-in-gles-core-functions.h
+++ b/cogl/gl-prototypes/cogl-in-gles-core-functions.h
@@ -50,11 +50,11 @@
  */
 
 COGL_EXT_BEGIN (only_in_both_gles,
-                255, 255,
+                4, 1,
                 COGL_EXT_IN_GLES |
                 COGL_EXT_IN_GLES2,
-                "\0",
-                "\0")
+                "ARB\0",
+                "ES2_compatibility\0")
 COGL_EXT_FUNCTION (void, glDepthRangef,
                    (GLfloat near_val, GLfloat far_val))
 COGL_EXT_FUNCTION (void, glClearDepthf,
diff --git a/cogl/gl-prototypes/cogl-in-gles2-core-functions.h b/cogl/gl-prototypes/cogl-in-gles2-core-functions.h
index f39bd27..6130576 100644
--- a/cogl/gl-prototypes/cogl-in-gles2-core-functions.h
+++ b/cogl/gl-prototypes/cogl-in-gles2-core-functions.h
@@ -50,7 +50,7 @@
  */
 
 COGL_EXT_BEGIN (offscreen,
-                255, 255,
+                3, 0,
                 COGL_EXT_IN_GLES2,
                 /* for some reason the ARB version of this
                    extension doesn't have an ARB suffix for the
@@ -146,10 +146,10 @@ COGL_EXT_FUNCTION (void, glBlendEquationSeparate,
 COGL_EXT_END ()
 
 COGL_EXT_BEGIN (gles2_only_api,
-                255, 255,
+                4, 1,
                 COGL_EXT_IN_GLES2,
-                "\0",
-                "\0")
+                "ARB:\0",
+                "ES2_compatibility\0")
 COGL_EXT_FUNCTION (void, glReleaseShaderCompiler, (void))
 COGL_EXT_FUNCTION (void, glGetShaderPrecisionFormat,
                    (GLenum shadertype,
diff --git a/cogl/winsys/cogl-winsys-egl-feature-functions.h b/cogl/winsys/cogl-winsys-egl-feature-functions.h
index 9c8dcca..9016f8d 100644
--- a/cogl/winsys/cogl-winsys-egl-feature-functions.h
+++ b/cogl/winsys/cogl-winsys-egl-feature-functions.h
@@ -87,4 +87,11 @@ COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglUnbindWaylandDisplay,
                               (EGLDisplay dpy,
                                struct wl_display *wayland_display))
 COGL_WINSYS_FEATURE_END ()
+
+COGL_WINSYS_FEATURE_BEGIN (create_context,
+                           "KHR\0",
+                           "create_context\0",
+                           COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT)
+COGL_WINSYS_FEATURE_END ()
+
 #endif
diff --git a/cogl/winsys/cogl-winsys-egl-private.h b/cogl/winsys/cogl-winsys-egl-private.h
index f1e5361..13ce9a4 100644
--- a/cogl/winsys/cogl-winsys-egl-private.h
+++ b/cogl/winsys/cogl-winsys-egl-private.h
@@ -68,7 +68,8 @@ typedef enum _CoglEGLWinsysFeature
 {
   COGL_EGL_WINSYS_FEATURE_SWAP_REGION                   =1L<<0,
   COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_X11_PIXMAP     =1L<<1,
-  COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_WAYLAND_BUFFER =1L<<2
+  COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_WAYLAND_BUFFER =1L<<2,
+  COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT                =1L<<3
 } CoglEGLWinsysFeature;
 
 typedef struct _CoglRendererEGL
diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c
index df07f81..f6fba07 100644
--- a/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/winsys/cogl-winsys-egl.c
@@ -148,9 +148,11 @@ check_egl_extensions (CoglRenderer *renderer)
 {
   CoglRendererEGL *egl_renderer = renderer->winsys;
   const char *egl_extensions;
+  char **split_extensions;
   int i;
 
   egl_extensions = eglQueryString (egl_renderer->edpy, EGL_EXTENSIONS);
+  split_extensions = g_strsplit (egl_extensions, " ", 0 /* max_tokens */);
 
   COGL_NOTE (WINSYS, "  EGL Extensions: %s", egl_extensions);
 
@@ -159,12 +161,14 @@ check_egl_extensions (CoglRenderer *renderer)
     if (_cogl_feature_check (renderer,
                              "EGL", winsys_feature_data + i, 0, 0,
                              COGL_DRIVER_GL, /* the driver isn't used */
-                             egl_extensions,
+                             split_extensions,
                              egl_renderer))
       {
         egl_renderer->private_features |=
           winsys_feature_data[i].feature_flags_private;
       }
+
+  g_strfreev (split_extensions);
 }
 
 CoglBool
@@ -234,11 +238,12 @@ egl_attributes_from_framebuffer_config (CoglDisplay *display,
   attributes[i++] = EGL_DONT_CARE;
 
   attributes[i++] = EGL_RENDERABLE_TYPE;
-  attributes[i++] = (renderer->driver == COGL_DRIVER_GL ?
-                      EGL_OPENGL_BIT :
-                      renderer->driver == COGL_DRIVER_GLES1 ?
-                      EGL_OPENGL_ES_BIT :
-                      EGL_OPENGL_ES2_BIT);
+  attributes[i++] = ((renderer->driver == COGL_DRIVER_GL ||
+                      renderer->driver == COGL_DRIVER_GL3) ?
+                     EGL_OPENGL_BIT :
+                     renderer->driver == COGL_DRIVER_GLES1 ?
+                     EGL_OPENGL_ES_BIT :
+                     EGL_OPENGL_ES2_BIT);
 
   attributes[i++] = EGL_SURFACE_TYPE;
   attributes[i++] = EGL_WINDOW_BIT;
@@ -314,24 +319,16 @@ try_create_context (CoglDisplay *display,
   EGLConfig config;
   EGLint config_count = 0;
   EGLBoolean status;
-  EGLint attribs[3];
+  EGLint attribs[9];
   EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS];
   const char *error_message;
 
   _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context == NULL, TRUE);
 
-  if (renderer->driver == COGL_DRIVER_GL)
+  if (renderer->driver == COGL_DRIVER_GL ||
+      renderer->driver == COGL_DRIVER_GL3)
     eglBindAPI (EGL_OPENGL_API);
 
-  if (display->renderer->driver == COGL_DRIVER_GLES2)
-    {
-      attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
-      attribs[1] = 2;
-      attribs[2] = EGL_NONE;
-    }
-  else
-    attribs[0] = EGL_NONE;
-
   egl_attributes_from_framebuffer_config (display,
                                           &display->onscreen_template->config,
                                           cfg_attribs);
@@ -350,10 +347,40 @@ try_create_context (CoglDisplay *display,
 
   egl_display->egl_config = config;
 
+  if (display->renderer->driver == COGL_DRIVER_GL3)
+    {
+      if (!(egl_renderer->private_features &
+            COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT))
+        {
+          error_message = "Driver does not support GL 3 contexts";
+          goto fail;
+        }
+
+      /* Try to get a core profile 3.1 context with no deprecated features */
+      attribs[0] = EGL_CONTEXT_MAJOR_VERSION_KHR;
+      attribs[1] = 3;
+      attribs[2] = EGL_CONTEXT_MINOR_VERSION_KHR;
+      attribs[3] = 1;
+      attribs[4] = EGL_CONTEXT_FLAGS_KHR;
+      attribs[5] = EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
+      attribs[6] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
+      attribs[7] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
+      attribs[8] = EGL_NONE;
+    }
+  else if (display->renderer->driver == COGL_DRIVER_GLES2)
+    {
+      attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
+      attribs[1] = 2;
+      attribs[2] = EGL_NONE;
+    }
+  else
+    attribs[0] = EGL_NONE;
+
   egl_display->egl_context = eglCreateContext (edpy,
                                                config,
                                                EGL_NO_CONTEXT,
                                                attribs);
+
   if (egl_display->egl_context == EGL_NO_CONTEXT)
     {
       error_message = "Unable to create a suitable EGL context";
diff --git a/cogl/winsys/cogl-winsys-glx-feature-functions.h b/cogl/winsys/cogl-winsys-glx-feature-functions.h
index 71fd827..f36e2ea 100644
--- a/cogl/winsys/cogl-winsys-glx-feature-functions.h
+++ b/cogl/winsys/cogl-winsys-glx-feature-functions.h
@@ -111,3 +111,17 @@ COGL_WINSYS_FEATURE_BEGIN (swap_event,
                            0,
                            COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT)
 COGL_WINSYS_FEATURE_END ()
+
+COGL_WINSYS_FEATURE_BEGIN (create_context,
+                           "ARB\0",
+                           "create_context",
+                           0,
+                           0,
+                           0)
+COGL_WINSYS_FEATURE_FUNCTION (GLXContext, glXCreateContextAttribs,
+                              (Display *dpy,
+                               GLXFBConfig config,
+                               GLXContext share_context,
+                               Bool direct,
+                               const int *attrib_list))
+COGL_WINSYS_FEATURE_END ()
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 6716c7c..c9449cc 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -331,7 +331,8 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
   if (!_cogl_xlib_renderer_connect (renderer, error))
     goto error;
 
-  if (renderer->driver != COGL_DRIVER_GL)
+  if (renderer->driver != COGL_DRIVER_GL &&
+      renderer->driver != COGL_DRIVER_GL3)
     {
       _cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
@@ -394,6 +395,7 @@ update_winsys_features (CoglContext *context, CoglError **error)
     _cogl_xlib_renderer_get_data (context->display->renderer);
   CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
   const char *glx_extensions;
+  char **split_extensions;
   int default_screen;
   int i;
 
@@ -418,11 +420,13 @@ update_winsys_features (CoglContext *context, CoglError **error)
                   COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
                   TRUE);
 
+  split_extensions = g_strsplit (glx_extensions, " ", 0 /* max_tokens */);
+
   for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++)
     if (_cogl_feature_check (context->display->renderer,
                              "GLX", winsys_feature_data + i, 0, 0,
                              COGL_DRIVER_GL, /* the driver isn't used */
-                             glx_extensions,
+                             split_extensions,
                              glx_renderer))
       {
         context->feature_flags |= winsys_feature_data[i].feature_flags;
@@ -432,6 +436,8 @@ update_winsys_features (CoglContext *context, CoglError **error)
                           TRUE);
       }
 
+  g_strfreev (split_extensions);
+
   /* Note: the GLX_SGI_video_sync spec explicitly states this extension
    * only works for direct contexts. */
   if (!glx_renderer->is_direct)
@@ -607,6 +613,36 @@ done:
   return ret;
 }
 
+static GLXContext
+create_gl3_context (CoglDisplay *display,
+                    GLXFBConfig fb_config)
+{
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (display->renderer);
+  CoglGLXRenderer *glx_renderer = display->renderer->winsys;
+
+  /* We want a core profile 3.1 context with no deprecated features */
+  static const int attrib_list[] =
+    {
+      GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+      GLX_CONTEXT_MINOR_VERSION_ARB, 1,
+      GLX_CONTEXT_PROFILE_MASK_ARB,  GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+      GLX_CONTEXT_FLAGS_ARB,         GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+      None
+    };
+
+  /* Make sure that the display supports the GLX_ARB_create_context
+     extension */
+  if (glx_renderer->pf_glXCreateContextAttribs == NULL)
+    return NULL;
+
+  return glx_renderer->pf_glXCreateContextAttribs (xlib_renderer->xdpy,
+                                                   fb_config,
+                                                   NULL /* share_context */,
+                                                   True, /* direct */
+                                                   attrib_list);
+}
+
 static CoglBool
 create_context (CoglDisplay *display, CoglError **error)
 {
@@ -644,12 +680,16 @@ create_context (CoglDisplay *display, CoglError **error)
   COGL_NOTE (WINSYS, "Creating GLX Context (display: %p)",
              xlib_renderer->xdpy);
 
-  glx_display->glx_context =
-    glx_renderer->glXCreateNewContext (xlib_renderer->xdpy,
-                                       config,
-                                       GLX_RGBA_TYPE,
-                                       NULL,
-                                       True);
+  if (display->renderer->driver == COGL_DRIVER_GL3)
+    glx_display->glx_context = create_gl3_context (display, config);
+  else
+    glx_display->glx_context =
+      glx_renderer->glXCreateNewContext (xlib_renderer->xdpy,
+                                         config,
+                                         GLX_RGBA_TYPE,
+                                         NULL,
+                                         True);
+
   if (glx_display->glx_context == NULL)
     {
       _cogl_set_error (error, COGL_WINSYS_ERROR,
diff --git a/cogl/winsys/cogl-winsys-sdl.c b/cogl/winsys/cogl-winsys-sdl.c
index f3a71d3..63abbd0 100644
--- a/cogl/winsys/cogl-winsys-sdl.c
+++ b/cogl/winsys/cogl-winsys-sdl.c
@@ -162,6 +162,12 @@ _cogl_winsys_display_setup (CoglDisplay *display,
       sdl_display->video_mode_flags = SDL_OPENGL;
       break;
 
+    case COGL_DRIVER_GL3:
+      _cogl_set_error (error, COGL_WINSYS_ERROR,
+                       COGL_WINSYS_ERROR_INIT,
+                       "The SDL winsys does not support GL 3");
+      goto error;
+
 #ifdef COGL_HAS_SDL_GLES_SUPPORT
     case COGL_DRIVER_GLES2:
       sdl_display->video_mode_flags = SDL_OPENGLES;
diff --git a/cogl/winsys/cogl-winsys-sdl2.c b/cogl/winsys/cogl-winsys-sdl2.c
index fd9d7d5..8367324 100644
--- a/cogl/winsys/cogl-winsys-sdl2.c
+++ b/cogl/winsys/cogl-winsys-sdl2.c
@@ -157,6 +157,8 @@ _cogl_winsys_display_setup (CoglDisplay *display,
     SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 1);
   else if (display->renderer->driver == COGL_DRIVER_GLES2)
     SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+  else if (display->renderer->driver == COGL_DRIVER_GL3)
+    SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3);
 
   /* Create a dummy 1x1 window that never gets display so that we can
    * create a GL context */
@@ -195,6 +197,7 @@ _cogl_winsys_display_setup (CoglDisplay *display,
   switch (display->renderer->driver)
     {
     case COGL_DRIVER_GL:
+    case COGL_DRIVER_GL3:
       /* The first character of the version string will be a digit if
        * it's normal GL */
       if (!g_ascii_isdigit (gl_version[0]))
@@ -204,6 +207,29 @@ _cogl_winsys_display_setup (CoglDisplay *display,
                        "The GL driver was requested but SDL is using GLES");
           goto error;
         }
+
+      if (gl_version[0] >= '3')
+        {
+          if (display->renderer->driver == COGL_DRIVER_GL)
+            {
+              _cogl_set_error (error, COGL_WINSYS_ERROR,
+                               COGL_WINSYS_ERROR_INIT,
+                               "The GL driver was requested but SDL is using "
+                               "GL %c", gl_version[0]);
+              goto error;
+            }
+        }
+      else
+        {
+          if (display->renderer->driver == COGL_DRIVER_GL3)
+            {
+              _cogl_set_error (error, COGL_WINSYS_ERROR,
+                               COGL_WINSYS_ERROR_INIT,
+                               "The GL3 driver was requested but SDL is using "
+                               "GL %c", gl_version[0]);
+              goto error;
+            }
+        }
       break;
 
     case COGL_DRIVER_GLES2:
diff --git a/cogl/winsys/cogl-winsys-wgl.c b/cogl/winsys/cogl-winsys-wgl.c
index 7e2dc5d..e6686d8 100644
--- a/cogl/winsys/cogl-winsys-wgl.c
+++ b/cogl/winsys/cogl-winsys-wgl.c
@@ -579,9 +579,14 @@ get_wgl_extensions_string (HDC dc)
      GL_EXT_SWAP_CONTROL so if the extension to get the list of WGL
      extensions isn't supported then we can at least fake it to
      support the swap control extension */
-  if (_cogl_check_extension ("WGL_EXT_swap_control",
-                             _cogl_context_get_gl_extensions (ctx)))
-    return "WGL_EXT_swap_control";
+  {
+    char **extensions = _cogl_context_get_gl_extensions (ctx);
+    CoglBool have_ext = _cogl_check_extension ("WGL_EXT_swap_control",
+                                               extensions);
+    g_strfreev (extensions);
+    if (have_ext)
+      return "WGL_EXT_swap_control";
+  }
 
   return NULL;
 }
@@ -612,13 +617,15 @@ update_winsys_features (CoglContext *context, CoglError **error)
 
   if (wgl_extensions)
     {
+      char **split_extensions = g_strsplit (wgl_extensions);
+
       COGL_NOTE (WINSYS, "  WGL Extensions: %s", wgl_extensions);
 
       for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++)
         if (_cogl_feature_check (context->display->renderer,
                                  "WGL", winsys_feature_data + i, 0, 0,
                                  COGL_DRIVER_GL,
-                                 wgl_extensions,
+                                 split_extensions,
                                  wgl_renderer))
           {
             context->feature_flags |= winsys_feature_data[i].feature_flags;
@@ -627,6 +634,8 @@ update_winsys_features (CoglContext *context, CoglError **error)
                               winsys_feature_data[i].winsys_feature,
                               TRUE);
           }
+
+      g_strfreev (split_extensions);
     }
 
   return TRUE;
diff --git a/tests/conform/run-tests.sh b/tests/conform/run-tests.sh
index fc476a8..266f1c6 100755
--- a/tests/conform/run-tests.sh
+++ b/tests/conform/run-tests.sh
@@ -67,8 +67,8 @@ TITLE_FORMAT="%35s"
 printf $TITLE_FORMAT "Test"
 
 if test $HAVE_GL -eq 1; then
-  GL_FORMAT=" %6s %8s %7s %6s"
-  printf "$GL_FORMAT" "GL+FF" "GL+ARBFP" "GL+GLSL" "GL-NPT"
+  GL_FORMAT=" %6s %8s %7s %6s %6s"
+  printf "$GL_FORMAT" "GL+FF" "GL+ARBFP" "GL+GLSL" "GL-NPT" "GL3"
 fi
 if test $HAVE_GLES2 -eq 1; then
   GLES2_FORMAT=" %6s %7s"
@@ -101,6 +101,10 @@ do
     export COGL_DRIVER=gl
     export COGL_DEBUG=disable-npot-textures
     run_test $test gl_npot
+
+    export COGL_DRIVER=gl3
+    export COGL_DEBUG=
+    run_test $test gl3
   fi
 
   if test $HAVE_GLES2 -eq 1; then
@@ -119,7 +123,8 @@ do
       "`get_status $gl_ff_result`" \
       "`get_status $gl_arbfp_result`" \
       "`get_status $gl_glsl_result`" \
-      "`get_status $gl_npot_result`"
+      "`get_status $gl_npot_result`" \
+      "`get_status $gl3_result`"
   fi
   if test $HAVE_GLES2 -eq 1; then
     printf "$GLES2_FORMAT" \
diff --git a/tests/conform/test-utils.c b/tests/conform/test-utils.c
index bbf9b05..84cb23b 100644
--- a/tests/conform/test-utils.c
+++ b/tests/conform/test-utils.c
@@ -53,7 +53,8 @@ test_utils_init (TestFlags flags)
   renderer = cogl_display_get_renderer (display);
 
   if (flags & TEST_REQUIREMENT_GL &&
-      cogl_renderer_get_driver (renderer) != COGL_DRIVER_GL)
+      cogl_renderer_get_driver (renderer) != COGL_DRIVER_GL &&
+      cogl_renderer_get_driver (renderer) != COGL_DRIVER_GL3)
     {
       missing_requirement = TRUE;
     }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]