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.
This commit is contained in:
Neil Roberts 2009-11-25 13:39:45 +00:00
parent 558b17ee1e
commit e12a691187
4 changed files with 154 additions and 251 deletions

View File

@ -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 */

View File

@ -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
};

View File

@ -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,

View File

@ -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);
}