[Cogl] [PATCH v3] Adds initial GLES2 integration support
Robert Bragg
robert at sixbynine.org
Wed May 16 05:54:42 PDT 2012
From: Robert Bragg <robert at linux.intel.com>
Ok, here's another update with the following changes:
* Uses g_queue_init() instead of g_queue_new()
* Uses an embedded list for the gles2-offscreens
* Fixes how we free gles2-offscreens to ensure they are removed from
the foreign_offscreens list.
* Fixes building without EGL
* Wraps glCopyTex{Sub}Image2D
* Documents that textures shared from gles2 to Cogl or vica versa
should be considered read only for now.
kind regards,
- Robert
-- >8 --
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 optimize
the cost of allocating multiple GLES2 contexts and switching between
them which can both be very expensive with many 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 at collabora.com> who did the first iteration of adding GLES2
API support to Cogl so that WebGL support could be added to
webkit-clutter.
This patch adds a very minimal cogl-gles2-context example that shows how
to create a gles2 context, clear the screen to a random color and also
draw a triangle with the cogl api.
---
cogl/Makefile.am | 14 +
cogl/cogl-context-private.h | 7 +
cogl/cogl-context.c | 6 +-
cogl/cogl-context.h | 4 +
cogl/cogl-framebuffer-private.h | 33 ++-
cogl/cogl-framebuffer.c | 380 +++++++++++++++---------
cogl/cogl-gles2-context-private.h | 68 ++++
cogl/cogl-gles2-context.c | 542 +++++++++++++++++++++++++++++++++
cogl/cogl-gles2-types.h | 474 ++++++++++++++++++++++++++++
cogl/cogl-gles2.h | 368 ++++++++++++++++++++++
cogl/cogl.h | 2 +-
cogl/winsys/cogl-winsys-egl-android.c | 8 +-
cogl/winsys/cogl-winsys-egl-gdl.c | 8 +-
cogl/winsys/cogl-winsys-egl-kms.c | 8 +-
cogl/winsys/cogl-winsys-egl-null.c | 8 +-
cogl/winsys/cogl-winsys-egl-private.h | 13 +-
cogl/winsys/cogl-winsys-egl-wayland.c | 10 +-
cogl/winsys/cogl-winsys-egl-x11.c | 8 +-
cogl/winsys/cogl-winsys-egl.c | 225 +++++++++++++--
cogl/winsys/cogl-winsys-private.h | 18 ++
examples/Makefile.am | 5 +-
examples/cogl-gles2-context.c | 135 ++++++++
examples/cogl-info.c | 6 +
23 files changed, 2159 insertions(+), 191 deletions(-)
create mode 100644 cogl/cogl-gles2-context-private.h
create mode 100644 cogl/cogl-gles2-context.c
create mode 100644 cogl/cogl-gles2-types.h
create mode 100644 cogl/cogl-gles2.h
create mode 100644 examples/cogl-gles2-context.c
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index c363f9b..3c5500c 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -74,6 +74,8 @@ cogl_experimental_h = \
$(srcdir)/cogl-pipeline-layer-state.h \
$(srcdir)/cogl-snippet.h \
$(srcdir)/cogl-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 \
@@ -99,6 +101,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 =
@@ -333,6 +343,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
@@ -477,6 +488,9 @@ if USE_GLIB
nodist_coglinclude_HEADERS += cogl-enum-types.h
endif
+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 a1776dc..48c170e 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
{
@@ -172,6 +173,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 */
CoglPipeline *stencil_pipeline;
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 73871d4..a971bc9 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
@@ -303,6 +303,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;
@@ -466,6 +468,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 21ea636..757b1a8 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 4c95f73..9922a1a 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 45af11b..63d8c4b 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;
@@ -793,23 +786,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 != NULL)
cogl_object_unref (offscreen->texture);
@@ -817,72 +818,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 (!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)
+ if (flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL |
+ COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH24_STENCIL8))
{
- 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 */
@@ -905,13 +854,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
@@ -928,13 +879,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)
@@ -949,28 +901,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;
}
@@ -987,21 +1002,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
@@ -1015,41 +1049,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,
+ 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))
{
- 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;
}
CoglBool
@@ -1309,14 +1408,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 =
@@ -1665,7 +1767,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
@@ -1676,8 +1778,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 0000000..4512de4
--- /dev/null
+++ b/cogl/cogl-gles2-context-private.h
@@ -0,0 +1,68 @@
+/*
+ * 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 at collabora.com>
+ * Robert Bragg <robert at 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 _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 0000000..7fbf2ff
--- /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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Tomeu Vizoso <tomeu.vizoso at collabora.com>
+ * Robert Bragg <robert at linux.intel.com>
+ *
+ */
+
+#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->glCopyTexImage2D (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 0000000..9f6d097
--- /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 <stdint.h>
+
+#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 0000000..56ff64d
--- /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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Tomeu Vizoso <tomeu.vizoso at collabora.com>
+ * Robert Bragg <robert at linux.intel.com>
+ *
+ */
+
+#ifndef __COGL_GLES2_H__
+#define __COGL_GLES2_H__
+
+#define __COGL_H_INSIDE__
+#include <cogl/cogl-defines.h>
+#include <cogl/cogl-context.h>
+#include <cogl/cogl-framebuffer.h>
+#include <cogl/cogl-texture.h>
+#include <cogl/cogl-texture-2d.h>
+
+/* 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 <cogl/cogl-gles2-types.h>
+#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 <cogl/gl-prototypes/cogl-gles2-functions.h>
+
+#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.
+ *
+ * <note>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.</note>
+ *
+ * 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.
+ *
+ * <note>You should not try to directly link to and use the symbols
+ * provided by any system OpenGLES 2.0 driver.</note>
+ *
+ * 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.
+ *
+ * <note>This interface is only intended for sharing textures to read
+ * from. The behaviour is undefined if the texture is modified using
+ * the Cogl api.</note>
+ *
+ * <note>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.</note>
+ *
+ * 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.
+ *
+ * <note>This interface is only intended for sharing textures to read
+ * from. The behaviour is undefined if the texture is modified by a
+ * GLES2 context.</note>
+ *
+ * <note>This function will only return %TRUE for low-level
+ * #CoglTexture<!-- -->s such as #CoglTexture2D or #CoglTexture3D but
+ * not for high level meta textures such as
+ * #CoglTexture2DSliced</note>
+ *
+ * <note>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.</note>
+ *
+ * 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 7ce7e32..f2c915b 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -102,7 +102,7 @@
#include <cogl/cogl-kms-renderer.h>
#include <cogl/cogl-kms-display.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 dd96ccf..269d65d 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 fbaad74..8d57904 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 c2ad357..8ff03c4 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 20f209f..65da170 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 000fe51..27274bb 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 cabe632..c1dec24 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 8b4551c..94a9410 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 e0e8bb5..b2413ad 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;
+
+ if (fb->config.swap_throttled)
+ eglSwapInterval (egl_renderer->edpy, 1);
+ else
+ eglSwapInterval (egl_renderer->edpy, 0);
+ }
- eglMakeCurrent (egl_renderer->edpy,
- egl_onscreen->egl_surface,
- egl_onscreen->egl_surface,
- egl_display->egl_context);
- egl_context->current_surface = egl_onscreen->egl_surface;
+ return status;
+}
- if (fb->config.swap_throttled)
- eglSwapInterval (egl_renderer->edpy, 1);
- else
- eglSwapInterval (egl_renderer->edpy, 0);
+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 5332723..cd9ca2e 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 fec0a65..1dab73c 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -23,7 +23,7 @@ cogl_info_SOURCES = cogl-info.c
cogl_info_LDADD = $(common_ldadd)
if USE_GLIB
-programs += cogl-hello cogl-msaa
+programs += cogl-hello cogl-msaa cogl-gles2-context
examples_datadir = $(pkgdatadir)/examples-data
examples_data_DATA =
@@ -60,6 +60,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)
+
endif #USE_GLIB
if INSTALL_EXAMPLES
diff --git a/examples/cogl-gles2-context.c b/examples/cogl-gles2-context.c
new file mode 100644
index 0000000..c25b73d
--- /dev/null
+++ b/examples/cogl-gles2-context.c
@@ -0,0 +1,135 @@
+#include <cogl/cogl.h>
+#include <cogl/cogl-gles2.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;
+ 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 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."
}
};
--
1.7.7.6
More information about the Cogl
mailing list