[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