[Cogl] [PATCH 7/8] cogl-gles2-context: Keep track of extra data per texture object
Robert Bragg
robert at sixbynine.org
Thu Aug 9 10:22:05 PDT 2012
This looks good to land to me:
Reviewed-by: Robert Bragg <robert at linux.intel.com>
thanks,
- Robert
On Thu, Aug 9, 2012 at 5:08 PM, Neil Roberts <neil at linux.intel.com> wrote:
> This patch adds a hash table mapping texture object IDs to a struct so
> that we can keep track of some of the state for each texture object.
> Currently it will just track the width and height of the texture 2D
> target.
>
> Additionally it will now try to delete any texture objects that have
> data created for them by the GLES2 context so that it won't leak them.
> It only tracks objects that get data set on them, not all objects that
> are bound because it is possible to use the GLES2 context with foreign
> textures via cogl_gles2_texture_get_handle() and we don't want to
> delete those.
>
> In order to keep track of the currently bound texture object it also
> needs to track the active texture unit.
>
> Note that this state tracking will probably go wrong if GL throws an
> error for invalid state. For example if glActiveTexture is called with
> an invalid texture unit then GL will ignore the binding but Cogl will
> assume it is valid and the state tracking will get out of sync.
> Perhaps it would be good if Cogl could detect the errors but this is
> difficult to do without consuming them.
> ---
> cogl/cogl-gles2-context-private.h | 32 ++++++
> cogl/cogl-gles2-context.c | 212 +++++++++++++++++++++++++++++++++++++-
> 2 files changed, 240 insertions(+), 4 deletions(-)
>
> diff --git a/cogl/cogl-gles2-context-private.h b/cogl/cogl-gles2-context-private.h
> index 1325ad4..f948548 100644
> --- a/cogl/cogl-gles2-context-private.h
> +++ b/cogl/cogl-gles2-context-private.h
> @@ -105,6 +105,26 @@ typedef struct
> CoglGLES2Context *context;
> } CoglGLES2ProgramData;
>
> +/* State tracked for each texture unit */
> +typedef struct
> +{
> + /* The currently bound texture for the GL_TEXTURE_2D */
> + GLuint current_texture_2d;
> +} CoglGLES2TextureUnitData;
> +
> +/* State tracked for each texture object */
> +typedef struct
> +{
> + /* GL's ID for this object */
> + GLuint object_id;
> +
> + GLenum target;
> +
> + /* The details for texture when it has a 2D target */
> + int width, height;
> + GLenum format;
> +} CoglGLES2TextureObjectData;
> +
> struct _CoglGLES2Context
> {
> CoglObject _parent;
> @@ -165,6 +185,18 @@ struct _CoglGLES2Context
> * results of glReadPixels read from a CoglOffscreen */
> int pack_alignment;
>
> + /* A hash table of CoglGLES2TextureObjects indexed by the texture
> + * object ID so that we can track some state */
> + GHashTable *texture_object_map;
> +
> + /* Array of CoglGLES2TextureUnits to keep track of state for each
> + * texture unit */
> + GArray *texture_units;
> +
> + /* The currently active texture unit indexed from 0 (not from
> + * GL_TEXTURE0) */
> + int current_texture_unit;
> +
> void *winsys;
> };
>
> diff --git a/cogl/cogl-gles2-context.c b/cogl/cogl-gles2-context.c
> index c339ba1..a7507c6 100644
> --- a/cogl/cogl-gles2-context.c
> +++ b/cogl/cogl-gles2-context.c
> @@ -23,6 +23,7 @@
> * Authors:
> * Tomeu Vizoso <tomeu.vizoso at collabora.com>
> * Robert Bragg <robert at linux.intel.com>
> + * Neil Roberts <neil at linux.intel.com>
> *
> */
>
> @@ -181,6 +182,65 @@ update_current_flip_state (CoglGLES2Context *gles2_ctx)
> }
> }
>
> +static GLuint
> +get_current_texture_2d_object (CoglGLES2Context *gles2_ctx)
> +{
> + return g_array_index (gles2_ctx->texture_units,
> + CoglGLES2TextureUnitData,
> + gles2_ctx->current_texture_unit).current_texture_2d;
> +}
> +
> +static void
> +set_texture_object_data (CoglGLES2Context *gles2_ctx,
> + GLenum target,
> + GLint level,
> + GLenum internal_format,
> + GLsizei width,
> + GLsizei height)
> +{
> + GLuint texture_id = get_current_texture_2d_object (gles2_ctx);
> + CoglGLES2TextureObjectData *texture_object;
> +
> + /* We want to keep track of all texture objects where the data is
> + * created by this context so that we can delete them later */
> + texture_object = g_hash_table_lookup (gles2_ctx->texture_object_map,
> + GUINT_TO_POINTER (texture_id));
> + if (texture_object == NULL)
> + {
> + texture_object = g_slice_new0 (CoglGLES2TextureObjectData);
> + texture_object->object_id = texture_id;
> +
> + g_hash_table_insert (gles2_ctx->texture_object_map,
> + GUINT_TO_POINTER (texture_id),
> + texture_object);
> + }
> +
> + switch (target)
> + {
> + case GL_TEXTURE_2D:
> + texture_object->target = GL_TEXTURE_2D;
> +
> + /* We want to keep track of the dimensions of any texture object
> + * setting the GL_TEXTURE_2D target */
> + if (level == 0)
> + {
> + texture_object->width = width;
> + texture_object->height = height;
> + texture_object->format = internal_format;
> + }
> + break;
> +
> + case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
> + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
> + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
> + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
> + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
> + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
> + texture_object->target = GL_TEXTURE_CUBE_MAP;
> + break;
> + }
> +}
> +
> /* We wrap glBindFramebuffer so that when framebuffer 0 is bound
> * we can instead bind the write_framebuffer passed to
> * cogl_push_gles2_context().
> @@ -369,7 +429,7 @@ gl_read_pixels_wrapper (GLint x,
> static void
> gl_copy_tex_image_2d_wrapper (GLenum target,
> GLint level,
> - GLenum internalformat,
> + GLenum internal_format,
> GLint x,
> GLint y,
> GLsizei width,
> @@ -379,10 +439,16 @@ gl_copy_tex_image_2d_wrapper (GLenum target,
> CoglGLES2Context *gles2_ctx = current_gles2_context;
> int restore_mode = transient_bind_read_buffer (gles2_ctx);
>
> - gles2_ctx->context->glCopyTexImage2D (target, level, internalformat,
> + gles2_ctx->context->glCopyTexImage2D (target, level, internal_format,
> x, y, width, height, border);
>
> restore_write_buffer (gles2_ctx, restore_mode);
> +
> + set_texture_object_data (gles2_ctx,
> + target,
> + level,
> + internal_format,
> + width, height);
> }
>
> static void
> @@ -1069,6 +1135,108 @@ gl_pixel_store_i_wrapper (GLenum pname, GLint param)
> }
>
> static void
> +gl_active_texture_wrapper (GLenum texture)
> +{
> + CoglGLES2Context *gles2_ctx = current_gles2_context;
> + int texture_unit;
> +
> + gles2_ctx->context->glActiveTexture (texture);
> +
> + texture_unit = texture - GL_TEXTURE0;
> +
> + /* If the application is binding some odd looking texture unit
> + * numbers then we'll just ignore it and hope that GL has generated
> + * an error */
> + if (texture_unit >= 0 && texture_unit < 512)
> + {
> + gles2_ctx->current_texture_unit = texture_unit;
> + g_array_set_size (gles2_ctx->texture_units,
> + MAX (texture_unit, gles2_ctx->texture_units->len));
> + }
> +}
> +
> +static void
> +gl_delete_textures_wrapper (GLsizei n,
> + const GLuint *textures)
> +{
> + CoglGLES2Context *gles2_ctx = current_gles2_context;
> + int texture_index;
> + int texture_unit;
> +
> + gles2_ctx->context->glDeleteTextures (n, textures);
> +
> + for (texture_index = 0; texture_index < n; texture_index++)
> + {
> + /* Reset any texture units that have any of these textures bound */
> + for (texture_unit = 0;
> + texture_unit < gles2_ctx->texture_units->len;
> + texture_unit++)
> + {
> + CoglGLES2TextureUnitData *unit =
> + &g_array_index (gles2_ctx->texture_units,
> + CoglGLES2TextureUnitData,
> + texture_unit);
> +
> + if (unit->current_texture_2d == textures[texture_index])
> + unit->current_texture_2d = 0;
> + }
> +
> + /* Remove the binding. We can do this immediately because unlike
> + * shader objects the deletion isn't delayed until the object is
> + * unbound */
> + g_hash_table_remove (gles2_ctx->texture_object_map,
> + GUINT_TO_POINTER (textures[texture_index]));
> + }
> +}
> +
> +static void
> +gl_bind_texture_wrapper (GLenum target,
> + GLuint texture)
> +{
> + CoglGLES2Context *gles2_ctx = current_gles2_context;
> +
> + gles2_ctx->context->glBindTexture (target, texture);
> +
> + if (target == GL_TEXTURE_2D)
> + {
> + CoglGLES2TextureUnitData *unit =
> + &g_array_index (gles2_ctx->texture_units,
> + CoglGLES2TextureUnitData,
> + gles2_ctx->current_texture_unit);
> + unit->current_texture_2d = texture;
> + }
> +}
> +
> +static void
> +gl_tex_image_2d_wrapper (GLenum target,
> + GLint level,
> + GLint internal_format,
> + GLsizei width,
> + GLsizei height,
> + GLint border,
> + GLenum format,
> + GLenum type,
> + const GLvoid *pixels)
> +{
> + CoglGLES2Context *gles2_ctx = current_gles2_context;
> +
> + gles2_ctx->context->glTexImage2D (target,
> + level,
> + internal_format,
> + width, height,
> + border,
> + format,
> + type,
> + pixels);
> +
> + set_texture_object_data (gles2_ctx,
> + target,
> + level,
> + internal_format,
> + width, height);
> +}
> +
> +static void
> _cogl_gles2_offscreen_free (CoglGLES2Offscreen *gles2_offscreen)
> {
> COGL_LIST_REMOVE (gles2_offscreen, list_node);
> @@ -1100,6 +1268,13 @@ force_delete_shader_object (CoglGLES2Context *context,
> }
>
> static void
> +force_delete_texture_object (CoglGLES2Context *context,
> + CoglGLES2TextureObjectData *texture_data)
> +{
> + context->context->glDeleteTextures (1, &texture_data->object_id);
> +}
> +
> +static void
> _cogl_gles2_context_free (CoglGLES2Context *gles2_context)
> {
> CoglContext *ctx = gles2_context->context;
> @@ -1111,8 +1286,8 @@ _cogl_gles2_context_free (CoglGLES2Context *gles2_context)
> 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
> + /* Try to forcibly delete any shaders, programs and textures 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 */
> @@ -1124,6 +1299,10 @@ _cogl_gles2_context_free (CoglGLES2Context *gles2_context)
> for (l = objects; l; l = l->next)
> force_delete_shader_object (gles2_context, l->data);
> g_list_free (objects);
> + objects = g_hash_table_get_values (gles2_context->texture_object_map);
> + for (l = objects; l; l = l->next)
> + force_delete_texture_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)
> @@ -1134,6 +1313,9 @@ _cogl_gles2_context_free (CoglGLES2Context *gles2_context)
> g_hash_table_destroy (gles2_context->program_map);
> g_hash_table_destroy (gles2_context->shader_map);
>
> + g_hash_table_destroy (gles2_context->texture_object_map);
> + g_array_free (gles2_context->texture_units, TRUE);
> +
> winsys = ctx->display->renderer->winsys_vtable;
> winsys->destroy_gles2_context (gles2_context);
>
> @@ -1173,6 +1355,12 @@ free_program_data (CoglGLES2ProgramData *data)
> g_slice_free (CoglGLES2ProgramData, data);
> }
>
> +static void
> +free_texture_object_data (CoglGLES2TextureObjectData *data)
> +{
> + g_slice_free (CoglGLES2TextureObjectData, data);
> +}
> +
> static GLuint
> create_wrapper_shader (CoglContext *ctx)
> {
> @@ -1285,6 +1473,10 @@ cogl_gles2_context_new (CoglContext *ctx, GError **error)
> gles2_ctx->vtable->glGetIntegerv = gl_get_integer_v_wrapper;
> gles2_ctx->vtable->glGetFloatv = gl_get_float_v_wrapper;
> gles2_ctx->vtable->glPixelStorei = gl_pixel_store_i_wrapper;
> + gles2_ctx->vtable->glActiveTexture = gl_active_texture_wrapper;
> + gles2_ctx->vtable->glDeleteTextures = gl_delete_textures_wrapper;
> + gles2_ctx->vtable->glBindTexture = gl_bind_texture_wrapper;
> + gles2_ctx->vtable->glTexImage2D = gl_tex_image_2d_wrapper;
>
> /* FIXME: we need to do something with glCopyTexImage2D and
> * glCopySubTexImage2D so that it will flip the data if it is read
> @@ -1301,6 +1493,18 @@ cogl_gles2_context_new (CoglContext *ctx, GError **error)
> NULL, /* key_destroy */
> (GDestroyNotify) free_program_data);
>
> + gles2_ctx->texture_object_map =
> + g_hash_table_new_full (g_direct_hash,
> + g_direct_equal,
> + NULL, /* key_destroy */
> + (GDestroyNotify) free_texture_object_data);
> +
> + gles2_ctx->texture_units = g_array_new (FALSE, /* not zero terminated */
> + TRUE, /* clear */
> + sizeof (CoglGLES2TextureUnitData));
> + gles2_ctx->current_texture_unit = 0;
> + g_array_set_size (gles2_ctx->texture_units, 1);
> +
> return _cogl_gles2_context_object_new (gles2_ctx);
> }
>
> --
> 1.7.11.3.g3c3efa5
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl
More information about the Cogl
mailing list