diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 91075d6a0..a2838b5ed 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -90,6 +90,8 @@ cogl_experimental_h = \
$(srcdir)/cogl-pipeline-layer-state.h \
$(srcdir)/cogl-snippet.h \
$(srcdir)/cogl2-path.h \
+ $(srcdir)/cogl-gles2.h \
+ $(srcdir)/cogl-gles2-types.h \
$(srcdir)/cogl-index-buffer.h \
$(srcdir)/cogl-attribute-buffer.h \
$(srcdir)/cogl-indices.h \
@@ -117,6 +119,14 @@ cogl_experimental_h = \
$(srcdir)/cogl-version.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 =
@@ -361,6 +371,7 @@ cogl_sources_c = \
$(srcdir)/cogl-memory-stack.c \
$(srcdir)/cogl-magazine-private.h \
$(srcdir)/cogl-magazine.c \
+ $(srcdir)/cogl-gles2-context.c \
$(NULL)
if USE_GLIB
@@ -496,6 +507,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)/cogl2/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 40f157330..1e96ad1b2 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -50,6 +50,7 @@
#include "cogl-sampler-cache-private.h"
#include "cogl-gpu-info-private.h"
#include "cogl-gl-header.h"
+#include "cogl-framebuffer-private.h"
typedef struct
{
@@ -180,6 +181,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 0d2a8f6de..3c39855fa 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -159,7 +159,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
@@ -309,6 +309,8 @@ cogl_context_new (CoglDisplay *display,
context->current_draw_buffer_state_flushed = 0;
context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;
+ g_queue_init (&context->gles2_context_stack);
+
context->journal_flush_attributes_array =
g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
context->journal_clip_bounds = NULL;
@@ -478,6 +480,8 @@ _cogl_context_free (CoglContext *context)
if (context->blit_texture_pipeline)
cogl_object_unref (context->blit_texture_pipeline);
+ g_warn_if_fail (context->gles2_context_stack.length == 0);
+
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 21ea6369e..757b1a874 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 4c95f7340..9922a1aa1 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -166,17 +166,33 @@ struct _CoglFramebuffer
CoglBool 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 */
@@ -400,4 +416,17 @@ _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);
+
+void
+_cogl_gl_framebuffer_bind (CoglFramebuffer *framebuffer, GLenum target);
+
#endif /* __COGL_FRAMEBUFFER_PRIVATE_H */
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 1cc7ca0a4..9945b2bcc 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -111,13 +111,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;
@@ -794,23 +787,31 @@ cogl_offscreen_new_to_texture (CoglTexture *texture)
}
static void
-_cogl_offscreen_free (CoglOffscreen *offscreen)
+delete_renderbuffers (CoglContext *ctx, GList *renderbuffers)
{
- CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen);
- CoglContext *ctx = framebuffer->context;
- GSList *l;
+ GList *l;
- /* Chain up to parent */
- _cogl_framebuffer_free (framebuffer);
-
- for (l = offscreen->renderbuffers; l; l = l->next)
+ for (l = renderbuffers; l; l = l->next)
{
GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
}
- g_slist_free (offscreen->renderbuffers);
- GE (ctx, glDeleteFramebuffers (1, &offscreen->fbo_handle));
+ g_list_free (renderbuffers);
+}
+
+static void
+_cogl_offscreen_free (CoglOffscreen *offscreen)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen);
+ CoglContext *ctx = framebuffer->context;
+
+ /* Chain up to parent */
+ _cogl_framebuffer_free (framebuffer);
+
+ delete_renderbuffers (ctx, offscreen->gl_framebuffer.renderbuffers);
+
+ GE (ctx, glDeleteFramebuffers (1, &offscreen->gl_framebuffer.fbo_handle));
if (offscreen->texture != NULL)
cogl_object_unref (offscreen->texture);
@@ -818,72 +819,20 @@ _cogl_offscreen_free (CoglOffscreen *offscreen)
g_free (offscreen);
}
-static CoglBool
-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 (flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL |
+ COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH24_STENCIL8))
{
- 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))
- {
- 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 */
@@ -906,13 +855,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
@@ -929,13 +880,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)
@@ -950,28 +902,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 CoglBool
+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, &gl_framebuffer->fbo_handle));
- GE (ctx, glDeleteFramebuffers (1, &fbo_gl_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;
}
@@ -988,21 +1003,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;
}
+CoglBool
+_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 CoglBool
_cogl_offscreen_allocate (CoglOffscreen *offscreen,
GError **error)
{
CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
CoglContext *ctx = fb->context;
- static TryFBOFlags flags;
- static CoglBool have_working_flags = FALSE;
- CoglBool 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
@@ -1016,41 +1050,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 ((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;
- }
+ 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)) ||
- if (!fbo_created)
+ (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,
+ flags = 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))
+ {
+ 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;
+
+ /* 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;
}
CoglBool
@@ -1325,14 +1424,17 @@ cogl_pop_draw_buffer (void)
cogl_pop_framebuffer ();
}
-static void
-bind_gl_framebuffer (CoglContext *ctx,
- GLenum target,
- CoglFramebuffer *framebuffer)
+void
+_cogl_gl_framebuffer_bind (CoglFramebuffer *framebuffer, GLenum target)
{
+ CoglContext *ctx = framebuffer->context;
+
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 =
@@ -1681,7 +1783,7 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
if (differences & COGL_FRAMEBUFFER_STATE_BIND)
{
if (draw_buffer == read_buffer)
- bind_gl_framebuffer (ctx, GL_FRAMEBUFFER, draw_buffer);
+ _cogl_gl_framebuffer_bind (draw_buffer, GL_FRAMEBUFFER);
else
{
/* NB: Currently we only take advantage of binding separate
@@ -1692,8 +1794,8 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
_COGL_RETURN_IF_FAIL (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
_COGL_RETURN_IF_FAIL (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
- bind_gl_framebuffer (ctx, GL_DRAW_FRAMEBUFFER, draw_buffer);
- bind_gl_framebuffer (ctx, GL_READ_FRAMEBUFFER, read_buffer);
+ _cogl_gl_framebuffer_bind (draw_buffer, GL_DRAW_FRAMEBUFFER);
+ _cogl_gl_framebuffer_bind (read_buffer, GL_READ_FRAMEBUFFER);
}
differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
diff --git a/cogl/cogl-gles2-context-private.h b/cogl/cogl-gles2-context-private.h
new file mode 100644
index 000000000..6a654c359
--- /dev/null
+++ b/cogl/cogl-gles2-context-private.h
@@ -0,0 +1,69 @@
+/*
+ * 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
+ * .
+ *
+ * Authors:
+ * Tomeu Vizoso
+ * Robert Bragg
+ *
+ */
+
+#ifndef __COGL_GLES2_CONTEXT_PRIVATE_H
+#define __COGL_GLES2_CONTEXT_PRIVATE_H
+
+#include
+
+#include "cogl-object-private.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-queue.h"
+
+typedef struct _CoglGLES2Offscreen CoglGLES2Offscreen;
+
+COGL_LIST_HEAD (CoglGLES2OffscreenList, CoglGLES2Offscreen);
+
+struct _CoglGLES2Offscreen
+{
+ COGL_LIST_ENTRY (CoglGLES2Offscreen) list_node;
+ CoglOffscreen *original_offscreen;
+ CoglGLFramebuffer gl_framebuffer;
+};
+
+struct _CoglGLES2Context
+{
+ CoglObject _parent;
+
+ CoglContext *context;
+
+ CoglFramebuffer *read_buffer;
+ CoglGLES2Offscreen *gles2_read_buffer;
+ CoglFramebuffer *write_buffer;
+ CoglGLES2Offscreen *gles2_write_buffer;
+
+ GLuint current_fbo_handle;
+
+ CoglGLES2OffscreenList foreign_offscreens;
+
+ 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 000000000..7d3f9d363
--- /dev/null
+++ b/cogl/cogl-gles2-context.c
@@ -0,0 +1,542 @@
+/*
+ * 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
+ * .
+ *
+ * Authors:
+ * Tomeu Vizoso
+ * Robert Bragg
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-gles2.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"
+
+static void _cogl_gles2_context_free (CoglGLES2Context *gles2_context);
+
+COGL_OBJECT_DEFINE (GLES2Context, gles2_context);
+
+static CoglGLES2Context *current_gles2_context;
+
+static CoglUserDataKey offscreen_wrapper_key;
+
+enum {
+ RESTORE_FB_NONE,
+ RESTORE_FB_FROM_OFFSCREEN,
+ RESTORE_FB_FROM_ONSCREEN,
+};
+
+GQuark
+_cogl_gles2_context_error_quark (void)
+{
+ return g_quark_from_static_string ("cogl-gles2-context-error-quark");
+}
+
+/* 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 && cogl_is_offscreen (gles2_ctx->write_buffer))
+ {
+ CoglGLES2Offscreen *write = gles2_ctx->gles2_write_buffer;
+ framebuffer = write->gl_framebuffer.fbo_handle;
+ }
+
+ gles2_ctx->context->glBindFramebuffer (target, framebuffer);
+}
+
+static int
+transient_bind_read_buffer (CoglGLES2Context *gles2_ctx)
+{
+ if (gles2_ctx->current_fbo_handle == 0)
+ {
+ if (cogl_is_offscreen (gles2_ctx->read_buffer))
+ {
+ CoglGLES2Offscreen *read = gles2_ctx->gles2_read_buffer;
+ GLuint read_fbo_handle = read->gl_framebuffer.fbo_handle;
+
+ gles2_ctx->context->glBindFramebuffer (GL_FRAMEBUFFER,
+ read_fbo_handle);
+
+ return RESTORE_FB_FROM_OFFSCREEN;
+ }
+ else
+ {
+ _cogl_gl_framebuffer_bind (gles2_ctx->read_buffer,
+ 0 /* target ignored */);
+
+ return RESTORE_FB_FROM_ONSCREEN;
+ }
+ }
+ else
+ return RESTORE_FB_NONE;
+}
+
+static void
+restore_write_buffer (CoglGLES2Context *gles2_ctx,
+ int restore_mode)
+{
+ switch (restore_mode)
+ {
+ case RESTORE_FB_FROM_OFFSCREEN:
+
+ gl_bind_framebuffer_wrapper (GL_FRAMEBUFFER, 0);
+
+ break;
+ case RESTORE_FB_FROM_ONSCREEN:
+
+ /* Note: we can't restore the original write buffer using
+ * _cogl_gl_framebuffer_bind() if it's an offscreen
+ * framebuffer because _cogl_gl_framebuffer_bind() doesn't
+ * know about the fbo handle owned by the gles2 context.
+ */
+ if (cogl_is_offscreen (gles2_ctx->write_buffer))
+ gl_bind_framebuffer_wrapper (GL_FRAMEBUFFER, 0);
+ else
+ _cogl_gl_framebuffer_bind (gles2_ctx->write_buffer, GL_FRAMEBUFFER);
+
+ break;
+ case RESTORE_FB_NONE:
+ break;
+ }
+}
+
+/* We wrap glReadPixels so when framebuffer 0 is bound then we can
+ * read from the read_framebuffer passed to cogl_push_gles2_context().
+ */
+static 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;
+ int restore_mode = transient_bind_read_buffer (gles2_ctx);
+
+ gles2_ctx->context->glReadPixels (x, y, width, height, format, type, pixels);
+
+ restore_write_buffer (gles2_ctx, restore_mode);
+}
+
+static void
+gl_copy_tex_image_2d_wrapper (GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border)
+{
+ CoglGLES2Context *gles2_ctx = current_gles2_context;
+ int restore_mode = transient_bind_read_buffer (gles2_ctx);
+
+ gles2_ctx->context->glCopyTexImage2D (target, level, internalformat,
+ x, y, width, height, border);
+
+ restore_write_buffer (gles2_ctx, restore_mode);
+}
+
+static void
+gl_copy_tex_sub_image_2d_wrapper (GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ CoglGLES2Context *gles2_ctx = current_gles2_context;
+ int restore_mode = transient_bind_read_buffer (gles2_ctx);
+
+ gles2_ctx->context->glCopyTexSubImage2D (target, level,
+ xoffset, yoffset,
+ x, y, width, height);
+
+ restore_write_buffer (gles2_ctx, restore_mode);
+}
+
+static void
+_cogl_gles2_offscreen_free (CoglGLES2Offscreen *gles2_offscreen)
+{
+ COGL_LIST_REMOVE (gles2_offscreen, list_node);
+ g_slice_free (CoglGLES2Offscreen, gles2_offscreen);
+}
+
+static void
+_cogl_gles2_context_free (CoglGLES2Context *gles2_context)
+{
+ CoglContext *ctx = gles2_context->context;
+ const CoglWinsysVtable *winsys;
+
+ winsys = ctx->display->renderer->winsys_vtable;
+ winsys->destroy_gles2_context (gles2_context);
+
+ while (gles2_context->foreign_offscreens.lh_first)
+ {
+ CoglGLES2Offscreen *gles2_offscreen =
+ gles2_context->foreign_offscreens.lh_first;
+
+ /* Note: this will also indirectly free the gles2_offscreen by
+ * calling the destroy notify for the _user_data */
+ cogl_object_set_user_data (COGL_OBJECT (gles2_offscreen->original_offscreen),
+ &offscreen_wrapper_key,
+ NULL,
+ NULL);
+ }
+
+ cogl_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_UNSUPPORTED,
+ "Backend doesn't support creating GLES2 contexts");
+
+ return NULL;
+ }
+
+ gles2_ctx = g_malloc0 (sizeof (CoglGLES2Context));
+
+ cogl_object_ref (ctx);
+ gles2_ctx->context = ctx;
+
+ COGL_LIST_INIT (&gles2_ctx->foreign_offscreens);
+
+ 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;
+ gles2_ctx->vtable->glReadPixels = gl_read_pixels_wrapper;
+ gles2_ctx->vtable->glCopyTexImage2D = gl_copy_tex_image_2d_wrapper;
+ gles2_ctx->vtable->glCopyTexSubImage2D = gl_copy_tex_sub_image_2d_wrapper;
+
+ return _cogl_gles2_context_object_new (gles2_ctx);
+}
+
+const CoglGLES2Vtable *
+cogl_gles2_context_get_vtable (CoglGLES2Context *gles2_ctx)
+{
+ return gles2_ctx->vtable;
+}
+
+/* When drawing to a CoglFramebuffer from a separate context we have
+ * to be able to allocate ancillary buffers for that context...
+ */
+static CoglGLES2Offscreen *
+_cogl_gles2_offscreen_allocate (CoglOffscreen *offscreen,
+ CoglGLES2Context *gles2_context,
+ GError **error)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen);
+ const CoglWinsysVtable *winsys;
+ GError *internal_error = NULL;
+ CoglGLES2Offscreen *gles2_offscreen;
+
+ if (!framebuffer->allocated &&
+ !cogl_framebuffer_allocate (framebuffer, error))
+ {
+ return NULL;
+ }
+
+ for (gles2_offscreen = gles2_context->foreign_offscreens.lh_first;
+ gles2_offscreen;
+ gles2_offscreen = gles2_offscreen->list_node.le_next)
+ {
+ if (gles2_offscreen->original_offscreen == offscreen)
+ return gles2_offscreen;
+ }
+
+ 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_offscreen = g_slice_new0 (CoglGLES2Offscreen);
+ 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_offscreen->gl_framebuffer))
+ {
+ winsys->restore_context (framebuffer->context);
+
+ g_slice_free (CoglGLES2Offscreen, gles2_offscreen);
+
+ 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_offscreen->original_offscreen = offscreen;
+
+ COGL_LIST_INSERT_HEAD (&gles2_context->foreign_offscreens,
+ gles2_offscreen,
+ list_node);
+
+ /* So we avoid building up an ever growing collection of ancillary
+ * buffers for wrapped framebuffers, we make sure that the wrappers
+ * get freed when the original offscreen framebuffer is freed. */
+ cogl_object_set_user_data (COGL_OBJECT (framebuffer),
+ &offscreen_wrapper_key,
+ gles2_offscreen,
+ (CoglUserDataDestroyCallback)
+ _cogl_gles2_offscreen_free);
+
+ return gles2_offscreen;
+}
+
+CoglBool
+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;
+ GError *internal_error = NULL;
+
+ _COGL_RETURN_VAL_IF_FAIL (gles2_ctx != NULL, FALSE);
+
+ /* The read/write buffers are properties of the gles2 context and we
+ * don't currently track the read/write buffers as part of the stack
+ * entries so we explicitly don't allow the same context to be
+ * pushed multiple times. */
+ if (g_queue_find (&ctx->gles2_context_stack, gles2_ctx))
+ {
+ g_critical ("Pushing the same GLES2 context multiple times isn't "
+ "supported");
+ return FALSE;
+ }
+
+ if (ctx->gles2_context_stack.length == 0)
+ {
+ _cogl_journal_flush (read_buffer->journal);
+ if (write_buffer != read_buffer)
+ _cogl_journal_flush (write_buffer->journal);
+ winsys->save_context (ctx);
+ }
+ else
+ gles2_ctx->vtable->glFlush ();
+
+ if (gles2_ctx->read_buffer != read_buffer)
+ {
+ if (cogl_is_offscreen (read_buffer))
+ {
+ gles2_ctx->gles2_read_buffer =
+ _cogl_gles2_offscreen_allocate (COGL_OFFSCREEN (read_buffer),
+ gles2_ctx,
+ error);
+ /* XXX: what consistency guarantees should this api have?
+ *
+ * It should be safe to return at this point but we provide
+ * no guarantee to the caller whether their given buffers
+ * may be referenced and old buffers unreferenced even
+ * if the _push fails. */
+ if (!gles2_ctx->gles2_read_buffer)
+ return FALSE;
+ }
+ else
+ gles2_ctx->gles2_read_buffer = NULL;
+ if (gles2_ctx->read_buffer)
+ cogl_object_unref (gles2_ctx->read_buffer);
+ gles2_ctx->read_buffer = cogl_object_ref (read_buffer);
+ }
+
+ if (gles2_ctx->write_buffer != write_buffer)
+ {
+ if (cogl_is_offscreen (write_buffer))
+ {
+ gles2_ctx->gles2_write_buffer =
+ _cogl_gles2_offscreen_allocate (COGL_OFFSCREEN (write_buffer),
+ gles2_ctx,
+ error);
+ /* XXX: what consistency guarantees should this api have?
+ *
+ * It should be safe to return at this point but we provide
+ * no guarantee to the caller whether their given buffers
+ * may be referenced and old buffers unreferenced even
+ * if the _push fails. */
+ if (!gles2_ctx->gles2_write_buffer)
+ return FALSE;
+ }
+ else
+ gles2_ctx->gles2_write_buffer = NULL;
+ if (gles2_ctx->write_buffer)
+ cogl_object_unref (gles2_ctx->write_buffer);
+ gles2_ctx->write_buffer = cogl_object_ref (write_buffer);
+ }
+
+ if (!winsys->set_gles2_context (gles2_ctx, &internal_error))
+ {
+ winsys->restore_context (ctx);
+
+ g_error_free (internal_error);
+ g_set_error (error, COGL_GLES2_CONTEXT_ERROR,
+ COGL_GLES2_CONTEXT_ERROR_DRIVER,
+ "Driver failed to make GLES2 context current");
+ return FALSE;
+ }
+
+ g_queue_push_tail (&ctx->gles2_context_stack, gles2_ctx);
+
+ /* The last time this context was pushed may have been with a
+ * different offscreen draw framebuffer and so if GL framebuffer 0
+ * is bound for this GLES2 context we may need to bind a new,
+ * corresponding, window system framebuffer... */
+ if (gles2_ctx->current_fbo_handle == 0)
+ {
+ if (cogl_is_offscreen (gles2_ctx->write_buffer))
+ {
+ CoglGLES2Offscreen *write = gles2_ctx->gles2_write_buffer;
+ GLuint handle = write->gl_framebuffer.fbo_handle;
+ gles2_ctx->context->glBindFramebuffer (GL_FRAMEBUFFER, handle);
+ }
+ }
+
+ current_gles2_context = gles2_ctx;
+ return TRUE;
+}
+
+CoglGLES2Vtable *
+cogl_gles2_get_current_vtable (void)
+{
+ return current_gles2_context ? current_gles2_context->vtable : NULL;
+}
+
+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 = gles2_ctx;
+ }
+ else
+ {
+ winsys->restore_context (ctx);
+ current_gles2_context = NULL;
+ }
+}
+
+CoglTexture2D *
+cogl_gles2_texture_2d_new_from_handle (CoglContext *ctx,
+ CoglGLES2Context *gles2_ctx,
+ unsigned int handle,
+ int width,
+ int height,
+ CoglPixelFormat internal_format,
+ GError **error)
+{
+ return cogl_texture_2d_new_from_foreign (ctx,
+ handle,
+ width,
+ height,
+ internal_format,
+ error);
+}
+
+CoglBool
+cogl_gles2_texture_get_handle (CoglTexture *texture,
+ unsigned int *handle,
+ unsigned int *target)
+{
+ return cogl_texture_get_gl_texture (texture, handle, target);
+}
diff --git a/cogl/cogl-gles2-types.h b/cogl/cogl-gles2-types.h
new file mode 100644
index 000000000..9f6d097b8
--- /dev/null
+++ b/cogl/cogl-gles2-types.h
@@ -0,0 +1,474 @@
+#ifndef __COGL_GLES2_TYPES_H_
+#define __COGL_GLES2_TYPES_H_
+
+/* $Revision: 16803 $ on $Date:: 2012-02-02 09:49:18 -0800 #$ */
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef char GLchar;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef intptr_t GLintptr;
+typedef long GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __COGL_GLES2_TYPES_H_ */
diff --git a/cogl/cogl-gles2.h b/cogl/cogl-gles2.h
new file mode 100644
index 000000000..56ff64d14
--- /dev/null
+++ b/cogl/cogl-gles2.h
@@ -0,0 +1,368 @@
+/*
+ * 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
+ * .
+ *
+ * Authors:
+ * Tomeu Vizoso
+ * Robert Bragg
+ *
+ */
+
+#ifndef __COGL_GLES2_H__
+#define __COGL_GLES2_H__
+
+#define __COGL_H_INSIDE__
+#include
+#include
+#include
+#include
+#include
+
+/* CoglGLES2Vtable depends on GLES 2.0 typedefs being available but we
+ * want to be careful that the public api doesn't expose arbitrary
+ * system GL headers as part of the Cogl API so although when building
+ * internally we consistently refer to the system headers to avoid
+ * conflicts we only expose the minimal set of GLES 2.0 types and enums
+ * publicly.
+ */
+#ifdef CLUTTER_COMPILATION
+#include "cogl-gl-header.h"
+#else
+#include
+#endif
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION:cogl-gles2
+ * @short_description: A portable api to access OpenGLES 2.0
+ *
+ * Cogl provides portable access to the OpenGLES api through a single
+ * library that is able to smooth over inconsistencies between the
+ * different vendor drivers for OpenGLES in a single place.
+ *
+ * The api is designed to allow Cogl to transparently implement the
+ * api on top of other drivers, such as OpenGL, D3D or on Cogl's own
+ * drawing api so even if your platform doesn't come with an
+ * OpenGLES 2.0 api Cogl may still be able to expose the api to your
+ * application.
+ *
+ * Since Cogl is a library and not an api specification it is possible
+ * to add OpenGLES 2.0 api features to Cogl which can immidiately
+ * benefit developers regardless of what platform they are running on.
+ *
+ * With this api it's possible to re-use existing OpenGLES 2.0 code
+ * within applications that are rendering with the Cogl API and also
+ * it's possible for applications that render using OpenGLES 2.0 to
+ * incorporate content rendered with Cogl.
+ *
+ * Applications can check for OpenGLES 2.0 api support by checking for
+ * %COGL_FEATURE_ID_GLES2_CONTEXT support with cogl_has_feature().
+ *
+ * Since: 1.12
+ * Stability: unstable
+ */
+
+/**
+ * CoglGLES2Context:
+ *
+ * Represents an OpenGLES 2.0 api context used as a sandbox for
+ * OpenGLES 2.0 state. This is comparable to an EGLContext for those
+ * who have used OpenGLES 2.0 with EGL before.
+ *
+ * Since: 1.12
+ * Stability: unstable
+ */
+typedef struct _CoglGLES2Context CoglGLES2Context;
+
+/**
+ * CoglGLES2Vtable:
+ *
+ * Provides function pointers for the full OpenGLES 2.0 api. The
+ * api must be accessed this way and not by directly calling
+ * symbols of any system OpenGLES 2.0 api.
+ *
+ * Since: 1.12
+ * Stability: unstable
+ */
+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
+
+#undef COGL_EXT_BEGIN
+#undef COGL_EXT_FUNCTION
+#undef COGL_EXT_END
+};
+
+GQuark
+_cogl_gles2_context_error_quark (void);
+
+/**
+ * COGL_GLES2_CONTEXT_ERROR:
+ *
+ * An error domain for runtime exceptions relating to the
+ * cogl_gles2_context api.
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+#define COGL_GLES2_CONTEXT_ERROR (_cogl_gles2_context_error_quark ())
+
+/**
+ * CoglGLES2ContextError:
+ * @COGL_GLES2_CONTEXT_ERROR_UNSUPPORTED: Creating GLES2 contexts
+ * isn't supported. Applications should use cogl_has_feature() to
+ * check for the %COGL_FEATURE_ID_GLES2_CONTEXT.
+ * @COGL_GLES2_CONTEXT_ERROR_DRIVER: An underlying driver error
+ * occured.
+ *
+ * Error codes that relate to the cogl_gles2_context api.
+ */
+typedef enum { /*< prefix=COGL_GLES2_CONTEXT_ERROR >*/
+ COGL_GLES2_CONTEXT_ERROR_UNSUPPORTED,
+ COGL_GLES2_CONTEXT_ERROR_DRIVER
+} CoglGLES2ContextError;
+
+/**
+ * cogl_gles2_context_new:
+ * @ctx: A #CoglContext
+ * @error: A pointer to a #GError for returning exceptions
+ *
+ * Allocates a new OpenGLES 2.0 context that can be used to render to
+ * #CoglOffscreen framebuffers (Rendering to #CoglOnscreen
+ * framebuffers is not currently supported).
+ *
+ * To actually access the OpenGLES 2.0 api itself you need to use
+ * cogl_gles2_context_get_vtable(). You should not try to directly link
+ * to and use the symbols provided by the a system OpenGLES 2.0
+ * driver.
+ *
+ * Once you have allocated an OpenGLES 2.0 context you can make it
+ * current using cogl_push_gles2_context(). For those familiar with
+ * using the EGL api, this serves a similar purpose to eglMakeCurrent.
+ *
+ * Before using this api applications can check for OpenGLES 2.0
+ * api support by checking for %COGL_FEATURE_ID_GLES2_CONTEXT support
+ * with cogl_has_feature(). This function will return %FALSE and
+ * return an %COGL_GLES2_CONTEXT_ERROR_UNSUPPORTED error if the
+ * feature isn't available.
+ *
+ * Since: 2.0
+ * Return value: A newly allocated #CoglGLES2Context or %NULL if there
+ * was an error and @error will be updated in that case.
+ * Stability: unstable
+ */
+CoglGLES2Context *
+cogl_gles2_context_new (CoglContext *ctx, GError **error);
+
+/**
+ * cogl_gles2_context_get_vtable:
+ * @gles2_ctx: A #CoglGLES2Context allocated with
+ * cogl_gles2_context_new()
+ *
+ * Queries the OpenGLES 2.0 api function pointers that should be
+ * used for rendering with the given @gles2_ctx.
+ *
+ * You should not try to directly link to and use the symbols
+ * provided by any system OpenGLES 2.0 driver.
+ *
+ * Since: 2.0
+ * Return value: A pointer to a #CoglGLES2Vtable providing pointers
+ * to functions for the full OpenGLES 2.0 api.
+ * Stability: unstable
+ */
+const CoglGLES2Vtable *
+cogl_gles2_context_get_vtable (CoglGLES2Context *gles2_ctx);
+
+/**
+ * cogl_push_gles2_context:
+ * @ctx: A #CoglContext
+ * @gles2_ctx: A #CoglGLES2Context allocated with
+ * cogl_gles2_context_new()
+ * @read_buffer: A #CoglFramebuffer to access to read operations
+ * such as glReadPixels. (must be a #CoglOffscreen
+ * framebuffer currently)
+ * @write_buffer: A #CoglFramebuffer to access for drawing operations
+ * such as glDrawArrays. (must be a #CoglOffscreen
+ * framebuffer currently)
+ * @error: A pointer to a #GError for returning exceptions
+ *
+ * Pushes the given @gles2_ctx onto a stack associated with @ctx so
+ * that the OpenGLES 2.0 api can be used instead of the Cogl
+ * rendering apis to read and write to the specified framebuffers.
+ *
+ * Usage of the api available through a #CoglGLES2Vtable is only
+ * allowed between cogl_push_gles2_context() and
+ * cogl_pop_gles2_context() calls.
+ *
+ * If there is a runtime problem with switching over to the given
+ * @gles2_ctx then this function will return %FALSE and return
+ * an error through @error.
+ *
+ * Since: 2.0
+ * Return value: %TRUE if operation was successfull or %FALSE
+ * otherwise and @error will be updated.
+ * Stability: unstable
+ */
+CoglBool
+cogl_push_gles2_context (CoglContext *ctx,
+ CoglGLES2Context *gles2_ctx,
+ CoglFramebuffer *read_buffer,
+ CoglFramebuffer *write_buffer,
+ GError **error);
+
+/**
+ * cogl_pop_gles2_context:
+ * @ctx: A #CoglContext
+ *
+ * Restores the previously active #CoglGLES2Context if there
+ * were nested calls to cogl_push_gles2_context() or otherwise
+ * restores the ability to render with the Cogl api instead
+ * of OpenGLES 2.0.
+ *
+ * The behaviour is undefined if calls to cogl_pop_gles2_context()
+ * are not balenced with the number of corresponding calls to
+ * cogl_push_gles2_context().
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+void
+cogl_pop_gles2_context (CoglContext *ctx);
+
+/**
+ * cogl_gles2_get_current_vtable:
+ *
+ * Returns the OpenGL ES 2.0 api vtable for the currently pushed
+ * #CoglGLES2Context (last pushed with cogl_push_gles2_context()) or
+ * %NULL if no #CoglGLES2Context has been pushed.
+ *
+ * Return value: The #CoglGLES2Vtable for the currently pushed
+ * #CoglGLES2Context or %NULL if none has been pushed.
+ * Since: 2.0
+ * Stability: unstable
+ */
+CoglGLES2Vtable *
+cogl_gles2_get_current_vtable (void);
+
+/**
+ * cogl_gles2_texture_2d_new_from_handle:
+ * @ctx: A #CoglContext
+ * @gles2_ctx: A #CoglGLES2Context allocated with
+ * cogl_gles2_context_new()
+ * @handle: An OpenGL ES 2.0 texture handle created with
+ * glGenTextures()
+ *
+ * Creates a #CoglTexture2D from an OpenGL ES 2.0 texture handle that
+ * was created within the given @gles2_ctx via glGenTextures(). The
+ * texture needs to have been associated with the GL_TEXTURE_2D target.
+ *
+ * This interface is only intended for sharing textures to read
+ * from. The behaviour is undefined if the texture is modified using
+ * the Cogl api.
+ *
+ * Applications should only pass this function handles that were
+ * created via a #CoglGLES2Vtable or via libcogl-gles2 and not pass
+ * handles created directly using the system's native libGLESv2
+ * api.
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+CoglTexture2D *
+cogl_gles2_texture_2d_new_from_handle (CoglContext *ctx,
+ CoglGLES2Context *gles2_ctx,
+ unsigned int handle,
+ int width,
+ int height,
+ CoglPixelFormat internal_format,
+ GError **error);
+
+/**
+ * cogl_gles2_texture_get_handle:
+ * @handle: A return location for an OpenGL ES 2.0 texture handle
+ * @target: A return location for an OpenGL ES 2.0 texture target
+ *
+ * Gets an OpenGL ES 2.0 texture handle for a #CoglTexture that can
+ * then be referenced by a #CoglGLES2Context. As well as returning
+ * a texture handle the texture's target (such as GL_TEXTURE_2D) is
+ * also returned.
+ *
+ * If the #CoglTexture can not be shared with a #CoglGLES2Context then
+ * this function will return %FALSE.
+ *
+ * This api does not affect the lifetime of the CoglTexture and you
+ * must take care not to reference the returned handle after the
+ * original texture has been freed.
+ *
+ * This interface is only intended for sharing textures to read
+ * from. The behaviour is undefined if the texture is modified by a
+ * GLES2 context.
+ *
+ * This function will only return %TRUE for low-level
+ * #CoglTextures such as #CoglTexture2D or #CoglTexture3D but
+ * not for high level meta textures such as
+ * #CoglTexture2DSliced
+ *
+ * The handle returned should not be passed directly to a system
+ * OpenGL ES 2.0 library, the handle is only intended to be used via
+ * a #CoglGLES2Vtable or via libcogl-gles2.
+ *
+ * Return value: %TRUE if a handle and target could be returned
+ * otherwise %FALSE is returned.
+ * Since: 2.0
+ * Stability: unstable
+ */
+CoglBool
+cogl_gles2_texture_get_handle (CoglTexture *texture,
+ unsigned int *handle,
+ unsigned int *target);
+
+/**
+ * cogl_is_gles2_context:
+ * @object: A #CoglObject pointer
+ *
+ * Gets whether the given object references a #CoglGLES2Context.
+ *
+ * Return value: %TRUE if the object references a #CoglGLES2Context
+ * and %FALSE otherwise.
+ * Since: 2.0
+ * Stability: unstable
+ */
+CoglBool
+cogl_is_gles2_context (void *object);
+
+G_END_DECLS
+
+#endif /* __COGL_GLES2_H__ */
+
diff --git a/cogl/cogl.h b/cogl/cogl.h
index 2462984ed..797cdb765 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -108,7 +108,7 @@
#include
#include
#endif
-#if COGL_HAS_WIN32_SUPPORT
+#ifdef COGL_HAS_WIN32_SUPPORT
#include
#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 dd96ccf8c..269d65d81 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 fbaad7402..8d57904a7 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 c2ad357d8..8ff03c442 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
@@ -541,10 +541,10 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglDisplayEGL *egl_display = display->winsys;
- 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,
diff --git a/cogl/winsys/cogl-winsys-egl-null.c b/cogl/winsys/cogl-winsys-egl-null.c
index 20f209f60..65da170a2 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 000fe510d..27274bb50 100644
--- a/cogl/winsys/cogl-winsys-egl-private.h
+++ b/cogl/winsys/cogl-winsys-egl-private.h
@@ -113,13 +113,18 @@ typedef struct _CoglDisplayEGL
CoglBool found_egl_config;
CoglBool stencil_disabled;
+ EGLSurface current_read_surface;
+ EGLSurface current_draw_surface;
+ EGLContext current_context;
+
/* 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
@@ -133,6 +138,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 cabe632e0..c1dec2443 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 8b4551c08..94a941083 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 e0e8bb5f7..b2413adc5 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)
@@ -289,6 +323,33 @@ 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 &&
+ egl_display->current_context == context)
+ return EGL_TRUE;
+
+ ret = eglMakeCurrent (egl_renderer->edpy,
+ draw,
+ read,
+ context);
+
+ egl_display->current_draw_surface = draw;
+ egl_display->current_read_surface = read;
+ egl_display->current_context = context;
+
+ return ret;
+}
+
static void
cleanup_context (CoglDisplay *display)
{
@@ -298,8 +359,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;
}
@@ -416,6 +478,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;
@@ -435,6 +504,54 @@ _cogl_winsys_context_deinit (CoglContext *context)
g_free (context->winsys);
}
+typedef struct _CoglGLES2ContextEGL
+{
+ EGLContext egl_context;
+ EGLSurface dummy_surface;
+} CoglGLES2ContextEGL;
+
+static 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;
+}
+
+static void
+_cogl_winsys_destroy_gles2_context (CoglGLES2Context *gles2_ctx)
+{
+ CoglContext *context = gles2_ctx->context;
+ CoglDisplay *display = context->display;
+ CoglDisplayEGL *egl_display = display->winsys;
+ CoglRenderer *renderer = display->renderer;
+ CoglRendererEGL *egl_renderer = renderer->winsys;
+ EGLContext egl_context = gles2_ctx->winsys;
+
+ _COGL_RETURN_IF_FAIL (egl_display->current_context != egl_context);
+
+ eglDestroyContext (egl_renderer->edpy, egl_context);
+}
+
static CoglBool
_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
GError **error)
@@ -524,30 +641,36 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
onscreen->winsys = NULL;
}
-static void
-_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
+static CoglBool
+bind_onscreen (CoglOnscreen *onscreen)
{
CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
CoglContext *context = fb->context;
CoglDisplayEGL *egl_display = context->display->winsys;
- 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;
+ CoglBool status = _cogl_winsys_egl_make_current (context->display,
+ egl_onscreen->egl_surface,
+ egl_onscreen->egl_surface,
+ egl_display->egl_context);
+ if (status)
+ {
+ CoglRenderer *renderer = context->display->renderer;
+ CoglRendererEGL *egl_renderer = renderer->winsys;
- eglMakeCurrent (egl_renderer->edpy,
- egl_onscreen->egl_surface,
- egl_onscreen->egl_surface,
- egl_display->egl_context);
- egl_context->current_surface = egl_onscreen->egl_surface;
+ if (fb->config.swap_throttled)
+ eglSwapInterval (egl_renderer->edpy, 1);
+ else
+ eglSwapInterval (egl_renderer->edpy, 0);
+ }
- if (fb->config.swap_throttled)
- eglSwapInterval (egl_renderer->edpy, 1);
- else
- eglSwapInterval (egl_renderer->edpy, 0);
+ return status;
+}
+
+static void
+_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
+{
+ bind_onscreen (onscreen);
}
static void
@@ -613,13 +736,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);
}
@@ -632,6 +755,58 @@ _cogl_winsys_context_egl_get_egl_display (CoglContext *context)
return egl_renderer->edpy;
}
+static 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;
+}
+
+static CoglBool
+_cogl_winsys_set_gles2_context (CoglGLES2Context *gles2_ctx, GError **error)
+{
+ CoglContext *ctx = gles2_ctx->context;
+ CoglDisplayEGL *egl_display = ctx->display->winsys;
+ CoglBool status;
+
+ if (gles2_ctx->write_buffer &&
+ cogl_is_onscreen (gles2_ctx->write_buffer))
+ {
+ status = bind_onscreen (COGL_ONSCREEN (gles2_ctx->write_buffer));
+ }
+ else
+ status = _cogl_winsys_egl_make_current (ctx->display,
+ egl_display->dummy_surface,
+ egl_display->dummy_surface,
+ gles2_ctx->winsys);
+
+ if (!status)
+ {
+ g_set_error (error,
+ COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_MAKE_CURRENT,
+ "Failed to make gles2 context current");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static 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,
@@ -648,6 +823,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,
@@ -655,6 +833,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 53327237a..cd9ca2e66 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.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);
+
CoglBool
(*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);
+
+ CoglBool
+ (*set_gles2_context) (CoglGLES2Context *gles2_ctx, GError **error);
+
+ void
+ (*restore_context) (CoglContext *ctx);
+
+ void
+ (*destroy_gles2_context) (CoglGLES2Context *gles2_ctx);
+
} CoglWinsysVtable;
CoglBool
diff --git a/examples/Makefile.am b/examples/Makefile.am
index f96ae653b..7fd76a565 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -18,7 +18,13 @@ common_ldadd = \
$(COGL_DEP_LIBS) \
$(top_builddir)/cogl/libcogl.la
-programs = cogl-hello cogl-info cogl-msaa
+programs = cogl-info
+
+cogl_info_SOURCES = cogl-info.c
+cogl_info_LDADD = $(common_ldadd)
+
+if USE_GLIB
+programs += cogl-hello cogl-msaa cogl-gles2-context
examples_datadir = $(pkgdatadir)/examples-data
examples_data_DATA =
@@ -57,6 +63,11 @@ 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)
+
+endif #USE_GLIB
+
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 000000000..c25b73d5e
--- /dev/null
+++ b/examples/cogl-gles2-context.c
@@ -0,0 +1,135 @@
+#include
+#include
+#include
+#include
+
+#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;
+ const CoglGLES2Vtable *gles2_vtable;
+} Data;
+
+static gboolean
+paint_cb (void *user_data)
+{
+ Data *data = user_data;
+ GError *error = NULL;
+ const CoglGLES2Vtable *gles2 = data->gles2_vtable;
+
+ /* Draw scene with GLES2 */
+ if (!cogl_push_gles2_context (data->ctx,
+ data->gles2_ctx,
+ data->fb,
+ data->fb,
+ &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);
+
+ /* Draw scene with Cogl */
+ cogl_framebuffer_draw_primitive (data->fb, data->pipeline, data->triangle);
+
+ 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);
+
+ /* Draw scene with GLES2 */
+ if (!cogl_push_gles2_context (data.ctx,
+ data.gles2_ctx,
+ data.fb,
+ data.fb,
+ &error))
+ {
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+ }
+
+ cogl_pop_gles2_context (data.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 988e99182..b7dab0071 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."
}
};