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." } };