1
0
Fork 0
mutter-performance-source/cogl/cogl-gles2-context.c
Neil Roberts 12a1ef72c0 cogl-gles2-context: Keep some extra data for shaders and programs
All of the functions that create and destroy shaders are now wrapped
in the CoglGLES2Context so that we can track some extra data for them.
There are hash tables mapping object IDs to the corresponding data.
The data is currently not used for anything but will be in later
patches.

The glUseProgram, glAttachShader and glDetachShader functions
additionally need to be wrapped because GL does not delete shader
objects that are in use. Therefore we need to have a reference count
on the data so we can recognise when the last use has been removed.

The IDs are assumed to be specific to an individual CoglGLES2Context.
This is technically not the case because all of the CoglGLES2Contexts
are in the same share list. However we don't really want this to be
the case so currently we will assume sharing the object IDs between
contexts is undefined behaviour. Eventually we may want to actually
enforce this.

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

(cherry picked from commit 05dc1e34785ae5f5484cd398ecc5464bd8bd3dcd)
2012-08-14 18:55:42 +01:00

829 lines
26 KiB
C

/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2011 Collabora Ltd.
* Copyright (C) 2012 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
* Authors:
* Tomeu Vizoso <tomeu.vizoso@collabora.com>
* Robert Bragg <robert@linux.intel.com>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cogl-gles2.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");
}
static void
shader_data_unref (CoglGLES2Context *context,
CoglGLES2ShaderData *shader_data)
{
if (--shader_data->ref_count < 1)
/* Removing the hash table entry should also destroy the data */
g_hash_table_remove (context->shader_map,
GINT_TO_POINTER (shader_data->object_id));
}
static void
program_data_unref (CoglGLES2ProgramData *program_data)
{
if (--program_data->ref_count < 1)
/* Removing the hash table entry should also destroy the data */
g_hash_table_remove (program_data->context->program_map,
GINT_TO_POINTER (program_data->object_id));
}
static void
detach_shader (CoglGLES2ProgramData *program_data,
CoglGLES2ShaderData *shader_data)
{
GList *l;
for (l = program_data->attached_shaders; l; l = l->next)
{
if (l->data == shader_data)
{
shader_data_unref (program_data->context, shader_data);
program_data->attached_shaders =
g_list_delete_link (program_data->attached_shaders, l);
break;
}
}
}
/* 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 GLuint
gl_create_shader_wrapper (GLenum type)
{
CoglGLES2Context *gles2_ctx = current_gles2_context;
GLuint id;
id = gles2_ctx->context->glCreateShader (type);
if (id != 0)
{
CoglGLES2ShaderData *data = g_slice_new (CoglGLES2ShaderData);
data->object_id = id;
data->type = type;
data->ref_count = 1;
data->deleted = FALSE;
g_hash_table_insert (gles2_ctx->shader_map,
GINT_TO_POINTER (id),
data);
}
return id;
}
static void
gl_delete_shader_wrapper (GLuint shader)
{
CoglGLES2Context *gles2_ctx = current_gles2_context;
CoglGLES2ShaderData *shader_data;
if ((shader_data = g_hash_table_lookup (gles2_ctx->shader_map,
GINT_TO_POINTER (shader))) &&
!shader_data->deleted)
{
shader_data->deleted = TRUE;
shader_data_unref (gles2_ctx, shader_data);
}
gles2_ctx->context->glDeleteShader (shader);
}
static GLuint
gl_create_program_wrapper (void)
{
CoglGLES2Context *gles2_ctx = current_gles2_context;
GLuint id;
id = gles2_ctx->context->glCreateProgram ();
if (id != 0)
{
CoglGLES2ProgramData *data = g_slice_new (CoglGLES2ProgramData);
data->object_id = id;
data->attached_shaders = NULL;
data->ref_count = 1;
data->deleted = FALSE;
data->context = gles2_ctx;
g_hash_table_insert (gles2_ctx->program_map,
GINT_TO_POINTER (id),
data);
}
return id;
}
static void
gl_delete_program_wrapper (GLuint program)
{
CoglGLES2Context *gles2_ctx = current_gles2_context;
CoglGLES2ProgramData *program_data;
if ((program_data = g_hash_table_lookup (gles2_ctx->program_map,
GINT_TO_POINTER (program))) &&
!program_data->deleted)
{
program_data->deleted = TRUE;
program_data_unref (program_data);
}
gles2_ctx->context->glDeleteProgram (program);
}
static void
gl_use_program_wrapper (GLuint program)
{
CoglGLES2Context *gles2_ctx = current_gles2_context;
CoglGLES2ProgramData *program_data;
program_data = g_hash_table_lookup (gles2_ctx->program_map,
GINT_TO_POINTER (program));
if (program_data)
program_data->ref_count++;
if (gles2_ctx->current_program)
program_data_unref (gles2_ctx->current_program);
gles2_ctx->current_program = program_data;
gles2_ctx->context->glUseProgram (program);
}
static void
gl_attach_shader_wrapper (GLuint program,
GLuint shader)
{
CoglGLES2Context *gles2_ctx = current_gles2_context;
CoglGLES2ProgramData *program_data;
CoglGLES2ShaderData *shader_data;
if ((program_data = g_hash_table_lookup (gles2_ctx->program_map,
GINT_TO_POINTER (program))) &&
(shader_data = g_hash_table_lookup (gles2_ctx->shader_map,
GINT_TO_POINTER (shader))) &&
/* Ignore attempts to attach a shader that is already attached */
g_list_find (program_data->attached_shaders, shader_data) == NULL)
{
shader_data->ref_count++;
program_data->attached_shaders =
g_list_prepend (program_data->attached_shaders, shader_data);
}
gles2_ctx->context->glAttachShader (program, shader);
}
static void
gl_detach_shader_wrapper (GLuint program,
GLuint shader)
{
CoglGLES2Context *gles2_ctx = current_gles2_context;
CoglGLES2ProgramData *program_data;
CoglGLES2ShaderData *shader_data;
if ((program_data = g_hash_table_lookup (gles2_ctx->program_map,
GINT_TO_POINTER (program))) &&
(shader_data = g_hash_table_lookup (gles2_ctx->shader_map,
GINT_TO_POINTER (shader))))
detach_shader (program_data, shader_data);
gles2_ctx->context->glDetachShader (program, shader);
}
static void
_cogl_gles2_offscreen_free (CoglGLES2Offscreen *gles2_offscreen)
{
COGL_LIST_REMOVE (gles2_offscreen, list_node);
g_slice_free (CoglGLES2Offscreen, gles2_offscreen);
}
static void
force_delete_program_object (CoglGLES2Context *context,
CoglGLES2ProgramData *program_data)
{
if (!program_data->deleted)
{
context->context->glDeleteProgram (program_data->object_id);
program_data->deleted = TRUE;
program_data_unref (program_data);
}
}
static void
force_delete_shader_object (CoglGLES2Context *context,
CoglGLES2ShaderData *shader_data)
{
if (!shader_data->deleted)
{
context->context->glDeleteShader (shader_data->object_id);
shader_data->deleted = TRUE;
shader_data_unref (context, shader_data);
}
}
static void
_cogl_gles2_context_free (CoglGLES2Context *gles2_context)
{
CoglContext *ctx = gles2_context->context;
const CoglWinsysVtable *winsys;
GList *objects, *l;
if (gles2_context->current_program)
program_data_unref (gles2_context->current_program);
/* Try to forcibly delete any shaders and programs so that they
* won't get leaked. Because all GLES2 contexts are in the same
* share list as Cogl's context these won't get deleted by default.
* FIXME: we should do this for all of the other resources too, like
* textures */
objects = g_hash_table_get_values (gles2_context->program_map);
for (l = objects; l; l = l->next)
force_delete_program_object (gles2_context, l->data);
g_list_free (objects);
objects = g_hash_table_get_values (gles2_context->shader_map);
for (l = objects; l; l = l->next)
force_delete_shader_object (gles2_context, l->data);
g_list_free (objects);
/* All of the program and shader objects should now be destroyed */
if (g_hash_table_size (gles2_context->program_map) > 0)
g_warning ("Program objects have been leaked from a CoglGLES2Context");
if (g_hash_table_size (gles2_context->shader_map) > 0)
g_warning ("Shader objects have been leaked from a CoglGLES2Context");
g_hash_table_destroy (gles2_context->program_map);
g_hash_table_destroy (gles2_context->shader_map);
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);
}
static void
free_shader_data (CoglGLES2ShaderData *data)
{
g_slice_free (CoglGLES2ShaderData, data);
}
static void
free_program_data (CoglGLES2ProgramData *data)
{
while (data->attached_shaders)
detach_shader (data,
data->attached_shaders->data);
g_slice_free (CoglGLES2ProgramData, data);
}
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;
gles2_ctx->vtable->glCreateShader = gl_create_shader_wrapper;
gles2_ctx->vtable->glDeleteShader = gl_delete_shader_wrapper;
gles2_ctx->vtable->glCreateProgram = gl_create_program_wrapper;
gles2_ctx->vtable->glDeleteProgram = gl_delete_program_wrapper;
gles2_ctx->vtable->glUseProgram = gl_use_program_wrapper;
gles2_ctx->vtable->glAttachShader = gl_attach_shader_wrapper;
gles2_ctx->vtable->glDetachShader = gl_detach_shader_wrapper;
gles2_ctx->shader_map =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL, /* key_destroy */
(GDestroyNotify) free_shader_data);
gles2_ctx->program_map =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL, /* key_destroy */
(GDestroyNotify) free_program_data);
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;
/* If this is the first time this gles2 context has been used then
* we'll force the viewport and scissor to the right size. GL has
* the semantics that the viewport and scissor default to the size
* of the first surface the context is used with. If the first
* CoglFramebuffer that this context is used with is an offscreen,
* then the surface from GL's point of view will be the 1x1 dummy
* surface so the viewport will be wrong. Therefore we just override
* the default viewport and scissor here */
if (!gles2_ctx->has_been_bound)
{
int fb_width = cogl_framebuffer_get_width (write_buffer);
int fb_height = cogl_framebuffer_get_height (write_buffer);
gles2_ctx->vtable->glViewport (0, 0, /* x/y */
fb_width, fb_height);
gles2_ctx->vtable->glScissor (0, 0, /* x/y */
fb_width, fb_height);
gles2_ctx->has_been_bound = TRUE;
}
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);
}