[cogl/wip/rib/gles2-context] Adds initial GLES2 integration support



commit 7fc90333089f69f4e3e180360062531951e0e0c0
Author: Robert Bragg <robert linux intel com>
Date:   Tue Mar 6 03:21:30 2012 +0000

    Adds initial GLES2 integration support
    
    This makes it possible to integrate existing GLES2 code with
    applications using Cogl as the rendering api.
    
    Currently all GLES2 usage is handled with separate GLES2 contexts to
    ensure that GLES2 api usage doesn't interfere with Cogl's own use of
    OpenGL[ES]. The api has been designed though so we can provide tighter
    integration later.
    
    The api would allow us to support GLES2 virtualized on top of an
    OpenGL/GLX driver as well as GLES2 virtualized on the core rendering api
    of Cogl itself. Virtualizing the GLES2 support on Cogl will allow us to
    take advantage of Cogl debugging facilities as well as let us avoid the
    cost of GLES2 context switches which are *very* expensive with some
    drivers.
    
    As as a side effect of this patch Cogl can also now be used as a
    portable window system binding API for GLES2 as an alternative to EGL.
    
    Parts of this patch are based on work done by Tomeu Vizoso
    <tomeu vizoso collabora com> who did the first iteration of adding GLES2
    API support to Cogl so that WebGL support could be added to
    webkit-clutter.

 cogl/Makefile.am                      |   13 ++
 cogl/cogl-context-private.h           |    7 +
 cogl/cogl-context.c                   |   10 +-
 cogl/cogl-context.h                   |    4 +
 cogl/cogl-framebuffer-private.h       |   30 +++-
 cogl/cogl-framebuffer.c               |  366 +++++++++++++++++++++------------
 cogl/cogl-gles2-context-private.h     |   61 ++++++
 cogl/cogl-gles2-context.c             |  336 ++++++++++++++++++++++++++++++
 cogl/cogl-gles2-context.h             |   81 ++++++++
 cogl/cogl.h                           |    3 +-
 cogl/winsys/cogl-winsys-egl-android.c |    8 +-
 cogl/winsys/cogl-winsys-egl-gdl.c     |    8 +-
 cogl/winsys/cogl-winsys-egl-kms.c     |   21 +-
 cogl/winsys/cogl-winsys-egl-null.c    |    8 +-
 cogl/winsys/cogl-winsys-egl-private.h |   12 +-
 cogl/winsys/cogl-winsys-egl-wayland.c |   10 +-
 cogl/winsys/cogl-winsys-egl-x11.c     |    8 +-
 cogl/winsys/cogl-winsys-egl.c         |  189 ++++++++++++++++--
 cogl/winsys/cogl-winsys-private.h     |   18 ++
 examples/Makefile.am                  |    5 +-
 examples/cogl-gles2-context.c         |  131 ++++++++++++
 examples/cogl-info.c                  |    6 +
 22 files changed, 1151 insertions(+), 184 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 853e561..d19d558 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -89,6 +89,7 @@ cogl_experimental_h = \
 	$(srcdir)/cogl-pipeline-state.h 	\
 	$(srcdir)/cogl-pipeline-layer-state.h 	\
 	$(srcdir)/cogl-snippet.h		\
+	$(srcdir)/cogl-gles2-context.h		\
 	$(srcdir)/cogl2-path.h 			\
 	$(srcdir)/cogl-index-buffer.h 		\
 	$(srcdir)/cogl-attribute-buffer.h 	\
@@ -115,6 +116,14 @@ cogl_experimental_h = \
 	$(srcdir)/cogl2-compatibility.h		\
 	$(NULL)
 
+cogl_gl_prototypes_h = \
+	$(srcdir)/gl-prototypes/cogl-gles2-functions.h		\
+	$(srcdir)/gl-prototypes/cogl-core-functions.h		\
+	$(srcdir)/gl-prototypes/cogl-in-gles-core-functions.h	\
+	$(srcdir)/gl-prototypes/cogl-in-gles2-core-functions.h	\
+	$(srcdir)/gl-prototypes/cogl-glsl-functions.h		\
+	$(NULL)
+
 # driver sources
 cogl_driver_sources =
 
@@ -350,6 +359,7 @@ cogl_sources_c = \
 	$(srcdir)/gl-prototypes/cogl-in-gles2-core-functions.h	\
 	$(srcdir)/gl-prototypes/cogl-fixed-functions.h	\
 	$(srcdir)/gl-prototypes/cogl-glsl-functions.h	\
+	$(srcdir)/cogl-gles2-context.c			\
 	$(NULL)
 
 if USE_GLIB
@@ -477,6 +487,9 @@ coglincludedir = $(includedir)/cogl/cogl
 coglinclude_HEADERS = $(cogl_headers) $(cogl_experimental_h)
 nodist_coglinclude_HEADERS = cogl-defines.h cogl-enum-types.h
 
+cogl_proto_includedir = $(includedir)/cogl/cogl/gl-prototypes
+cogl_proto_include_HEADERS = $(cogl_gl_prototypes_h)
+
 dist-hook: ../build/win32/vs9/cogl.vcproj ../build/win32/vs10/cogl.vcxproj ../build/win32/vs10/cogl.vcxproj.filters ../build/win32/gen-enums.bat
 
 # I know those filters below don't look nice, but this is to ensure the right files are in the Project files only *once*
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 6d92faf..d7ecb10 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -46,6 +46,7 @@
 #include "cogl-texture-2d.h"
 #include "cogl-texture-3d.h"
 #include "cogl-texture-rectangle.h"
+#include "cogl-framebuffer-private.h"
 
 typedef struct
 {
@@ -168,6 +169,12 @@ struct _CoglContext
   CoglFramebuffer  *current_draw_buffer;
   CoglFramebuffer  *current_read_buffer;
 
+  gboolean have_last_offscreen_allocate_flags;
+  CoglOffscreenAllocateFlags last_offscreen_allocate_flags;
+
+  CoglGLES2Context *current_gles2_context;
+  GQueue *gles2_context_stack;
+
   /* Primitives */
   CoglPath         *current_path;
   CoglPipeline     *stencil_pipeline;
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 8b1ea2b..32a247d 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -156,7 +156,7 @@ cogl_context_new (CoglDisplay *display,
 #endif
 
   /* Allocate context memory */
-  context = g_malloc (sizeof (CoglContext));
+  context = g_malloc0 (sizeof (CoglContext));
 
   /* Convert the context into an object immediately in case any of the
      code below wants to verify that the context pointer is a valid
@@ -293,6 +293,8 @@ cogl_context_new (CoglDisplay *display,
   context->current_draw_buffer_state_flushed = 0;
   context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;
 
+  context->gles2_context_stack = g_queue_new ();
+
   context->journal_flush_attributes_array =
     g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
   context->journal_clip_bounds = NULL;
@@ -466,6 +468,12 @@ _cogl_context_free (CoglContext *context)
   if (context->blit_texture_pipeline)
     cogl_handle_unref (context->blit_texture_pipeline);
 
+  if (context->gles2_context_stack)
+    {
+      g_warn_if_fail (context->gles2_context_stack->length == 0);
+      g_queue_free (context->gles2_context_stack);
+    }
+
   if (context->journal_flush_attributes_array)
     g_array_free (context->journal_flush_attributes_array, TRUE);
   if (context->journal_clip_bounds)
diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h
index e2120d7..51a435f 100644
--- a/cogl/cogl-context.h
+++ b/cogl/cogl-context.h
@@ -203,6 +203,9 @@ cogl_is_context (void *object);
  * @COGL_FEATURE_ID_SWAP_BUFFERS_EVENT:
  *     Available if the window system supports reporting an event
  *     for swap buffer completions.
+ * @COGL_FEATURE_ID_GLES2_CONTEXT: Whether creating new GLES2 contexts is
+ *    suported.
+ *
  *
  * All the capabilities that can vary between different GPUs supported
  * by Cogl. Applications that depend on any of these features should explicitly
@@ -230,6 +233,7 @@ typedef enum _CoglFeatureID
   COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE,
   COGL_FEATURE_ID_MIRRORED_REPEAT,
   COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
+  COGL_FEATURE_ID_GLES2_CONTEXT,
 
   /*< private > */
   _COGL_N_FEATURE_IDS
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index 0081a2f..43bd47f 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -155,17 +155,33 @@ struct _CoglFramebuffer
   gboolean            clear_clip_dirty;
 };
 
+typedef enum {
+  COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL    = 1L<<0,
+  COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH24_STENCIL8 = 1L<<1,
+  COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH            = 1L<<2,
+  COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL          = 1L<<3
+} CoglOffscreenAllocateFlags;
+
+typedef struct _CoglGLFramebuffer
+{
+  GLuint fbo_handle;
+  GList *renderbuffers;
+  int samples_per_pixel;
+} CoglGLFramebuffer;
+
 struct _CoglOffscreen
 {
   CoglFramebuffer  _parent;
-  GLuint          fbo_handle;
-  GSList          *renderbuffers;
+
+  CoglGLFramebuffer gl_framebuffer;
 
   CoglTexture    *texture;
   int             texture_level;
   int             texture_level_width;
   int             texture_level_height;
 
+  CoglOffscreenAllocateFlags allocation_flags;
+
   /* FIXME: _cogl_offscreen_new_to_texture_full should be made to use
    * fb->config to configure if we want a depth or stencil buffer so
    * we can get rid of these flags */
@@ -389,4 +405,14 @@ _cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
                                            int n_attributes,
                                            CoglDrawFlags flags);
 
+gboolean
+_cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx,
+                                       CoglTexture *texture,
+                                       int texture_level,
+                                       int texture_level_width,
+                                       int texture_level_height,
+                                       CoglFramebufferConfig *config,
+                                       CoglOffscreenAllocateFlags flags,
+                                       CoglGLFramebuffer *gl_framebuffer);
+
 #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 799f406..130a0c6 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -109,13 +109,6 @@
 #endif
 
 
-typedef enum {
-  _TRY_DEPTH_STENCIL    = 1L<<0,
-  _TRY_DEPTH24_STENCIL8 = 1L<<1,
-  _TRY_DEPTH            = 1L<<2,
-  _TRY_STENCIL          = 1L<<3
-} TryFBOFlags;
-
 typedef struct _CoglFramebufferStackEntry
 {
   CoglFramebuffer *draw_buffer;
@@ -792,23 +785,31 @@ cogl_offscreen_new_to_texture (CoglTexture *texture)
 }
 
 static void
+delete_renderbuffers (CoglContext *ctx, GList *renderbuffers)
+{
+  GList *l;
+
+  for (l = renderbuffers; l; l = l->next)
+    {
+      GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
+      GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
+    }
+
+  g_list_free (renderbuffers);
+}
+
+static void
 _cogl_offscreen_free (CoglOffscreen *offscreen)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen);
   CoglContext *ctx = framebuffer->context;
-  GSList *l;
 
   /* Chain up to parent */
   _cogl_framebuffer_free (framebuffer);
 
-  for (l = offscreen->renderbuffers; l; l = l->next)
-    {
-      GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
-      GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
-    }
-  g_slist_free (offscreen->renderbuffers);
+  delete_renderbuffers (ctx, offscreen->gl_framebuffer.renderbuffers);
 
-  GE (ctx, glDeleteFramebuffers (1, &offscreen->fbo_handle));
+  GE (ctx, glDeleteFramebuffers (1, &offscreen->gl_framebuffer.fbo_handle));
 
   if (offscreen->texture != COGL_INVALID_HANDLE)
     cogl_object_unref (offscreen->texture);
@@ -816,72 +817,20 @@ _cogl_offscreen_free (CoglOffscreen *offscreen)
   g_free (offscreen);
 }
 
-static gboolean
-try_creating_fbo (CoglOffscreen *offscreen,
-                  TryFBOFlags flags)
+static GList *
+try_creating_renderbuffers (CoglContext *ctx,
+                            int width,
+                            int height,
+                            CoglOffscreenAllocateFlags flags,
+                            int n_samples)
 {
-  CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
-  CoglContext *ctx = fb->context;
+  GList *renderbuffers = NULL;
   GLuint gl_depth_stencil_handle;
-  GLuint gl_depth_handle;
-  GLuint gl_stencil_handle;
-  GLuint tex_gl_handle;
-  GLenum tex_gl_target;
-  GLuint fbo_gl_handle;
-  GLenum status;
-  int n_samples;
-  int height;
-  int width;
-
-  if (!cogl_texture_get_gl_texture (offscreen->texture,
-                                    &tex_gl_handle, &tex_gl_target))
-    return FALSE;
 
-  if (tex_gl_target != GL_TEXTURE_2D
-#ifdef HAVE_COGL_GL
-      && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
-#endif
-      )
-    return FALSE;
-
-  if (fb->config.samples_per_pixel)
-    {
-      if (!ctx->glFramebufferTexture2DMultisampleIMG)
-        return FALSE;
-      n_samples = fb->config.samples_per_pixel;
-    }
-  else
-    n_samples = 0;
-
-  width = offscreen->texture_level_width;
-  height = offscreen->texture_level_height;
-
-  /* We are about to generate and bind a new fbo, so we pretend to
-   * change framebuffer state so that the old framebuffer will be
-   * rebound again before drawing. */
-  ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
-
-  /* Generate framebuffer */
-  ctx->glGenFramebuffers (1, &fbo_gl_handle);
-  GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle));
-  offscreen->fbo_handle = fbo_gl_handle;
-
-  if (n_samples)
-    {
-      GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER,
-                                                     GL_COLOR_ATTACHMENT0,
-                                                     tex_gl_target, tex_gl_handle,
-                                                     n_samples,
-                                                     offscreen->texture_level));
-    }
-  else
-    GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                     tex_gl_target, tex_gl_handle,
-                                     offscreen->texture_level));
-
-  if (flags & (_TRY_DEPTH_STENCIL | _TRY_DEPTH24_STENCIL8))
+  if (flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL |
+               COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH24_STENCIL8))
     {
-      GLenum format = ((flags & _TRY_DEPTH_STENCIL) ?
+      GLenum format = ((flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL) ?
                        GL_DEPTH_STENCIL : GL_DEPTH24_STENCIL8);
 
       /* Create a renderbuffer for depth and stenciling */
@@ -904,13 +853,15 @@ try_creating_fbo (CoglOffscreen *offscreen,
                                           GL_DEPTH_ATTACHMENT,
                                           GL_RENDERBUFFER,
                                           gl_depth_stencil_handle));
-      offscreen->renderbuffers =
-        g_slist_prepend (offscreen->renderbuffers,
-                         GUINT_TO_POINTER (gl_depth_stencil_handle));
+      renderbuffers =
+        g_list_prepend (renderbuffers,
+                        GUINT_TO_POINTER (gl_depth_stencil_handle));
     }
 
-  if (flags & _TRY_DEPTH)
+  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)
     {
+      GLuint gl_depth_handle;
+
       GE (ctx, glGenRenderbuffers (1, &gl_depth_handle));
       GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle));
       /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's
@@ -927,13 +878,14 @@ try_creating_fbo (CoglOffscreen *offscreen,
       GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
                                           GL_DEPTH_ATTACHMENT,
                                           GL_RENDERBUFFER, gl_depth_handle));
-      offscreen->renderbuffers =
-        g_slist_prepend (offscreen->renderbuffers,
-                         GUINT_TO_POINTER (gl_depth_handle));
+      renderbuffers =
+        g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle));
     }
 
-  if (flags & _TRY_STENCIL)
+  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL)
     {
+      GLuint gl_stencil_handle;
+
       GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle));
       GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
       if (n_samples)
@@ -948,28 +900,91 @@ try_creating_fbo (CoglOffscreen *offscreen,
       GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
                                           GL_STENCIL_ATTACHMENT,
                                           GL_RENDERBUFFER, gl_stencil_handle));
-      offscreen->renderbuffers =
-        g_slist_prepend (offscreen->renderbuffers,
-                         GUINT_TO_POINTER (gl_stencil_handle));
+      renderbuffers =
+        g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle));
+    }
+
+  return renderbuffers;
+}
+
+/*
+ * NB: This function may be called with a standalone GLES2 context
+ * bound so we can create a shadow framebuffer that wraps the same
+ * CoglTexture as the given CoglOffscreen. This function shouldn't
+ * modify anything in
+ */
+static gboolean
+try_creating_fbo (CoglContext *ctx,
+                  CoglTexture *texture,
+                  int texture_level,
+                  int texture_level_width,
+                  int texture_level_height,
+                  CoglFramebufferConfig *config,
+                  CoglOffscreenAllocateFlags flags,
+                  CoglGLFramebuffer *gl_framebuffer)
+{
+  GLuint tex_gl_handle;
+  GLenum tex_gl_target;
+  GLenum status;
+  int n_samples;
+
+  if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target))
+    return FALSE;
+
+  if (tex_gl_target != GL_TEXTURE_2D
+#ifdef HAVE_COGL_GL
+      && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
+#endif
+      )
+    return FALSE;
+
+  if (config->samples_per_pixel)
+    {
+      if (!ctx->glFramebufferTexture2DMultisampleIMG)
+        return FALSE;
+      n_samples = config->samples_per_pixel;
     }
+  else
+    n_samples = 0;
+
+  /* We are about to generate and bind a new fbo, so we pretend to
+   * change framebuffer state so that the old framebuffer will be
+   * rebound again before drawing. */
+  ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
+
+  /* Generate framebuffer */
+  ctx->glGenFramebuffers (1, &gl_framebuffer->fbo_handle);
+  GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_framebuffer->fbo_handle));
+
+  if (n_samples)
+    {
+      GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER,
+                                                     GL_COLOR_ATTACHMENT0,
+                                                     tex_gl_target, tex_gl_handle,
+                                                     n_samples,
+                                                     texture_level));
+    }
+  else
+    GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                     tex_gl_target, tex_gl_handle,
+                                     texture_level));
+
+  gl_framebuffer->renderbuffers =
+    try_creating_renderbuffers (ctx,
+                                texture_level_width,
+                                texture_level_height,
+                                flags,
+                                n_samples);
 
   /* Make sure it's complete */
   status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER);
 
   if (status != GL_FRAMEBUFFER_COMPLETE)
     {
-      GSList *l;
-
-      GE (ctx, glDeleteFramebuffers (1, &fbo_gl_handle));
+      GE (ctx, glDeleteFramebuffers (1, &gl_framebuffer->fbo_handle));
 
-      for (l = offscreen->renderbuffers; l; l = l->next)
-        {
-          GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
-          GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
-        }
-
-      g_slist_free (offscreen->renderbuffers);
-      offscreen->renderbuffers = NULL;
+      delete_renderbuffers (ctx, gl_framebuffer->renderbuffers);
+      gl_framebuffer->renderbuffers = NULL;
 
       return FALSE;
     }
@@ -986,21 +1001,40 @@ try_creating_fbo (CoglOffscreen *offscreen,
                                                       attachment,
                                                       pname,
                                                       &texture_samples) );
-      fb->samples_per_pixel = texture_samples;
+      gl_framebuffer->samples_per_pixel = texture_samples;
     }
 
   return TRUE;
 }
 
+gboolean
+_cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx,
+                                       CoglTexture *texture,
+                                       int texture_level,
+                                       int texture_level_width,
+                                       int texture_level_height,
+                                       CoglFramebufferConfig *config,
+                                       CoglOffscreenAllocateFlags flags,
+                                       CoglGLFramebuffer *gl_framebuffer)
+{
+  return try_creating_fbo (ctx,
+                           texture,
+                           texture_level,
+                           texture_level_width,
+                           texture_level_height,
+                           config,
+                           flags,
+                           gl_framebuffer);
+}
+
 static gboolean
 _cogl_offscreen_allocate (CoglOffscreen *offscreen,
                           GError **error)
 {
   CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
   CoglContext *ctx = fb->context;
-  static TryFBOFlags flags;
-  static gboolean have_working_flags = FALSE;
-  gboolean fbo_created;
+  CoglOffscreenAllocateFlags flags;
+  CoglGLFramebuffer *gl_framebuffer = &offscreen->gl_framebuffer;
 
   /* XXX: The framebuffer_object spec isn't clear in defining whether attaching
    * a texture as a renderbuffer with mipmap filtering enabled while the
@@ -1014,41 +1048,106 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
    */
   _cogl_texture_set_filters (offscreen->texture, GL_NEAREST, GL_NEAREST);
 
-  if ((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL))
-    fbo_created = try_creating_fbo (offscreen, 0);
-  else
+  if (((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) &&
+       try_creating_fbo (ctx,
+                         offscreen->texture,
+                         offscreen->texture_level,
+                         offscreen->texture_level_width,
+                         offscreen->texture_level_height,
+                         &fb->config,
+                         flags = 0,
+                         gl_framebuffer)) ||
+
+      (ctx->have_last_offscreen_allocate_flags &&
+       try_creating_fbo (ctx,
+                         offscreen->texture,
+                         offscreen->texture_level,
+                         offscreen->texture_level_width,
+                         offscreen->texture_level_height,
+                         &fb->config,
+                         ctx->last_offscreen_allocate_flags,
+                         gl_framebuffer)) ||
+
+      ((ctx->private_feature_flags &
+        COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) &&
+       try_creating_fbo (ctx,
+                         offscreen->texture,
+                         offscreen->texture_level,
+                         offscreen->texture_level_width,
+                         offscreen->texture_level_height,
+                         &fb->config,
+                         flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL,
+                         gl_framebuffer)) ||
+
+      ((ctx->private_feature_flags &
+        COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL) &&
+       try_creating_fbo (ctx,
+                         offscreen->texture,
+                         offscreen->texture_level,
+                         offscreen->texture_level_width,
+                         offscreen->texture_level_height,
+                         &fb->config,
+                         flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH24_STENCIL8,
+                         gl_framebuffer)) ||
+
+      try_creating_fbo (ctx,
+                        offscreen->texture,
+                        offscreen->texture_level,
+                        offscreen->texture_level_width,
+                        offscreen->texture_level_height,
+                        &fb->config,
+                        flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH |
+                        COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
+                        gl_framebuffer) ||
+
+      try_creating_fbo (ctx,
+                        offscreen->texture,
+                        offscreen->texture_level,
+                        offscreen->texture_level_width,
+                        offscreen->texture_level_height,
+                        &fb->config,
+                        flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
+                        gl_framebuffer) ||
+
+      try_creating_fbo (ctx,
+                        offscreen->texture,
+                        offscreen->texture_level,
+                        offscreen->texture_level_width,
+                        offscreen->texture_level_height,
+                        &fb->config,
+                        flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH,
+                        gl_framebuffer) ||
+
+      try_creating_fbo (ctx,
+                        offscreen->texture,
+                        offscreen->texture_level,
+                        offscreen->texture_level_width,
+                        offscreen->texture_level_height,
+                        &fb->config,
+                        flags = 0,
+                        gl_framebuffer))
     {
-      if ((have_working_flags &&
-           try_creating_fbo (offscreen, flags)) ||
-          ((ctx->private_feature_flags &
-            COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) &&
-           try_creating_fbo (offscreen, flags = _TRY_DEPTH_STENCIL)) ||
-          ((ctx->private_feature_flags &
-            COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL) &&
-           try_creating_fbo (offscreen, flags = _TRY_DEPTH24_STENCIL8)) ||
-          try_creating_fbo (offscreen, flags = _TRY_DEPTH | _TRY_STENCIL) ||
-          try_creating_fbo (offscreen, flags = _TRY_STENCIL) ||
-          try_creating_fbo (offscreen, flags = _TRY_DEPTH) ||
-          try_creating_fbo (offscreen, flags = 0))
-        {
-          /* Record that the last set of flags succeeded so that we can
-             try that set first next time */
-          have_working_flags = TRUE;
-          fbo_created = TRUE;
-        }
-      else
-        fbo_created = FALSE;
-    }
+      fb->samples_per_pixel = gl_framebuffer->samples_per_pixel;
+
+      /* Record that the last set of flags succeeded so that we can
+         try that set first next time */
+      ctx->last_offscreen_allocate_flags = flags;
+      ctx->have_last_offscreen_allocate_flags = TRUE;
 
-  if (!fbo_created)
+      /* Save the flags we managed so successfully allocate the
+       * renderbuffers with in case we need to make renderbuffers for a
+       * GLES2 context later */
+      offscreen->allocation_flags = flags;
+
+      return TRUE;
+    }
+  else
     {
       g_set_error (error, COGL_FRAMEBUFFER_ERROR,
                    COGL_FRAMEBUFFER_ERROR_ALLOCATE,
                    "Failed to create an OpenGL framebuffer object");
       return FALSE;
     }
-
-  return TRUE;
 }
 
 gboolean
@@ -1329,8 +1428,11 @@ bind_gl_framebuffer (CoglContext *ctx,
                      CoglFramebuffer *framebuffer)
 {
   if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
-    GE (ctx, glBindFramebuffer (target,
-                           COGL_OFFSCREEN (framebuffer)->fbo_handle));
+    {
+      CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer);
+      GE (ctx, glBindFramebuffer (target,
+                                  offscreen->gl_framebuffer.fbo_handle));
+    }
   else
     {
       const CoglWinsysVtable *winsys =
diff --git a/cogl/cogl-gles2-context-private.h b/cogl/cogl-gles2-context-private.h
new file mode 100644
index 0000000..f3f9b47
--- /dev/null
+++ b/cogl/cogl-gles2-context-private.h
@@ -0,0 +1,61 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Tomeu Vizoso <tomeu vizoso collabora com>
+ *  Robert Bragg <robert linux intel com>
+ *
+ */
+
+#ifndef __COGL_GLES2_CONTEXT_PRIVATE_H
+#define __COGL_GLES2_CONTEXT_PRIVATE_H
+
+#include <glib.h>
+
+#include "cogl-object-private.h"
+#include "cogl-framebuffer-private.h"
+
+typedef struct _CoglGLES2Framebuffer
+{
+  CoglFramebuffer *original;
+  CoglGLFramebuffer gl_framebuffer;
+} CoglGLES2Framebuffer;
+
+struct _CoglGLES2Context
+{
+  CoglObject _parent;
+
+  CoglContext *context;
+
+  CoglGLES2Framebuffer *read_buffer;
+  CoglGLES2Framebuffer *write_buffer;
+
+  GLuint current_fbo_handle;
+
+  GList *foreign_framebuffers;
+
+  CoglGLES2Vtable *vtable;
+
+  void *winsys;
+};
+
+#endif /* __COGL_GLES2_CONTEXT_PRIVATE_H */
diff --git a/cogl/cogl-gles2-context.c b/cogl/cogl-gles2-context.c
new file mode 100644
index 0000000..de1d1aa
--- /dev/null
+++ b/cogl/cogl-gles2-context.c
@@ -0,0 +1,336 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Tomeu Vizoso <tomeu vizoso collabora com>
+ *  Robert Bragg <robert linux intel com>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-gles2-context.h"
+#include "cogl-gles2-context-private.h"
+
+#include "cogl-context-private.h"
+#include "cogl-display-private.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-onscreen-template-private.h"
+#include "cogl-renderer-private.h"
+#include "cogl-swap-chain-private.h"
+#include "cogl-texture-2d-private.h"
+#include "winsys/cogl-winsys-egl-private.h"
+
+static void _cogl_gles2_context_free (CoglGLES2Context *gles2_context);
+
+COGL_OBJECT_DEFINE (GLES2Context, gles2_context);
+
+static CoglGLES2Context *current_gles2_context;
+
+GQuark
+_cogl_gles2_context_error_quark (void)
+{
+  return g_quark_from_static_string ("cogl-gles2-context-error-quark");
+}
+
+#define COGL_GLES2_CONTEXT_ERROR (_cogl_gles2_context_error_quark ())
+
+typedef enum { /*< prefix=COGL_GLES2_CONTEXT_ERROR >*/
+  COGL_GLES2_CONTEXT_ERROR_NEW,
+  COGL_GLES2_CONTEXT_ERROR_PUSH_CONTEXT,
+} CoglGLES2ContextError;
+
+/* We wrap glBindFramebuffer so that when framebuffer 0 is bound
+ * we can instead bind the write_framebuffer passed to
+ * cogl_push_gles2_context().
+ */
+static void
+gl_bind_framebuffer_wrapper (GLenum target, GLuint framebuffer)
+{
+  CoglGLES2Context *gles2_ctx = current_gles2_context;
+
+  gles2_ctx->current_fbo_handle = framebuffer;
+
+  if (framebuffer == 0)
+    {
+      CoglGLES2Framebuffer *write = gles2_ctx->write_buffer;
+      framebuffer = write->gl_framebuffer.fbo_handle;
+    }
+
+  gles2_ctx->context->glBindFramebuffer (target, framebuffer);
+}
+
+/* We wrap glReadPixels so when framebuffer 0 is bound then we can
+ * read from the read_framebuffer passed to cogl_push_gles2_context().
+ */
+void
+gl_read_pixels_wrapper (GLint x,
+                        GLint y,
+                        GLsizei width,
+                        GLsizei height,
+                        GLenum format,
+                        GLenum type,
+                        GLvoid *pixels)
+{
+  CoglGLES2Context *gles2_ctx = current_gles2_context;
+
+  if (gles2_ctx->current_fbo_handle == 0)
+    {
+      CoglGLES2Framebuffer *read = gles2_ctx->read_buffer;
+      CoglGLES2Framebuffer *write = gles2_ctx->write_buffer;
+
+      gles2_ctx->context->glBindFramebuffer (GL_FRAMEBUFFER,
+                                             read->gl_framebuffer.fbo_handle);
+      gles2_ctx->context->glReadPixels (x, y,
+                                        width, height,
+                                        format, type, pixels);
+      gles2_ctx->context->glBindFramebuffer (GL_FRAMEBUFFER,
+                                             write->gl_framebuffer.fbo_handle);
+    }
+  else
+    gles2_ctx->context->glReadPixels (x, y,
+                                      width, height, format, type, pixels);
+}
+
+static void
+_cogl_gles2_context_free (CoglGLES2Context *gles2_context)
+{
+  CoglContext *ctx = gles2_context->context;
+  const CoglWinsysVtable *winsys;
+  GList *l;
+
+  winsys = ctx->display->renderer->winsys_vtable;
+  winsys->destroy_gles2_context (gles2_context);
+
+  for (l = gles2_context->foreign_framebuffers; l; l = l->next)
+    {
+      CoglGLES2Framebuffer *gles2_framebuffer = l->data;
+
+      cogl_object_unref (gles2_framebuffer->original);
+      g_slice_free (CoglGLES2Framebuffer, gles2_framebuffer);
+    }
+  g_list_free (gles2_context->foreign_framebuffers);
+
+  g_object_unref (gles2_context->context);
+
+  g_free (gles2_context->vtable);
+
+  g_free (gles2_context);
+}
+
+CoglGLES2Context *
+cogl_gles2_context_new (CoglContext *ctx, GError **error)
+{
+  CoglGLES2Context *gles2_ctx;
+  const CoglWinsysVtable *winsys;
+
+  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLES2_CONTEXT))
+    {
+      g_set_error (error, COGL_GLES2_CONTEXT_ERROR,
+                   COGL_GLES2_CONTEXT_ERROR_NEW,
+                   "Backend doesn't support creating GLES2 contexts");
+
+      return NULL;
+    }
+
+  gles2_ctx = g_malloc0 (sizeof (CoglGLES2Context));
+
+  cogl_object_ref (ctx);
+  gles2_ctx->context = ctx;
+
+  winsys = ctx->display->renderer->winsys_vtable;
+  gles2_ctx->winsys = winsys->context_create_gles2_context (ctx, error);
+  if (gles2_ctx->winsys == NULL)
+    {
+      cogl_object_unref (gles2_ctx->context);
+      g_free (gles2_ctx);
+      return NULL;
+    }
+
+  gles2_ctx->vtable = g_malloc0 (sizeof (CoglGLES2Vtable));
+#define COGL_EXT_BEGIN(name, \
+                       min_gl_major, min_gl_minor, \
+                       gles_availability, \
+                       extension_suffixes, extension_names)
+
+#define COGL_EXT_FUNCTION(ret, name, args) \
+  gles2_ctx->vtable->name = ctx->name;
+
+#define COGL_EXT_END()
+
+#include "gl-prototypes/cogl-gles2-functions.h"
+
+#undef COGL_EXT_BEGIN
+#undef COGL_EXT_FUNCTION
+#undef COGL_EXT_END
+
+  gles2_ctx->vtable->glBindFramebuffer = gl_bind_framebuffer_wrapper;
+
+  return _cogl_gles2_context_object_new (gles2_ctx);
+}
+
+CoglGLES2Vtable *
+cogl_gles2_context_get_vtable (CoglGLES2Context *gles2_ctx)
+{
+  return gles2_ctx->vtable;
+}
+
+/* When drawing to a CoglFramebuffer from separate context we have
+ * to be able to allocate ancillary buffers for that context...
+ */
+static CoglGLES2Framebuffer *
+_cogl_gles2_framebuffer_allocate (CoglFramebuffer *framebuffer,
+                                  CoglGLES2Context *gles2_context,
+                                  GError **error)
+{
+  CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer);
+  const CoglWinsysVtable *winsys;
+  GList *l;
+  GError *internal_error = NULL;
+  CoglGLES2Framebuffer *gles2_framebuffer;
+
+  _COGL_RETURN_VAL_IF_FAIL (cogl_is_offscreen (framebuffer), FALSE);
+
+  if (!framebuffer->allocated &&
+      !cogl_framebuffer_allocate (framebuffer, error))
+    {
+      return NULL;
+    }
+
+  for (l = gles2_context->foreign_framebuffers; l; l = l->next)
+    {
+      CoglGLES2Framebuffer *gles2_framebuffer = l->data;
+      if (gles2_framebuffer->original == framebuffer)
+        return gles2_framebuffer;
+    }
+
+  winsys = _cogl_framebuffer_get_winsys (framebuffer);
+  winsys->save_context (framebuffer->context);
+  if (!winsys->set_gles2_context (gles2_context, &internal_error))
+    {
+      winsys->restore_context (framebuffer->context);
+
+      g_error_free (internal_error);
+      g_set_error (error, COGL_FRAMEBUFFER_ERROR,
+                   COGL_FRAMEBUFFER_ERROR_ALLOCATE,
+                   "Failed to bind gles2 context to create framebuffer");
+      return NULL;
+    }
+
+  gles2_framebuffer = g_slice_new0 (CoglGLES2Framebuffer);
+  if (!_cogl_framebuffer_try_creating_gl_fbo (gles2_context->context,
+                                          offscreen->texture,
+                                          offscreen->texture_level,
+                                          offscreen->texture_level_width,
+                                          offscreen->texture_level_height,
+                                          &COGL_FRAMEBUFFER (offscreen)->config,
+                                          offscreen->allocation_flags,
+                                          &gles2_framebuffer->gl_framebuffer))
+    {
+      winsys->restore_context (framebuffer->context);
+
+      g_slice_free (CoglGLES2Framebuffer, gles2_framebuffer);
+
+      g_set_error (error, COGL_FRAMEBUFFER_ERROR,
+                   COGL_FRAMEBUFFER_ERROR_ALLOCATE,
+                   "Failed to create an OpenGL framebuffer object");
+      return NULL;
+    }
+
+  winsys->restore_context (framebuffer->context);
+
+  gles2_framebuffer->original = cogl_object_ref (framebuffer);
+
+  gles2_context->foreign_framebuffers =
+    g_list_prepend (gles2_context->foreign_framebuffers,
+                    gles2_framebuffer);
+
+  return gles2_framebuffer;
+}
+
+gboolean
+cogl_push_gles2_context (CoglContext *ctx,
+                         CoglGLES2Context *gles2_ctx,
+                         CoglFramebuffer *read_buffer,
+                         CoglFramebuffer *write_buffer,
+                         GError **error)
+{
+  const CoglWinsysVtable *winsys = ctx->display->renderer->winsys_vtable;
+
+  _COGL_RETURN_VAL_IF_FAIL (gles2_ctx != NULL, FALSE);
+  _COGL_RETURN_VAL_IF_FAIL (cogl_is_offscreen (read_buffer), FALSE);
+  _COGL_RETURN_VAL_IF_FAIL (cogl_is_offscreen (write_buffer), FALSE);
+
+  if (ctx->gles2_context_stack->length == 0)
+    winsys->save_context (ctx);
+
+  winsys->set_gles2_context (gles2_ctx, error);
+
+  g_queue_push_tail (ctx->gles2_context_stack, gles2_ctx);
+
+  gles2_ctx->read_buffer = _cogl_gles2_framebuffer_allocate (read_buffer,
+                                                             gles2_ctx,
+                                                             error);
+  if (!gles2_ctx->read_buffer)
+    {
+      winsys->restore_context (ctx);
+      return FALSE;
+    }
+
+  gles2_ctx->write_buffer = _cogl_gles2_framebuffer_allocate (write_buffer,
+                                                              gles2_ctx,
+                                                              error);
+  if (!gles2_ctx->write_buffer)
+    {
+      winsys->restore_context (ctx);
+      return FALSE;
+    }
+
+  current_gles2_context = gles2_ctx;
+  return TRUE;
+}
+
+void
+cogl_pop_gles2_context (CoglContext *ctx)
+{
+  CoglGLES2Context *gles2_ctx;
+  const CoglWinsysVtable *winsys = ctx->display->renderer->winsys_vtable;
+
+  _COGL_RETURN_IF_FAIL (ctx->gles2_context_stack->length > 0);
+
+  g_queue_pop_tail (ctx->gles2_context_stack);
+
+  gles2_ctx = g_queue_peek_tail (ctx->gles2_context_stack);
+
+  if (gles2_ctx)
+    {
+      winsys->set_gles2_context (gles2_ctx, NULL);
+      current_gles2_context = NULL;
+    }
+  else
+    {
+      winsys->restore_context (ctx);
+      current_gles2_context = gles2_ctx;
+    }
+}
diff --git a/cogl/cogl-gles2-context.h b/cogl/cogl-gles2-context.h
new file mode 100644
index 0000000..6d2c80d
--- /dev/null
+++ b/cogl/cogl-gles2-context.h
@@ -0,0 +1,81 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *  Tomeu Vizoso <tomeu vizoso collabora com>
+ *  Robert Bragg <robert linux intel com>
+ *
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef __COGL_GLES2_CONTEXT_H__
+#define __COGL_GLES2_CONTEXT_H__
+
+#include <cogl/cogl-defines.h>
+#include <cogl/cogl-context.h>
+#include <cogl/cogl-framebuffer.h>
+
+G_BEGIN_DECLS
+
+typedef struct _CoglGLES2Context CoglGLES2Context;
+typedef struct _CoglGLES2Vtable CoglGLES2Vtable;
+
+struct _CoglGLES2Vtable
+{
+#define COGL_EXT_BEGIN(name, \
+                       min_gl_major, min_gl_minor, \
+                       gles_availability, \
+                       extension_suffixes, extension_names)
+
+#define COGL_EXT_FUNCTION(ret, name, args) \
+  ret (* name) args;
+
+#define COGL_EXT_END()
+
+#include <cogl/gl-prototypes/cogl-gles2-functions.h>
+
+#undef COGL_EXT_BEGIN
+#undef COGL_EXT_FUNCTION
+#undef COGL_EXT_END
+};
+
+CoglGLES2Context *cogl_gles2_context_new (CoglContext *ctx, GError **error);
+
+CoglGLES2Vtable *cogl_gles2_context_get_vtable (CoglGLES2Context *gles2_ctx);
+
+gboolean
+cogl_push_gles2_context (CoglContext *ctx,
+                         CoglGLES2Context *gles2_ctx,
+                         CoglFramebuffer *read_buffer,
+                         CoglFramebuffer *write_buffer,
+                         GError **error);
+
+void
+cogl_pop_gles2_context (CoglContext *ctx);
+
+G_END_DECLS
+
+#endif /* __COGL_GLES2_CONTEXT_H__ */
+
diff --git a/cogl/cogl.h b/cogl/cogl.h
index d2e0bc0..1e9dd49 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -102,13 +102,14 @@
 #include <cogl/cogl-framebuffer.h>
 #include <cogl/cogl-onscreen.h>
 #include <cogl/cogl-poll.h>
+#include <cogl/cogl-gles2-context.h>
 #if defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
 #include <cogl/cogl-kms-renderer.h>
 #endif
 #if defined (COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT)
 #include <cogl/cogl-wayland-renderer.h>
 #endif
-#if COGL_HAS_WIN32_SUPPORT
+#ifdef COGL_HAS_WIN32_SUPPORT
 #include <cogl/cogl-win32-renderer.h>
 #endif
 #ifdef COGL_HAS_GLIB_SUPPORT
diff --git a/cogl/winsys/cogl-winsys-egl-android.c b/cogl/winsys/cogl-winsys-egl-android.c
index 2efa6b2..c9f7a09 100644
--- a/cogl/winsys/cogl-winsys-egl-android.c
+++ b/cogl/winsys/cogl-winsys-egl-android.c
@@ -132,10 +132,10 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
       goto fail;
     }
 
-  if (!eglMakeCurrent (egl_renderer->edpy,
-                       egl_display->egl_surface,
-                       egl_display->egl_surface,
-                       egl_display->egl_context))
+  if (!_cogl_winsys_egl_make_current (display,
+                                      egl_display->egl_surface,
+                                      egl_display->egl_surface,
+                                      egl_display->egl_context))
     {
       error_message = "Unable to eglMakeCurrent with egl surface";
       goto fail;
diff --git a/cogl/winsys/cogl-winsys-egl-gdl.c b/cogl/winsys/cogl-winsys-egl-gdl.c
index 1f7a2c3..ef7a72a 100644
--- a/cogl/winsys/cogl-winsys-egl-gdl.c
+++ b/cogl/winsys/cogl-winsys-egl-gdl.c
@@ -140,10 +140,10 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
       goto fail;
     }
 
-  if (!eglMakeCurrent (egl_renderer->edpy,
-                       egl_display->egl_surface,
-                       egl_display->egl_surface,
-                       egl_display->egl_context))
+  if (!_cogl_winsys_egl_make_current (display,
+                                      egl_display->egl_surface,
+                                      egl_display->egl_surface,
+                                      egl_display->egl_context))
     {
       error_message = "Unable to eglMakeCurrent with egl surface";
       goto fail;
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c
index ecddb43..fcba974 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
@@ -278,10 +278,10 @@ _cogl_winsys_egl_try_create_context (CoglDisplay *display,
       return FALSE;
     }
 
-  if (!eglMakeCurrent (egl_renderer->edpy,
-                       EGL_NO_SURFACE,
-                       EGL_NO_SURFACE,
-                       egl_display->egl_context))
+  if (!_cogl_winsys_egl_make_current (display,
+                                      EGL_NO_SURFACE,
+                                      EGL_NO_SURFACE,
+                                      egl_display->egl_context))
     {
       g_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
@@ -511,14 +511,13 @@ static void
 _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
 {
   CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
-  CoglDisplayEGL *egl_display = context->display->winsys;
-  CoglRenderer *renderer = context->display->renderer;
-  CoglRendererEGL *egl_renderer = renderer->winsys;
+  CoglDisplay *display = context->display;
+  CoglDisplayEGL *egl_display = display->winsys;
 
-  eglMakeCurrent (egl_renderer->edpy,
-                  EGL_NO_SURFACE,
-                  EGL_NO_SURFACE,
-                  egl_display->egl_context);
+  _cogl_winsys_egl_make_current (display,
+                                 EGL_NO_SURFACE,
+                                 EGL_NO_SURFACE,
+                                 egl_display->egl_context);
 }
 
 static void
diff --git a/cogl/winsys/cogl-winsys-egl-null.c b/cogl/winsys/cogl-winsys-egl-null.c
index f0b9200..d19d06b 100644
--- a/cogl/winsys/cogl-winsys-egl-null.c
+++ b/cogl/winsys/cogl-winsys-egl-null.c
@@ -98,10 +98,10 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
       goto fail;
     }
 
-  if (!eglMakeCurrent (egl_renderer->edpy,
-                       egl_display->egl_surface,
-                       egl_display->egl_surface,
-                       egl_display->egl_context))
+  if (!_cogl_winsys_egl_make_current (display,
+                                      egl_display->egl_surface,
+                                      egl_display->egl_surface,
+                                      egl_display->egl_context))
     {
       error_message = "Unable to eglMakeCurrent with egl surface";
       goto fail;
diff --git a/cogl/winsys/cogl-winsys-egl-private.h b/cogl/winsys/cogl-winsys-egl-private.h
index 6658278..374c894 100644
--- a/cogl/winsys/cogl-winsys-egl-private.h
+++ b/cogl/winsys/cogl-winsys-egl-private.h
@@ -118,13 +118,17 @@ typedef struct _CoglDisplayEGL
   gboolean found_egl_config;
   gboolean stencil_disabled;
 
+  EGLSurface current_read_surface;
+  EGLSurface current_draw_surface;
+
   /* Platform specific display data */
   void *platform;
 } CoglDisplayEGL;
 
 typedef struct _CoglContextEGL
 {
-  EGLSurface current_surface;
+  EGLSurface saved_draw_surface;
+  EGLSurface saved_read_surface;
 } CoglContextEGL;
 
 typedef struct _CoglOnscreenEGL
@@ -138,6 +142,12 @@ typedef struct _CoglOnscreenEGL
 const CoglWinsysVtable *
 _cogl_winsys_egl_get_vtable (void);
 
+EGLBoolean
+_cogl_winsys_egl_make_current (CoglDisplay *display,
+                               EGLSurface draw,
+                               EGLSurface read,
+                               EGLContext context);
+
 #ifdef EGL_KHR_image_base
 EGLImageKHR
 _cogl_egl_create_image (CoglContext *ctx,
diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c
index a9d2129..03e995b 100644
--- a/cogl/winsys/cogl-winsys-egl-wayland.c
+++ b/cogl/winsys/cogl-winsys-egl-wayland.c
@@ -231,14 +231,14 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
                             NULL);
   if (egl_display->dummy_surface == EGL_NO_SURFACE)
     {
-      error_message= "Unable to eglMakeCurrent with dummy surface";
+      error_message= "Unable to create dummy window surface";
       goto fail;
     }
 
-  if (!eglMakeCurrent (egl_renderer->edpy,
-                       egl_display->dummy_surface,
-                       egl_display->dummy_surface,
-                       egl_display->egl_context))
+  if (!_cogl_winsys_egl_make_current (display,
+                                      egl_display->dummy_surface,
+                                      egl_display->dummy_surface,
+                                      egl_display->egl_context))
     {
       error_message = "Unable to eglMakeCurrent with dummy surface";
       goto fail;
diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/winsys/cogl-winsys-egl-x11.c
index 55cbbc2..5fdf105 100644
--- a/cogl/winsys/cogl-winsys-egl-x11.c
+++ b/cogl/winsys/cogl-winsys-egl-x11.c
@@ -505,10 +505,10 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
       goto fail;
     }
 
-  if (!eglMakeCurrent (egl_renderer->edpy,
-                       egl_display->dummy_surface,
-                       egl_display->dummy_surface,
-                       egl_display->egl_context))
+  if (!_cogl_winsys_egl_make_current (display,
+                                      egl_display->dummy_surface,
+                                      egl_display->dummy_surface,
+                                      egl_display->egl_context))
     {
       error_message = "Unable to eglMakeCurrent with dummy surface";
       goto fail;
diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c
index 5d96ac4..b01f3ac 100644
--- a/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/winsys/cogl-winsys-egl.c
@@ -38,6 +38,7 @@
 #include "cogl-swap-chain-private.h"
 #include "cogl-renderer-private.h"
 #include "cogl-onscreen-template-private.h"
+#include "cogl-gles2-context-private.h"
 
 #include "cogl-private.h"
 
@@ -82,6 +83,39 @@ static const CoglFeatureData winsys_feature_data[] =
 #include "cogl-winsys-egl-feature-functions.h"
   };
 
+static const char *
+get_error_string (void)
+{
+  switch (eglGetError()){
+  case EGL_BAD_DISPLAY:
+    return "Invalid display";
+  case EGL_NOT_INITIALIZED:
+    return "Display not initialized";
+  case EGL_BAD_ALLOC:
+    return "Not enough resources to allocate context";
+  case EGL_BAD_ATTRIBUTE:
+    return "Invalid attribute";
+  case EGL_BAD_CONFIG:
+    return "Invalid config";
+  case EGL_BAD_CONTEXT:
+    return "Invalid context";
+  case EGL_BAD_CURRENT_SURFACE:
+     return "Invalid current surface";
+  case EGL_BAD_MATCH:
+     return "Bad match";
+  case EGL_BAD_NATIVE_PIXMAP:
+     return "Invalid native pixmap";
+  case EGL_BAD_NATIVE_WINDOW:
+     return "Invalid native window";
+  case EGL_BAD_PARAMETER:
+     return "Invalid parameter";
+  case EGL_BAD_SURFACE:
+     return "Invalid surface";
+  default:
+    g_assert_not_reached ();
+  }
+}
+
 static CoglFuncPtr
 _cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer,
                                         const char *name)
@@ -294,6 +328,31 @@ fail:
   return FALSE;
 }
 
+EGLBoolean
+_cogl_winsys_egl_make_current (CoglDisplay *display,
+                               EGLSurface draw,
+                               EGLSurface read,
+                               EGLContext context)
+{
+  CoglDisplayEGL *egl_display = display->winsys;
+  CoglRendererEGL *egl_renderer = display->renderer->winsys;
+  EGLBoolean ret;
+
+  if (egl_display->current_draw_surface == draw &&
+      egl_display->current_read_surface == read)
+  return EGL_TRUE;
+
+  ret = eglMakeCurrent (egl_renderer->edpy,
+                        draw,
+                        read,
+                        context);
+
+  egl_display->current_draw_surface = draw;
+  egl_display->current_read_surface = read;
+
+  return ret;
+}
+
 static void
 cleanup_context (CoglDisplay *display)
 {
@@ -303,8 +362,9 @@ cleanup_context (CoglDisplay *display)
 
   if (egl_display->egl_context != EGL_NO_CONTEXT)
     {
-      eglMakeCurrent (egl_renderer->edpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
-                      EGL_NO_CONTEXT);
+      _cogl_winsys_egl_make_current (display,
+                                     EGL_NO_SURFACE, EGL_NO_SURFACE,
+                                     EGL_NO_CONTEXT);
       eglDestroyContext (egl_renderer->edpy, egl_display->egl_context);
       egl_display->egl_context = EGL_NO_CONTEXT;
     }
@@ -421,6 +481,13 @@ _cogl_winsys_context_init (CoglContext *context, GError **error)
                       COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
     }
 
+  /* NB: We currently only support creating standalone GLES2 contexts
+   * for offscreen rendering and so we need a dummy (non-visible)
+   * surface to be able to bind those contexts */
+  if (egl_display->dummy_surface != EGL_NO_SURFACE)
+    COGL_FLAGS_SET (context->features,
+                    COGL_FEATURE_ID_GLES2_CONTEXT, TRUE);
+
   if (egl_renderer->platform_vtable->context_init &&
       !egl_renderer->platform_vtable->context_init (context, error))
     return FALSE;
@@ -440,6 +507,54 @@ _cogl_winsys_context_deinit (CoglContext *context)
   g_free (context->winsys);
 }
 
+typedef struct _CoglGLES2ContextEGL
+{
+  EGLContext egl_context;
+  EGLSurface dummy_surface;
+} CoglGLES2ContextEGL;
+
+void *
+_cogl_winsys_context_create_gles2_context (CoglContext *ctx, GError **error)
+{
+  CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys;
+  CoglDisplayEGL *egl_display = ctx->display->winsys;
+  EGLint attribs[3];
+  EGLContext egl_context;
+
+  attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
+  attribs[1] = 2;
+  attribs[2] = EGL_NONE;
+
+  egl_context = eglCreateContext (egl_renderer->edpy,
+                                  egl_display->egl_config,
+                                  egl_display->egl_context,
+                                  attribs);
+  if (egl_context == EGL_NO_CONTEXT)
+    {
+      g_set_error (error, COGL_WINSYS_ERROR,
+                   COGL_WINSYS_ERROR_CREATE_GLES2_CONTEXT,
+                   "%s", get_error_string ());
+      return NULL;
+    }
+
+  return (void *)egl_context;
+}
+
+void
+_cogl_winsys_destroy_gles2_context (CoglGLES2Context *gles2_ctx)
+{
+  CoglContext *context = gles2_ctx->context;
+  CoglDisplay *display = context->display;
+  CoglRenderer *renderer = display->renderer;
+  CoglRendererEGL *egl_renderer = renderer->winsys;
+  EGLContext egl_context = gles2_ctx->winsys;
+
+  _cogl_winsys_egl_make_current (display,
+                                 EGL_NO_SURFACE, EGL_NO_SURFACE,
+                                 EGL_NO_CONTEXT);
+  eglDestroyContext (egl_renderer->edpy, egl_context);
+}
+
 static gboolean
 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
                             GError **error)
@@ -538,16 +653,11 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
   CoglRenderer *renderer = context->display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
-  CoglContextEGL *egl_context = context->winsys;
 
-  if (egl_context->current_surface == egl_onscreen->egl_surface)
-    return;
-
-  eglMakeCurrent (egl_renderer->edpy,
-                  egl_onscreen->egl_surface,
-                  egl_onscreen->egl_surface,
-                  egl_display->egl_context);
-  egl_context->current_surface = egl_onscreen->egl_surface;
+  _cogl_winsys_egl_make_current (context->display,
+                                 egl_onscreen->egl_surface,
+                                 egl_onscreen->egl_surface,
+                                 egl_display->egl_context);
 
   if (fb->config.swap_throttled)
     eglSwapInterval (egl_renderer->edpy, 1);
@@ -618,13 +728,13 @@ static void
 _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
 {
   CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
-  CoglContextEGL *egl_context = context->winsys;
+  CoglDisplayEGL *egl_display = context->display->winsys;
   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
 
-  if (egl_context->current_surface != egl_onscreen->egl_surface)
+  if (egl_display->current_draw_surface != egl_onscreen->egl_surface)
     return;
 
-  egl_context->current_surface = EGL_NO_SURFACE;
+  egl_display->current_draw_surface = EGL_NO_SURFACE;
 
   _cogl_winsys_onscreen_bind (onscreen);
 }
@@ -637,6 +747,49 @@ _cogl_winsys_context_egl_get_egl_display (CoglContext *context)
   return egl_renderer->edpy;
 }
 
+void
+_cogl_winsys_save_context (CoglContext *ctx)
+{
+  CoglContextEGL *egl_context = ctx->winsys;
+  CoglDisplayEGL *egl_display = ctx->display->winsys;
+
+  egl_context->saved_draw_surface = egl_display->current_draw_surface;
+  egl_context->saved_read_surface = egl_display->current_read_surface;
+}
+
+gboolean
+_cogl_winsys_set_gles2_context (CoglGLES2Context *gles2_ctx,
+                                GError **error)
+{
+  CoglContext *ctx = gles2_ctx->context;
+  CoglDisplayEGL *egl_display = ctx->display->winsys;
+
+  if (!_cogl_winsys_egl_make_current (ctx->display,
+                                      egl_display->dummy_surface,
+                                      egl_display->dummy_surface,
+                                      gles2_ctx->winsys))
+    {
+      g_set_error (error,
+                   COGL_WINSYS_ERROR,
+                   COGL_WINSYS_ERROR_MAKE_CURRENT,
+                   "Failed to make gles2 context current");
+      return FALSE;
+    }
+  return TRUE;
+}
+
+void
+_cogl_winsys_restore_context (CoglContext *ctx)
+{
+  CoglContextEGL *egl_context = ctx->winsys;
+  CoglDisplayEGL *egl_display = ctx->display->winsys;
+
+  _cogl_winsys_egl_make_current (ctx->display,
+                                 egl_context->saved_draw_surface,
+                                 egl_context->saved_read_surface,
+                                 egl_display->egl_context);
+}
+
 static CoglWinsysVtable _cogl_winsys_vtable =
   {
     .constraints = COGL_RENDERER_CONSTRAINT_USES_EGL,
@@ -653,6 +806,9 @@ static CoglWinsysVtable _cogl_winsys_vtable =
     .context_deinit = _cogl_winsys_context_deinit,
     .context_egl_get_egl_display =
       _cogl_winsys_context_egl_get_egl_display,
+    .context_create_gles2_context =
+      _cogl_winsys_context_create_gles2_context,
+    .destroy_gles2_context = _cogl_winsys_destroy_gles2_context,
     .onscreen_init = _cogl_winsys_onscreen_init,
     .onscreen_deinit = _cogl_winsys_onscreen_deinit,
     .onscreen_bind = _cogl_winsys_onscreen_bind,
@@ -660,6 +816,11 @@ static CoglWinsysVtable _cogl_winsys_vtable =
     .onscreen_swap_region = _cogl_winsys_onscreen_swap_region,
     .onscreen_update_swap_throttled =
       _cogl_winsys_onscreen_update_swap_throttled,
+
+    /* CoglGLES2Context related methods */
+    .save_context = _cogl_winsys_save_context,
+    .set_gles2_context = _cogl_winsys_set_gles2_context,
+    .restore_context = _cogl_winsys_restore_context,
   };
 
 /* XXX: we use a function because no doubt someone will complain
diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h
index 0e6c78b..c493dc2 100644
--- a/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/winsys/cogl-winsys-private.h
@@ -26,6 +26,7 @@
 
 #include "cogl-renderer.h"
 #include "cogl-onscreen.h"
+#include "cogl-gles2-context.h"
 
 #ifdef COGL_HAS_XLIB_SUPPORT
 #include "cogl-texture-pixmap-x11-private.h"
@@ -47,6 +48,8 @@ typedef enum { /*< prefix=COGL_WINSYS_ERROR >*/
   COGL_WINSYS_ERROR_INIT,
   COGL_WINSYS_ERROR_CREATE_CONTEXT,
   COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+  COGL_WINSYS_ERROR_MAKE_CURRENT,
+  COGL_WINSYS_ERROR_CREATE_GLES2_CONTEXT,
 } CoglWinsysError;
 
 typedef enum
@@ -87,6 +90,9 @@ typedef struct _CoglWinsysVtable
   void
   (*context_deinit) (CoglContext *context);
 
+  void *
+  (*context_create_gles2_context) (CoglContext *ctx, GError **error);
+
   gboolean
   (*onscreen_init) (CoglOnscreen *onscreen, GError **error);
 
@@ -158,6 +164,18 @@ typedef struct _CoglWinsysVtable
   (*texture_pixmap_x11_get_texture) (CoglTexturePixmapX11 *tex_pixmap);
 #endif
 
+  void
+  (*save_context) (CoglContext *ctx);
+
+  gboolean
+  (*set_gles2_context) (CoglGLES2Context *gles2_ctx, GError **error);
+
+  void
+  (*restore_context) (CoglContext *ctx);
+
+  void
+  (*destroy_gles2_context) (CoglGLES2Context *gles2_ctx);
+
 } CoglWinsysVtable;
 
 gboolean
diff --git a/examples/Makefile.am b/examples/Makefile.am
index f96ae65..868e9bc 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -18,7 +18,7 @@ common_ldadd = \
 	$(COGL_DEP_LIBS) \
 	$(top_builddir)/cogl/libcogl.la
 
-programs = cogl-hello cogl-info cogl-msaa
+programs = cogl-hello cogl-info cogl-msaa cogl-gles2-context
 examples_datadir = $(pkgdatadir)/examples-data
 examples_data_DATA =
 
@@ -57,6 +57,9 @@ cogl_sdl_hello_SOURCES = cogl-sdl-hello.c
 cogl_sdl_hello_LDADD = $(common_ldadd)
 endif
 
+cogl_gles2_context_SOURCES = cogl-gles2-context.c
+cogl_gles2_context_LDADD = $(common_ldadd)
+
 if INSTALL_EXAMPLES
 bin_PROGRAMS = $(programs)
 else
diff --git a/examples/cogl-gles2-context.c b/examples/cogl-gles2-context.c
new file mode 100644
index 0000000..5d54aa2
--- /dev/null
+++ b/examples/cogl-gles2-context.c
@@ -0,0 +1,131 @@
+#include <cogl/cogl.h>
+#include <glib.h>
+#include <stdio.h>
+
+#define OFFSCREEN_WIDTH 100
+#define OFFSCREEN_HEIGHT 100
+
+typedef struct _Data
+{
+    CoglContext *ctx;
+    CoglFramebuffer *fb;
+    CoglPrimitive *triangle;
+    CoglPipeline *pipeline;
+
+    CoglTexture *offscreen_texture;
+    CoglOffscreen *offscreen;
+    CoglGLES2Context *gles2_ctx;
+    CoglGLES2Vtable *gles2_vtable;
+} Data;
+
+static gboolean
+paint_cb (void *user_data)
+{
+    Data *data = user_data;
+    GError *error = NULL;
+    CoglGLES2Vtable *gles2 = data->gles2_vtable;
+
+    /* Draw scene with Cogl */
+    cogl_framebuffer_clear4f (data->fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+    cogl_framebuffer_draw_primitive (data->fb, data->pipeline, data->triangle);
+
+    /* Draw scene with GLES2 */
+    if (!cogl_push_gles2_context (data->ctx,
+                                  data->gles2_ctx,
+                                  COGL_FRAMEBUFFER (data->offscreen),
+                                  COGL_FRAMEBUFFER (data->offscreen),
+                                  &error))
+    {
+        g_error ("Failed to push gles2 context: %s\n", error->message);
+    }
+
+    /* Clear offscreen framebuffer with a random color */
+    gles2->glClearColor (g_random_double (),
+                         g_random_double (),
+                         g_random_double (),
+                         1.0f);
+    gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+    cogl_pop_gles2_context (data->ctx);
+
+    /* XXX: we still need a "current framebuffer" to use the cogl_rectangle api.
+     * FIXME: Add cogl_framebuffer_draw_textured_rectangle API. */
+    cogl_push_framebuffer (data->fb);
+    cogl_set_source_texture (data->offscreen_texture);
+    cogl_rectangle_with_texture_coords (-0.5, -0.5, 0.5, 0.5,
+                                        0, 0, 1.0, 1.0);
+    cogl_pop_framebuffer ();
+
+    cogl_onscreen_swap_buffers (COGL_ONSCREEN (data->fb));
+
+    /* If the driver can deliver swap complete events then we can remove
+     * the idle paint callback until we next get a swap complete event
+     * otherwise we keep the idle paint callback installed and simply
+     * paint as fast as the driver will allow... */
+    if (cogl_has_feature (data->ctx, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT))
+      return FALSE; /* remove the callback */
+    else
+      return TRUE;
+}
+
+static void
+swap_complete_cb (CoglFramebuffer *framebuffer, void *user_data)
+{
+    g_idle_add (paint_cb, user_data);
+}
+
+int
+main (int argc, char **argv)
+{
+    Data data;
+    CoglOnscreen *onscreen;
+    GError *error = NULL;
+    CoglVertexP2C4 triangle_vertices[] = {
+        {0, 0.7, 0xff, 0x00, 0x00, 0x80},
+        {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
+        {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
+    };
+    GSource *cogl_source;
+    GMainLoop *loop;
+
+    data.ctx = cogl_context_new (NULL, NULL);
+
+    onscreen = cogl_onscreen_new (data.ctx, 640, 480);
+    cogl_onscreen_show (onscreen);
+    data.fb = COGL_FRAMEBUFFER (onscreen);
+
+    /* Prepare onscreen primitive */
+    data.triangle = cogl_primitive_new_p2c4 (data.ctx,
+                                             COGL_VERTICES_MODE_TRIANGLES,
+                                             3, triangle_vertices);
+    data.pipeline = cogl_pipeline_new (data.ctx);
+
+    data.offscreen_texture =
+      cogl_texture_new_with_size (OFFSCREEN_WIDTH,
+                                  OFFSCREEN_HEIGHT,
+                                  COGL_TEXTURE_NO_SLICING,
+                                  COGL_PIXEL_FORMAT_ANY);
+    data.offscreen = cogl_offscreen_new_to_texture (data.offscreen_texture);
+
+    data.gles2_ctx = cogl_gles2_context_new (data.ctx, &error);
+    if (!data.gles2_ctx) {
+        g_error ("Failed to create GLES2 context: %s\n", error->message);
+    }
+
+    data.gles2_vtable = cogl_gles2_context_get_vtable (data.gles2_ctx);
+
+    cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);
+
+    g_source_attach (cogl_source, NULL);
+
+    if (cogl_has_feature (data.ctx, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT))
+      cogl_onscreen_add_swap_buffers_callback (COGL_ONSCREEN (data.fb),
+                                               swap_complete_cb, &data);
+
+    g_idle_add (paint_cb, &data);
+
+    loop = g_main_loop_new (NULL, TRUE);
+    g_main_loop_run (loop);
+
+    return 0;
+}
diff --git a/examples/cogl-info.c b/examples/cogl-info.c
index 988e991..b7dab00 100644
--- a/examples/cogl-info.c
+++ b/examples/cogl-info.c
@@ -103,6 +103,12 @@ struct {
     COGL_FEATURE_ID_MIRRORED_REPEAT,
     "Mirrored repeat wrap modes",
     "Mirrored repeat wrap modes"
+  },
+  {
+    COGL_FEATURE_ID_GLES2_CONTEXT,
+    "GLES2 API integration supported",
+    "Support for creating a GLES2 context for using the GLES2 API in a "
+      "way that's integrated with Cogl."
   }
 };
 



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