[Cogl] [PATCH] Add a GL 3 driver

Robert Bragg robert at sixbynine.org
Mon Oct 1 05:34:49 PDT 2012


This is really cool, and looks good to land to me so we don't have to
worry about re-basing it. Once we have a glsl frontend in Cogl that
will hopefully let us address the inconsistencies between GL versions
in supporting single component textures.

Reviewed-by: Robert Bragg <robert at linux.intel.com>

thanks,
- Robert

On Sat, Sep 29, 2012 at 2:00 AM, Neil Roberts <neil at linux.intel.com> wrote:
> 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.
> ---
>  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-texture.c                                |   2 +-
>  cogl/cogl.c                                        |  25 ++---
>  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                 |  77 ++++++++++----
>  .../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    |  13 +++
>  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 +-
>  42 files changed, 475 insertions(+), 227 deletions(-)
>
> diff --git a/cogl-pango/cogl-pango-display-list.c b/cogl-pango/cogl-pango-display-list.c
> index 52b6b25..d77b6fb 100644
> --- a/cogl-pango/cogl-pango-display-list.c
> +++ b/cogl-pango/cogl-pango-display-list.c
> @@ -349,7 +349,7 @@ emit_vertex_buffer_geometry (CoglFramebuffer *fb,
>                                                   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 afb9f14..7d4c2e5 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 53239f4..4ea6687 100644
> --- a/cogl/cogl-context-private.h
> +++ b/cogl/cogl-context-private.h
> @@ -341,7 +341,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 1d02f1f..325a58a 100644
> --- a/cogl/cogl-context.c
> +++ b/cogl/cogl-context.c
> @@ -248,9 +248,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... */
> @@ -347,8 +345,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
> @@ -358,6 +355,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);
> @@ -407,13 +420,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));
>
> @@ -572,38 +585,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 =
> @@ -621,46 +641,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 10562cf..1f638a6 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 fd284e2..1207f9e 100644
> --- a/cogl/cogl-feature-private.h
> +++ b/cogl/cogl-feature-private.h
> @@ -85,13 +85,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 41f5d18..8e4f6f3 100644
> --- a/cogl/cogl-framebuffer.c
> +++ b/cogl/cogl-framebuffer.c
> @@ -1540,7 +1540,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))
> @@ -1551,7 +1552,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 2d6e089..97f10d8 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_domain (void);
>
> diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c
> index a467c33..4faed16 100644
> --- a/cogl/cogl-journal.c
> +++ b/cogl/cogl-journal.c
> @@ -302,7 +302,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,
> @@ -639,7 +639,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 22afd7c..df1ec48 100644
> --- a/cogl/cogl-matrix-stack.c
> +++ b/cogl/cogl-matrix-stack.c
> @@ -794,8 +794,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)
> @@ -835,8 +834,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 fddc6c9..c4ec4ea 100644
> --- a/cogl/cogl-pipeline-state.c
> +++ b/cogl/cogl-pipeline-state.c
> @@ -708,7 +708,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 ac7b1cf..85264ab 100644
> --- a/cogl/cogl-pipeline.c
> +++ b/cogl/cogl-pipeline.c
> @@ -2641,8 +2641,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;
> @@ -2654,7 +2656,7 @@ _cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context)
>    CoglPipelineState state = (COGL_PIPELINE_STATE_LAYERS |
>                               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 9006892..a78435b 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 8b4413e..2e2a3df 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 e00e682..ebb055e 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-texture.c b/cogl/cogl-texture.c
> index 2d54216..12be86e 100644
> --- a/cogl/cogl-texture.c
> +++ b/cogl/cogl-texture.c
> @@ -176,7 +176,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 ff9f66f..62d511e 100644
> --- a/cogl/cogl.c
> +++ b/cogl/cogl.c
> @@ -90,26 +90,13 @@ _cogl_gl_error_to_string (GLenum error_code)
>  #endif /* COGL_GL_DEBUG */
>
>  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;
>  }
> diff --git a/cogl/driver/gl/cogl-attribute-gl.c b/cogl/driver/gl/cogl-attribute-gl.c
> index c85b179..af89380 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 933b943..9b9475e 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 6d743b1..622e4be 100644
> --- a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
> +++ b/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
> @@ -873,10 +873,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,
> @@ -1011,8 +1011,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
>
> @@ -1037,10 +1037,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 83dc197..fe4558b 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 */
> @@ -653,7 +653,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
> @@ -834,7 +835,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 ee0d699..5a62a28 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 e702e22..6387473 100644
> --- a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
> +++ b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
> @@ -223,7 +223,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,
> @@ -429,7 +430,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 52169ec..ecb3d1e 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_gl_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 d49040f..4b961b7 100644
> --- a/cogl/driver/gl/gl/cogl-driver-gl.c
> +++ b/cogl/driver/gl/gl/cogl-driver-gl.c
> @@ -290,10 +290,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))
>      {
> @@ -308,8 +308,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))
> @@ -342,32 +340,49 @@ _cogl_driver_update_features (CoglContext *ctx,
>                                CoglError **error)
>  {
>    CoglPrivateFeatureFlags private_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);
>
> @@ -390,8 +405,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,
> @@ -422,7 +435,10 @@ _cogl_driver_update_features (CoglContext *ctx,
>      private_flags |= COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
>
>    if (ctx->glGenRenderbuffers)
> -    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
> +    {
> +      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
> +      private_flags |= COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS;
> +    }
>
>    if (ctx->glBlitFramebuffer)
>      private_flags |= COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT;
> @@ -439,6 +455,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)
>      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_ARBFP, TRUE);
>
> @@ -512,9 +532,24 @@ _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;
>
> +  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 24782e7..31e715b 100644
> --- a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
> +++ b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
> @@ -48,7 +48,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 08d1a79..c38f090 100644
> --- a/cogl/driver/gl/gles/cogl-driver-gles.c
> +++ b/cogl/driver/gl/gles/cogl-driver-gles.c
> @@ -190,7 +190,7 @@ _cogl_driver_update_features (CoglContext *context,
>                                CoglError **error)
>  {
>    CoglPrivateFeatureFlags private_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
> @@ -201,23 +201,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 */,
> @@ -250,9 +257,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 */
>    COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE);
> @@ -313,6 +327,8 @@ _cogl_driver_update_features (CoglContext *context,
>    /* Cache features */
>    context->private_feature_flags |= private_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 ae46e61..2ff7687 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 c20f925..0450728 100644
> --- a/cogl/winsys/cogl-winsys-glx-feature-functions.h
> +++ b/cogl/winsys/cogl-winsys-glx-feature-functions.h
> @@ -105,3 +105,16 @@ 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)
> +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 ff9b1fd..29d8cc9 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;
>
> @@ -417,11 +419,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))
>        {
>          if (winsys_feature_data[i].winsys_feature)
> @@ -430,6 +434,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)
> @@ -605,6 +611,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)
>  {
> @@ -642,12 +678,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 8def1a9..ccb0764 100644
> --- a/cogl/winsys/cogl-winsys-sdl.c
> +++ b/cogl/winsys/cogl-winsys-sdl.c
> @@ -161,6 +161,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 390ab2b..3ebecf3 100644
> --- a/cogl/winsys/cogl-winsys-sdl2.c
> +++ b/cogl/winsys/cogl-winsys-sdl2.c
> @@ -156,6 +156,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 */
> @@ -194,6 +196,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]))
> @@ -203,6 +206,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 6c55bf7..8ec7dc7 100644
> --- a/tests/conform/test-utils.c
> +++ b/tests/conform/test-utils.c
> @@ -52,7 +52,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;
>      }
> --
> 1.7.11.3.g3c3efa5
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl


More information about the Cogl mailing list