From e12a691187a7dbbcfe5b46b94fe2975fd0927966 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Wed, 25 Nov 2009 13:39:45 +0000 Subject: [PATCH] cogl: Use a vtable for the texture backends instead of a type and switch Instead of storing an enum with the backend type for each texture and then using a switch statement to decide which function to call, we should store pointers to all of the functions in a struct and have each texture point to that struct. This is potentially slightly faster when there are more backends and it makes implementing new backends easier because it's more obvious which functions have to be implemented. --- .../cogl/cogl-texture-2d-sliced-private.h | 62 --------- clutter/cogl/cogl/cogl-texture-2d-sliced.c | 122 ++++++++--------- clutter/cogl/cogl/cogl-texture-private.h | 97 ++++++++++---- clutter/cogl/cogl/cogl-texture.c | 124 ++++-------------- 4 files changed, 154 insertions(+), 251 deletions(-) diff --git a/clutter/cogl/cogl/cogl-texture-2d-sliced-private.h b/clutter/cogl/cogl/cogl-texture-2d-sliced-private.h index 81c44a5a3..99f0e722a 100644 --- a/clutter/cogl/cogl/cogl-texture-2d-sliced-private.h +++ b/clutter/cogl/cogl/cogl-texture-2d-sliced-private.h @@ -99,66 +99,4 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle bmp_handle, CoglTextureFlags flags, CoglPixelFormat internal_format); -gboolean -_cogl_texture_2d_sliced_set_region (CoglHandle handle, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - int width, - int height, - CoglPixelFormat format, - unsigned int rowstride, - const guint8 *data); - -int -_cogl_texture_2d_sliced_get_data (CoglHandle handle, - CoglPixelFormat format, - unsigned int rowstride, - guint8 *data); - -void -_cogl_texture_2d_sliced_foreach_sub_texture_in_region ( - CoglTexture2DSliced *tex_2ds, - float virtual_tx_1, - float virtual_ty_1, - float virtual_tx_2, - float virtual_ty_2, - CoglTextureSliceCallback callback, - void *user_data); - -gint -_cogl_texture_2d_sliced_get_max_waste (CoglHandle handle); - -gboolean -_cogl_texture_2d_sliced_is_sliced (CoglHandle handle); - -gboolean -_cogl_texture_2d_sliced_can_hardware_repeat (CoglHandle handle); - -void -_cogl_texture_2d_sliced_transform_coords_to_gl (CoglTexture2DSliced *tex_2ds, - float *s, - float *t); - -gboolean -_cogl_texture_2d_sliced_get_gl_texture (CoglHandle handle, - GLuint *out_gl_handle, - GLenum *out_gl_target); - -void -_cogl_texture_2d_sliced_set_filters (CoglHandle handle, - GLenum min_filter, - GLenum mag_filter); - -void -_cogl_texture_2d_sliced_ensure_mipmaps (CoglHandle handle); - -void -_cogl_texture_2d_sliced_set_wrap_mode_parameter (CoglTexture2DSliced *tex_2ds, - GLenum wrap_mode); - - #endif /* __COGL_TEXTURE_2D_SLICED_H */ diff --git a/clutter/cogl/cogl/cogl-texture-2d-sliced.c b/clutter/cogl/cogl/cogl-texture-2d-sliced.c index 52eec49fe..56a4fdbea 100644 --- a/clutter/cogl/cogl/cogl-texture-2d-sliced.c +++ b/clutter/cogl/cogl/cogl-texture-2d-sliced.c @@ -50,6 +50,8 @@ static void _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds); COGL_HANDLE_DEFINE (Texture2DSliced, texture_2d_sliced); +static const CoglTextureVtable cogl_texture_2d_sliced_vtable; + /* To differentiate between texture coordinates of a specific, real, slice * texture and the texture coordinates of the composite, sliced texture, the * coordinates of the sliced texture are called "virtual" coordinates and the @@ -58,9 +60,9 @@ COGL_HANDLE_DEFINE (Texture2DSliced, texture_2d_sliced); * virtual coordinates of the parent sliced texture. */ /* Note: no guarantee is given about the order in which the slices will be * visited */ -void +static void _cogl_texture_2d_sliced_foreach_sub_texture_in_region ( - CoglTexture2DSliced *tex_2ds, + CoglTexture *tex, float virtual_tx_1, float virtual_ty_1, float virtual_tx_2, @@ -68,7 +70,7 @@ _cogl_texture_2d_sliced_foreach_sub_texture_in_region ( CoglTextureSliceCallback callback, void *user_data) { - CoglTexture *tex = COGL_TEXTURE (tex_2ds); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); float width = tex->bitmap.width; float height = tex->bitmap.height; CoglSpanIter iter_x; @@ -649,11 +651,11 @@ _cogl_pot_slices_for_size (gint size_to_fill, return 0; } -void -_cogl_texture_2d_sliced_set_wrap_mode_parameter (CoglTexture2DSliced *tex_2ds, +static void +_cogl_texture_2d_sliced_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode) { - CoglTexture *tex = COGL_TEXTURE (tex_2ds); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); /* Only set the wrap mode if it's different from the current value to avoid too many GL calls */ @@ -917,7 +919,7 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int width, tex_2ds = g_new (CoglTexture2DSliced, 1); tex = COGL_TEXTURE (tex_2ds); - tex->type = COGL_TEXTURE_TYPE_2D_SLICED; + tex->vtable = &cogl_texture_2d_sliced_vtable; tex->is_foreign = FALSE; tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; @@ -988,7 +990,7 @@ _cogl_texture_2d_sliced_new_from_data (unsigned int width, tex_2ds = g_new0 (CoglTexture2DSliced, 1); tex = COGL_TEXTURE (tex_2ds); - tex->type = COGL_TEXTURE_TYPE_2D_SLICED; + tex->vtable = &cogl_texture_2d_sliced_vtable; tex->is_foreign = FALSE; tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; @@ -1058,7 +1060,7 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle bmp_handle, tex_2ds = g_new0 (CoglTexture2DSliced, 1); tex = COGL_TEXTURE (tex_2ds); - tex->type = COGL_TEXTURE_TYPE_2D_SLICED; + tex->vtable = &cogl_texture_2d_sliced_vtable; tex->is_foreign = FALSE; tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; @@ -1240,7 +1242,7 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint gl_handle, tex_2ds = g_new0 (CoglTexture2DSliced, 1); tex = COGL_TEXTURE (tex_2ds); - tex->type = COGL_TEXTURE_TYPE_2D_SLICED; + tex->vtable = &cogl_texture_2d_sliced_vtable; /* Setup bitmap info */ tex->is_foreign = TRUE; @@ -1299,22 +1301,18 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint gl_handle, return _cogl_texture_2d_sliced_handle_new (tex_2ds); } -gint -_cogl_texture_2d_sliced_get_max_waste (CoglHandle handle) +static gint +_cogl_texture_2d_sliced_get_max_waste (CoglTexture *tex) { - CoglTexture2DSliced *tex_2ds; - - tex_2ds = _cogl_texture_2d_sliced_pointer_from_handle (handle); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); return tex_2ds->max_waste; } -gboolean -_cogl_texture_2d_sliced_is_sliced (CoglHandle handle) +static gboolean +_cogl_texture_2d_sliced_is_sliced (CoglTexture *tex) { - CoglTexture2DSliced *tex_2ds; - - tex_2ds = _cogl_texture_2d_sliced_pointer_from_handle (handle); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); if (tex_2ds->slice_gl_handles == NULL) return FALSE; @@ -1325,10 +1323,10 @@ _cogl_texture_2d_sliced_is_sliced (CoglHandle handle) return TRUE; } -gboolean -_cogl_texture_2d_sliced_can_hardware_repeat (CoglHandle handle) +static gboolean +_cogl_texture_2d_sliced_can_hardware_repeat (CoglTexture *tex) { - CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (handle); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglSpan *x_span; CoglSpan *y_span; @@ -1338,16 +1336,16 @@ _cogl_texture_2d_sliced_can_hardware_repeat (CoglHandle handle) return (x_span->waste || y_span->waste) ? FALSE : TRUE; } -void -_cogl_texture_2d_sliced_transform_coords_to_gl (CoglTexture2DSliced *tex_2ds, +static void +_cogl_texture_2d_sliced_transform_coords_to_gl (CoglTexture *tex, float *s, float *t) { - CoglTexture *tex = COGL_TEXTURE (tex_2ds); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglSpan *x_span; CoglSpan *y_span; - g_assert (!_cogl_texture_2d_sliced_is_sliced (tex_2ds)); + g_assert (!_cogl_texture_2d_sliced_is_sliced (tex)); /* Don't include the waste in the texture coordinates */ x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, 0); @@ -1366,19 +1364,12 @@ _cogl_texture_2d_sliced_transform_coords_to_gl (CoglTexture2DSliced *tex_2ds, #endif } -gboolean -_cogl_texture_2d_sliced_get_gl_texture (CoglHandle handle, +static gboolean +_cogl_texture_2d_sliced_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { - CoglTexture2DSliced *tex_2ds; - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return FALSE; - - tex_2ds = _cogl_texture_2d_sliced_pointer_from_handle (handle); - tex = COGL_TEXTURE (tex_2ds); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); if (tex_2ds->slice_gl_handles == NULL) return FALSE; @@ -1395,22 +1386,15 @@ _cogl_texture_2d_sliced_get_gl_texture (CoglHandle handle, return TRUE; } -void -_cogl_texture_2d_sliced_set_filters (CoglHandle handle, +static void +_cogl_texture_2d_sliced_set_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { - CoglTexture2DSliced *tex_2ds; - CoglTexture *tex; + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); GLuint gl_handle; int i; - if (!cogl_is_texture (handle)) - return; - - tex_2ds = _cogl_texture_2d_sliced_pointer_from_handle (handle); - tex = COGL_TEXTURE (tex_2ds); - /* Make sure slices were created */ if (tex_2ds->slice_gl_handles == NULL) return; @@ -1435,21 +1419,14 @@ _cogl_texture_2d_sliced_set_filters (CoglHandle handle, } } -void -_cogl_texture_2d_sliced_ensure_mipmaps (CoglHandle handle) +static void +_cogl_texture_2d_sliced_ensure_mipmaps (CoglTexture *tex) { - CoglTexture2DSliced *tex_2ds; - CoglTexture *tex; + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (!cogl_is_texture (handle)) - return; - - tex_2ds = _cogl_texture_2d_sliced_pointer_from_handle (handle); - tex = COGL_TEXTURE (tex_2ds); - /* Only update if the mipmaps are dirty */ if (!tex->auto_mipmap || !tex->mipmaps_dirty) return; @@ -1483,8 +1460,8 @@ _cogl_texture_2d_sliced_ensure_mipmaps (CoglHandle handle) tex->mipmaps_dirty = FALSE; } -gboolean -_cogl_texture_2d_sliced_set_region (CoglHandle handle, +static gboolean +_cogl_texture_2d_sliced_set_region (CoglTexture *tex, int src_x, int src_y, int dst_x, @@ -1497,8 +1474,7 @@ _cogl_texture_2d_sliced_set_region (CoglHandle handle, unsigned int rowstride, const guint8 *data) { - CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (handle); - CoglTexture *tex = COGL_TEXTURE (handle); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); gint bpp; CoglBitmap source_bmp; CoglBitmap temp_bmp; @@ -1562,7 +1538,7 @@ _cogl_texture_2d_sliced_set_region (CoglHandle handle, return TRUE; } -gboolean +static gboolean _cogl_texture_2d_sliced_download_from_gl ( CoglTexture2DSliced *tex_2ds, CoglBitmap *target_bmp, @@ -1663,14 +1639,13 @@ _cogl_texture_2d_sliced_download_from_gl ( return TRUE; } -int -_cogl_texture_2d_sliced_get_data (CoglHandle handle, +static int +_cogl_texture_2d_sliced_get_data (CoglTexture *tex, CoglPixelFormat format, unsigned int rowstride, guint8 *data) { - CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (handle); - CoglTexture *tex = COGL_TEXTURE (handle); + CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); gint bpp; gint byte_size; CoglPixelFormat closest_format; @@ -1762,3 +1737,18 @@ _cogl_texture_2d_sliced_get_data (CoglHandle handle, return byte_size; } +static const CoglTextureVtable +cogl_texture_2d_sliced_vtable = + { + _cogl_texture_2d_sliced_set_region, + _cogl_texture_2d_sliced_get_data, + _cogl_texture_2d_sliced_foreach_sub_texture_in_region, + _cogl_texture_2d_sliced_get_max_waste, + _cogl_texture_2d_sliced_is_sliced, + _cogl_texture_2d_sliced_can_hardware_repeat, + _cogl_texture_2d_sliced_transform_coords_to_gl, + _cogl_texture_2d_sliced_get_gl_texture, + _cogl_texture_2d_sliced_set_filters, + _cogl_texture_2d_sliced_ensure_mipmaps, + _cogl_texture_2d_sliced_set_wrap_mode_parameter + }; diff --git a/clutter/cogl/cogl/cogl-texture-private.h b/clutter/cogl/cogl/cogl-texture-private.h index 1b7184778..8c06af3da 100644 --- a/clutter/cogl/cogl/cogl-texture-private.h +++ b/clutter/cogl/cogl/cogl-texture-private.h @@ -31,29 +31,7 @@ #define COGL_TEXTURE(tex) ((CoglTexture *)(tex)) typedef struct _CoglTexture CoglTexture; - -typedef enum _CoglTextureType -{ - COGL_TEXTURE_TYPE_2D_SLICED -} CoglTextureType; - -struct _CoglTexture -{ - CoglHandleObject _parent; - CoglTextureType type; - CoglBitmap bitmap; - gboolean bitmap_owner; - GLenum gl_target; - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - GLenum min_filter; - GLenum mag_filter; - gboolean is_foreign; - GLint wrap_mode; - gboolean auto_mipmap; - gboolean mipmaps_dirty; -}; +typedef struct _CoglTextureVtable CoglTextureVtable; typedef void (*CoglTextureSliceCallback) (CoglHandle handle, GLuint gl_handle, @@ -62,6 +40,79 @@ typedef void (*CoglTextureSliceCallback) (CoglHandle handle, float *virtual_coords, void *user_data); +struct _CoglTextureVtable +{ + /* Virtual functions that must be implemented for a texture + backend */ + + gboolean (* set_region) (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int dst_width, + unsigned int dst_height, + int width, + int height, + CoglPixelFormat format, + unsigned int rowstride, + const guint8 *data); + + int (* get_data) (CoglTexture *tex, + CoglPixelFormat format, + unsigned int rowstride, + guint8 *data); + + void (* foreach_sub_texture_in_region) (CoglTexture *tex, + float virtual_tx_1, + float virtual_ty_1, + float virtual_tx_2, + float virtual_ty_2, + CoglTextureSliceCallback callback, + void *user_data); + + gint (* get_max_waste) (CoglTexture *tex); + + gboolean (* is_sliced) (CoglTexture *tex); + + gboolean (* can_hardware_repeat) (CoglTexture *tex); + + void (* transform_coords_to_gl) (CoglTexture *tex, + float *s, + float *t); + + gboolean (* get_gl_texture) (CoglTexture *tex, + GLuint *out_gl_handle, + GLenum *out_gl_target); + + void (* set_filters) (CoglTexture *tex, + GLenum min_filter, + GLenum mag_filter); + + void (* ensure_mipmaps) (CoglTexture *tex); + + void (* set_wrap_mode_parameter) (CoglTexture *tex, + GLenum wrap_mode); +}; + +struct _CoglTexture +{ + CoglHandleObject _parent; + const CoglTextureVtable *vtable; + CoglBitmap bitmap; + gboolean bitmap_owner; + GLenum gl_target; + GLenum gl_intformat; + GLenum gl_format; + GLenum gl_type; + GLenum min_filter; + GLenum mag_filter; + gboolean is_foreign; + GLint wrap_mode; + gboolean auto_mipmap; + gboolean mipmaps_dirty; +}; + void _cogl_texture_foreach_sub_texture_in_region (CoglHandle handle, float virtual_tx_1, diff --git a/clutter/cogl/cogl/cogl-texture.c b/clutter/cogl/cogl/cogl-texture.c index 763edbc2e..18dcb69fe 100644 --- a/clutter/cogl/cogl/cogl-texture.c +++ b/clutter/cogl/cogl/cogl-texture.c @@ -149,14 +149,7 @@ _cogl_texture_set_wrap_mode_parameter (CoglHandle handle, { CoglTexture *tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - _cogl_texture_2d_sliced_set_wrap_mode_parameter ( - (CoglTexture2DSliced *)tex, - wrap_mode); - break; - } + tex->vtable->set_wrap_mode_parameter (tex, wrap_mode); } gboolean @@ -340,11 +333,7 @@ cogl_texture_get_max_waste (CoglHandle handle) tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - return _cogl_texture_2d_sliced_get_max_waste (handle); - } + return tex->vtable->get_max_waste (tex); g_return_val_if_reached (0); } @@ -359,13 +348,7 @@ cogl_texture_is_sliced (CoglHandle handle) tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - return _cogl_texture_2d_sliced_is_sliced (handle); - } - - g_return_val_if_reached (FALSE); + return tex->vtable->is_sliced (tex); } /* Some CoglTextures, notably sliced textures or atlas textures when repeating @@ -388,21 +371,13 @@ _cogl_texture_foreach_sub_texture_in_region (CoglHandle handle, { CoglTexture *tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - { - CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); - _cogl_texture_2d_sliced_foreach_sub_texture_in_region (tex_2ds, - virtual_tx_1, - virtual_ty_1, - virtual_tx_2, - virtual_ty_2, - callback, - user_data); - break; - } - } + tex->vtable->foreach_sub_texture_in_region (tex, + virtual_tx_1, + virtual_ty_1, + virtual_tx_2, + virtual_ty_2, + callback, + user_data); } /* If this returns FALSE, that implies _foreach_sub_texture_in_region @@ -420,16 +395,7 @@ _cogl_texture_can_hardware_repeat (CoglHandle handle) return FALSE; #endif - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - { - CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); - return _cogl_texture_2d_sliced_can_hardware_repeat (tex_2ds); - } - } - - g_return_val_if_reached (FALSE); + return tex->vtable->can_hardware_repeat (tex); } /* NB: You can't use this with textures comprised of multiple sub textures (use @@ -442,12 +408,7 @@ _cogl_texture_transform_coords_to_gl (CoglHandle handle, { CoglTexture *tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - return _cogl_texture_2d_sliced_transform_coords_to_gl ( - COGL_TEXTURE_2D_SLICED (tex), s, t); - } + return tex->vtable->transform_coords_to_gl (tex, s, t); } GLenum @@ -470,15 +431,7 @@ cogl_texture_get_gl_texture (CoglHandle handle, tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - return _cogl_texture_2d_sliced_get_gl_texture (handle, - out_gl_handle, - out_gl_target); - } - - g_return_val_if_reached (FALSE); + return tex->vtable->get_gl_texture (tex, out_gl_handle, out_gl_target); } void @@ -493,12 +446,7 @@ _cogl_texture_set_filters (CoglHandle handle, tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - _cogl_texture_2d_sliced_set_filters (handle, min_filter, mag_filter); - break; - } + return tex->vtable->set_filters (tex, min_filter, mag_filter); } void @@ -511,12 +459,7 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle) tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - _cogl_texture_2d_sliced_ensure_mipmaps (handle); - break; - } + return tex->vtable->ensure_mipmaps (tex); } gboolean @@ -540,24 +483,14 @@ cogl_texture_set_region (CoglHandle handle, tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - return _cogl_texture_2d_sliced_set_region (handle, - src_x, - src_y, - dst_x, - dst_y, - dst_width, - dst_height, - width, - height, - format, - rowstride, - data); - } - - g_return_val_if_reached (FALSE); + return tex->vtable->set_region (tex, + src_x, src_y, + dst_x, dst_y, + dst_width, dst_height, + width, height, + format, + rowstride, + data); } /* Reads back the contents of a texture by rendering it to the framebuffer @@ -806,15 +739,6 @@ cogl_texture_get_data (CoglHandle handle, tex = COGL_TEXTURE (handle); - switch (tex->type) - { - case COGL_TEXTURE_TYPE_2D_SLICED: - return _cogl_texture_2d_sliced_get_data (handle, - format, - rowstride, - data); - } - - g_return_val_if_reached (0); + return tex->vtable->get_data (handle, format, rowstride, data); }