From 36f18e5ac57e068c3987d5b705f68fcc6f18d472 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Mon, 18 Jan 2010 09:22:04 +0000 Subject: [PATCH] cogl: Make CoglSubTexture only work for quad rendering The sub texture backend doesn't work well as a completely general texture backend because for example when rendering with cogl_polygon it needs to be able to tranform arbitrary texture coordinates without reference to the other coordintes. This can't be done when the texture coordinates are a multiple of one because sometimes the coordinate should represent the left or top edge and sometimes it should represent the bottom or top edge. For example if the s coordinates are 0 and 1 then 1 represents the right edge but if they are 1 and 2 then 1 represents the left edge. Instead the sub-textures are now documented not to support coordinates outside the range [0,1]. The coordinates for the sub-region are now represented as integers as this helps avoid rounding issues. The region can no longer be a super-region of the texture as this simplifies the code quite a lot. There are two new texture virtual functions: transform_quad_coords_to_gl - This transforms two pairs of coordinates representing a quad. It will return FALSE if the coordinates can not be transformed. The sub texture backend uses this to detect coordinates that require repeating which causes cogl-primitives to use manual repeating. ensure_non_quad_rendering - This is used in cogl_polygon and cogl_vertex_buffer to inform the texture backend that transform_quad_to_gl is going to be used. The atlas backend migrates the texture out of the atlas when it hits this. --- clutter/cogl/cogl/cogl-atlas-texture.c | 57 ++- clutter/cogl/cogl/cogl-primitives.c | 21 +- clutter/cogl/cogl/cogl-sub-texture-private.h | 15 +- clutter/cogl/cogl/cogl-sub-texture.c | 496 +++++++------------ clutter/cogl/cogl/cogl-texture-2d-sliced.c | 21 + clutter/cogl/cogl/cogl-texture-2d.c | 17 + clutter/cogl/cogl/cogl-texture-private.h | 10 + clutter/cogl/cogl/cogl-texture.c | 33 +- clutter/cogl/cogl/cogl-texture.h | 22 +- clutter/cogl/cogl/cogl-vertex-buffer.c | 5 + tests/conform/test-cogl-sub-texture.c | 81 +-- tests/conform/test-conform-main.c | 2 +- 12 files changed, 347 insertions(+), 433 deletions(-) diff --git a/clutter/cogl/cogl/cogl-atlas-texture.c b/clutter/cogl/cogl/cogl-atlas-texture.c index 4d7bf6f9d..4bbff22ea 100644 --- a/clutter/cogl/cogl/cogl-atlas-texture.c +++ b/clutter/cogl/cogl/cogl-atlas-texture.c @@ -34,6 +34,7 @@ #include "cogl-texture-private.h" #include "cogl-atlas-texture-private.h" #include "cogl-texture-2d-private.h" +#include "cogl-sub-texture-private.h" #include "cogl-context.h" #include "cogl-handle.h" #include "cogl-texture-driver.h" @@ -312,6 +313,17 @@ _cogl_atlas_texture_transform_coords_to_gl (CoglTexture *tex, _cogl_texture_transform_coords_to_gl (atlas_tex->sub_texture, s, t); } +static gboolean +_cogl_atlas_texture_transform_quad_coords_to_gl (CoglTexture *tex, + float *coords) +{ + CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); + + /* Forward on to the sub texture */ + return _cogl_texture_transform_quad_coords_to_gl (atlas_tex->sub_texture, + coords); +} + static gboolean _cogl_atlas_texture_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, @@ -337,12 +349,9 @@ _cogl_atlas_texture_set_filters (CoglTexture *tex, } static void -_cogl_atlas_texture_ensure_mipmaps (CoglTexture *tex) +_cogl_atlas_texture_migrate_out_of_atlas (CoglAtlasTexture *atlas_tex) { - CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); - - /* Mipmaps do not work well with the current atlas so instead we'll - just migrate the texture out and use a regular texture */ + /* Make sure this texture is not in the atlas */ if (atlas_tex->in_atlas) { CoglHandle atlas_texture; @@ -382,11 +391,34 @@ _cogl_atlas_texture_ensure_mipmaps (CoglTexture *tex) _cogl_atlas_texture_remove_from_atlas (atlas_tex); } +} + +static void +_cogl_atlas_texture_ensure_mipmaps (CoglTexture *tex) +{ + CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); + + /* Mipmaps do not work well with the current atlas so instead we'll + just migrate the texture out and use a regular texture */ + _cogl_atlas_texture_migrate_out_of_atlas (atlas_tex); /* Forward on to the sub texture */ _cogl_texture_ensure_mipmaps (atlas_tex->sub_texture); } +static void +_cogl_atlas_texture_ensure_non_quad_rendering (CoglTexture *tex) +{ + CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); + + /* Sub textures can't support non-quad rendering so we'll just + migrate the texture out */ + _cogl_atlas_texture_migrate_out_of_atlas (atlas_tex); + + /* Forward on to the sub texture */ + _cogl_texture_ensure_non_quad_rendering (atlas_tex->sub_texture); +} + static gboolean _cogl_atlas_texture_set_region (CoglTexture *tex, int src_x, @@ -546,14 +578,11 @@ _cogl_atlas_texture_create_sub_texture (CoglHandle full_texture, { /* Create a subtexture for the given rectangle not including the 1-pixel border */ - gfloat tex_width = cogl_texture_get_width (full_texture); - gfloat tex_height = cogl_texture_get_height (full_texture); - gfloat tx1 = (rectangle->x + 1) / tex_width; - gfloat ty1 = (rectangle->y + 1) / tex_height; - gfloat tx2 = (rectangle->x + rectangle->width - 1) / tex_width; - gfloat ty2 = (rectangle->y + rectangle->height - 1) / tex_height; - - return cogl_texture_new_from_sub_texture (full_texture, tx1, ty1, tx2, ty2); + return _cogl_sub_texture_new (full_texture, + rectangle->x + 1, + rectangle->y + 1, + rectangle->width - 2, + rectangle->height - 2); } typedef struct _CoglAtlasTextureRepositionData @@ -958,9 +987,11 @@ cogl_atlas_texture_vtable = _cogl_atlas_texture_is_sliced, _cogl_atlas_texture_can_hardware_repeat, _cogl_atlas_texture_transform_coords_to_gl, + _cogl_atlas_texture_transform_quad_coords_to_gl, _cogl_atlas_texture_get_gl_texture, _cogl_atlas_texture_set_filters, _cogl_atlas_texture_ensure_mipmaps, + _cogl_atlas_texture_ensure_non_quad_rendering, _cogl_atlas_texture_set_wrap_mode_parameter, _cogl_atlas_texture_get_format, _cogl_atlas_texture_get_gl_format, diff --git a/clutter/cogl/cogl/cogl-primitives.c b/clutter/cogl/cogl/cogl-primitives.c index b23d0158b..1215725ec 100644 --- a/clutter/cogl/cogl/cogl-primitives.c +++ b/clutter/cogl/cogl/cogl-primitives.c @@ -278,14 +278,14 @@ _cogl_multitexture_quad_single_primitive (float x_1, the coordinates (such as in the sub texture backend). This should be safe to call because we know that the texture only has one slice. */ - for (coord_num = 0; coord_num < 2; coord_num++) - { - float *s = out_tex_coords + coord_num * 2; - float *t = s + 1; - _cogl_texture_transform_coords_to_gl (tex_handle, s, t); - if (*s < 0.0f || *s > 1.0f || *t < 0.0f || *t > 1.0f) - need_repeat = TRUE; - } + if (!_cogl_texture_transform_quad_coords_to_gl (tex_handle, + out_tex_coords)) + /* If the backend can't support these coordinates then bail out */ + return FALSE; + for (coord_num = 0; coord_num < 4; coord_num++) + if (out_tex_coords[coord_num] < 0.0f || + out_tex_coords[coord_num] > 1.0f) + need_repeat = TRUE; /* If the texture has waste or we are using GL_TEXTURE_RECT we * can't handle texture repeating so we can't use the layer if @@ -867,6 +867,11 @@ cogl_polygon (const CoglTextureVertex *vertices, if (tex_handle == COGL_INVALID_HANDLE) continue; + /* Give the texture a chance to know that we're rendering + non-quad shaped primitives. If the texture is in an atlas it + will be migrated */ + _cogl_texture_ensure_non_quad_rendering (tex_handle); + if (i == 0 && cogl_texture_is_sliced (tex_handle)) { #if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) diff --git a/clutter/cogl/cogl/cogl-sub-texture-private.h b/clutter/cogl/cogl/cogl-sub-texture-private.h index 899f61e8c..c8fa4bbc9 100644 --- a/clutter/cogl/cogl/cogl-sub-texture-private.h +++ b/clutter/cogl/cogl/cogl-sub-texture-private.h @@ -37,12 +37,11 @@ struct _CoglSubTexture CoglHandle full_texture; - /* The texture coordinates of the subregion of full_texture */ - gfloat tx1, ty1; - gfloat tx2, ty2; - - /* Are all of the texture coordinates a multiple of one? */ - gboolean tex_coords_are_a_multiple; + /* The region represented by this sub-texture */ + gint sub_x; + gint sub_y; + gint sub_width; + gint sub_height; }; GQuark @@ -50,7 +49,7 @@ _cogl_handle_sub_texture_get_type (void); CoglHandle _cogl_sub_texture_new (CoglHandle full_texture, - gfloat tx1, gfloat ty1, - gfloat tx2, gfloat ty2); + gint sub_x, gint sub_y, + gint sub_width, gint sub_height); #endif /* __COGL_SUB_TEXTURE_H */ diff --git a/clutter/cogl/cogl/cogl-sub-texture.c b/clutter/cogl/cogl/cogl-sub-texture.c index d0213fe88..164a23f47 100644 --- a/clutter/cogl/cogl/cogl-sub-texture.c +++ b/clutter/cogl/cogl/cogl-sub-texture.c @@ -46,63 +46,105 @@ COGL_HANDLE_DEFINE (SubTexture, sub_texture); static const CoglTextureVtable cogl_sub_texture_vtable; -/* Maps from the texture coordinates of this texture to the texture - coordinates of the full texture */ - static void -_cogl_sub_texture_map_coordinate_pair (CoglSubTexture *sub_tex, - gfloat *tx, gfloat *ty) +_cogl_sub_texture_map_range (gfloat *t1, gfloat *t2, + gint sub_offset, + gint sub_size, + gint full_size) { - *tx = *tx * (sub_tex->tx2 - sub_tex->tx1) + sub_tex->tx1; - *ty = *ty * (sub_tex->ty2 - sub_tex->ty1) + sub_tex->ty1; + gfloat t1_frac, t1_int, t2_frac, t2_int; + + t1_frac = modff (*t1, &t1_int); + t2_frac = modff (*t2, &t2_int); + + if (t1_frac < 0.0f) + { + t1_frac += 1.0f; + t1_int -= 1.0f; + } + if (t2_frac < 0.0f) + { + t2_frac += 1.0f; + t2_int -= 1.0f; + } + + /* If one of the coordinates is zero we need to make sure it is + still greater than the other coordinate if it was originally so + we'll flip it to the other side */ + if (*t1 < *t2) + { + if (t2_frac == 0.0f) + { + t2_frac = 1.0f; + t2_int -= 1.0f; + } + } + else + { + if (t1_frac == 0.0f) + { + t1_frac = 1.0f; + t1_int -= 1.0f; + } + } + + /* Convert the fractional part leaving the integer part intact */ + t1_frac = (sub_offset + t1_frac * sub_size) / full_size; + *t1 = t1_frac + t1_int; + + t2_frac = (sub_offset + t2_frac * sub_size) / full_size; + *t2 = t2_frac + t2_int; } static void -_cogl_sub_texture_map_coordinate_set (CoglSubTexture *sub_tex, - gfloat *tx1, gfloat *ty1, - gfloat *tx2, gfloat *ty2) +_cogl_sub_texture_map_quad (CoglSubTexture *sub_tex, + gfloat *coords) { - _cogl_sub_texture_map_coordinate_pair (sub_tex, tx1, ty1); - _cogl_sub_texture_map_coordinate_pair (sub_tex, tx2, ty2); + guint full_width = cogl_texture_get_width (sub_tex->full_texture); + guint full_height = cogl_texture_get_height (sub_tex->full_texture); + + _cogl_sub_texture_map_range (coords + 0, coords + 2, + sub_tex->sub_x, sub_tex->sub_width, + full_width); + _cogl_sub_texture_map_range (coords + 1, coords + 3, + sub_tex->sub_y, sub_tex->sub_height, + full_height); } /* Maps from the texture coordinates of the full texture to the texture coordinates of the sub texture */ -static void -_cogl_sub_texture_unmap_coordinate_pair (CoglSubTexture *sub_tex, - gfloat *coords) +static gfloat +_cogl_sub_texture_unmap_coord (gfloat t, + gint sub_offset, + gint sub_size, + gint full_size) { - if (sub_tex->tx1 == sub_tex->tx2) - coords[0] = sub_tex->tx1; - else - coords[0] = (coords[0] - sub_tex->tx1) / (sub_tex->tx2 - sub_tex->tx1); + gfloat frac_part, int_part; - if (sub_tex->ty1 == sub_tex->ty2) - coords[0] = sub_tex->ty1; + /* Convert the fractional part leaving the integer part in tact */ + frac_part = modff (t, &int_part); + + if (signbit (frac_part)) + frac_part = ((1.0f + frac_part) * full_size - + sub_offset - sub_size) / sub_size; else - coords[1] = (coords[1] - sub_tex->ty1) / (sub_tex->ty2 - sub_tex->ty1); + frac_part = (frac_part * full_size - sub_offset) / sub_size; + + return frac_part + int_part; } static void -_cogl_sub_texture_unmap_coordinate_set (CoglSubTexture *sub_tex, - gfloat *coords) +_cogl_sub_texture_unmap_coords (CoglSubTexture *sub_tex, + gfloat *s, + gfloat *t) { - _cogl_sub_texture_unmap_coordinate_pair (sub_tex, coords); - _cogl_sub_texture_unmap_coordinate_pair (sub_tex, coords + 2); -} + guint full_width = cogl_texture_get_width (sub_tex->full_texture); + guint full_height = cogl_texture_get_height (sub_tex->full_texture); -static gboolean -_cogl_sub_texture_same_int_part (float t1, float t2) -{ - float int_part1, int_part2; - float frac_part1, frac_part2; - - frac_part1 = modff (t1, &int_part1); - frac_part2 = modff (t2, &int_part2); - - return (int_part1 == int_part2 || - ((frac_part1 == 0.0f || frac_part2 == 0.0f) && - ABS (int_part1 - int_part2) == 1.0f)); + *s = _cogl_sub_texture_unmap_coord (*s, sub_tex->sub_x, sub_tex->sub_width, + full_width); + *t = _cogl_sub_texture_unmap_coord (*t, sub_tex->sub_y, sub_tex->sub_height, + full_height); } typedef struct _CoglSubTextureForeachData @@ -126,7 +168,12 @@ _cogl_sub_texture_foreach_cb (CoglHandle handle, memcpy (virtual_coords, full_virtual_coords, sizeof (virtual_coords)); /* Convert the virtual coords from the full-texture space to the sub texture space */ - _cogl_sub_texture_unmap_coordinate_set (data->sub_tex, virtual_coords); + _cogl_sub_texture_unmap_coords (data->sub_tex, + &virtual_coords[0], + &virtual_coords[1]); + _cogl_sub_texture_unmap_coords (data->sub_tex, + &virtual_coords[2], + &virtual_coords[3]); data->callback (handle, gl_handle, gl_target, slice_coords, virtual_coords, @@ -142,11 +189,7 @@ _cogl_sub_texture_manual_repeat_cb (const float *coords, memcpy (mapped_coords, coords, sizeof (mapped_coords)); - _cogl_sub_texture_map_coordinate_set (data->sub_tex, - &mapped_coords[0], - &mapped_coords[1], - &mapped_coords[2], - &mapped_coords[3]); + _cogl_sub_texture_map_quad (data->sub_tex, mapped_coords); _cogl_texture_foreach_sub_texture_in_region (data->sub_tex->full_texture, mapped_coords[0], @@ -174,30 +217,10 @@ _cogl_sub_texture_foreach_sub_texture_in_region ( data.callback = callback; data.user_data = user_data; - /* If there is no repeating or the sub texture coordinates are a - multiple of the whole texture then we can just directly map the - texture coordinates */ - if (sub_tex->tex_coords_are_a_multiple || - (_cogl_sub_texture_same_int_part (virtual_tx_1, virtual_tx_2) && - _cogl_sub_texture_same_int_part (virtual_ty_1, virtual_ty_2))) - { - _cogl_sub_texture_map_coordinate_set (sub_tex, - &virtual_tx_1, - &virtual_ty_1, - &virtual_tx_2, - &virtual_ty_2); - - _cogl_texture_foreach_sub_texture_in_region - (sub_tex->full_texture, - virtual_tx_1, virtual_ty_1, - virtual_tx_2, virtual_ty_2, - _cogl_sub_texture_foreach_cb, &data); - } - else - _cogl_texture_iterate_manual_repeats (_cogl_sub_texture_manual_repeat_cb, - virtual_tx_1, virtual_ty_1, - virtual_tx_2, virtual_ty_2, - &data); + _cogl_texture_iterate_manual_repeats (_cogl_sub_texture_manual_repeat_cb, + virtual_tx_1, virtual_ty_1, + virtual_tx_2, virtual_ty_2, + &data); } static void @@ -219,12 +242,21 @@ _cogl_sub_texture_free (CoglSubTexture *sub_tex) CoglHandle _cogl_sub_texture_new (CoglHandle full_texture, - gfloat tx1, gfloat ty1, - gfloat tx2, gfloat ty2) + gint sub_x, gint sub_y, + gint sub_width, gint sub_height) { CoglSubTexture *sub_tex; CoglTexture *tex; - gfloat integer_part; + guint full_width, full_height; + + full_width = cogl_texture_get_width (full_texture); + full_height = cogl_texture_get_width (full_texture); + + /* The region must specify a non-zero subset of the full texture */ + g_return_val_if_fail (sub_x >= 0 && sub_y >= 0, COGL_INVALID_HANDLE); + g_return_val_if_fail (sub_width > 0 && sub_height > 0, COGL_INVALID_HANDLE); + g_return_val_if_fail (sub_x + sub_width <= full_width, COGL_INVALID_HANDLE); + g_return_val_if_fail (sub_y + sub_height <= full_height, COGL_INVALID_HANDLE); sub_tex = g_new (CoglSubTexture, 1); @@ -233,18 +265,10 @@ _cogl_sub_texture_new (CoglHandle full_texture, sub_tex->full_texture = cogl_handle_ref (full_texture); - sub_tex->tx1 = tx1; - sub_tex->ty1 = ty1; - sub_tex->tx2 = tx2; - sub_tex->ty2 = ty2; - - /* Track whether the texture coords are a multiple of one because in - that case we can use hardware repeating */ - sub_tex->tex_coords_are_a_multiple - = (modff (tx1, &integer_part) == 0.0f && - modff (ty1, &integer_part) == 0.0f && - modff (tx2, &integer_part) == 0.0f && - modff (ty2, &integer_part) == 0.0f); + sub_tex->sub_x = sub_x; + sub_tex->sub_y = sub_y; + sub_tex->sub_width = sub_width; + sub_tex->sub_height = sub_height; return _cogl_sub_texture_handle_new (sub_tex); } @@ -270,11 +294,12 @@ _cogl_sub_texture_can_hardware_repeat (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); - /* We can hardware repeat if the full texture can hardware repeat - and the coordinates for the subregion are all a multiple of the - full size of the texture (ie, they have no fractional part) */ - - return (sub_tex->tex_coords_are_a_multiple && + /* We can hardware repeat if the subtexture actually represents all of the + of the full texture */ + return (sub_tex->sub_width == + cogl_texture_get_width (sub_tex->full_texture) && + sub_tex->sub_height == + cogl_texture_get_height (sub_tex->full_texture) && _cogl_texture_can_hardware_repeat (sub_tex->full_texture)); } @@ -285,8 +310,34 @@ _cogl_sub_texture_transform_coords_to_gl (CoglTexture *tex, { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); - _cogl_sub_texture_map_coordinate_pair (sub_tex, s, t); - _cogl_texture_transform_coords_to_gl (sub_tex->full_texture, s, t); + /* This won't work if the sub texture is not the size of the full + texture and the coordinates are outside the range [0,1] */ + *s = ((*s * sub_tex->sub_width + sub_tex->sub_x) / + cogl_texture_get_width (sub_tex->full_texture)); + *t = ((*t * sub_tex->sub_height + sub_tex->sub_y) / + cogl_texture_get_height (sub_tex->full_texture)); + + return _cogl_texture_transform_coords_to_gl (sub_tex->full_texture, s, t); +} + +static gboolean +_cogl_sub_texture_transform_quad_coords_to_gl (CoglTexture *tex, + float *coords) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + int i; + + /* We can't support repeating with this method. In this case + cogl-primitives will resort to manual repeating */ + for (i = 0; i < 4; i++) + if (coords[i] < 0.0f || coords[i] > 1.0f) + return FALSE; + + _cogl_sub_texture_map_quad (sub_tex, coords); + + _cogl_texture_transform_quad_coords_to_gl (sub_tex->full_texture, coords); + + return TRUE; } static gboolean @@ -320,67 +371,8 @@ _cogl_sub_texture_ensure_mipmaps (CoglTexture *tex) } static void -_cogl_sub_texture_get_next_chunk (int pos, int end, - int tex_size, - int *chunk_start, int *chunk_end) +_cogl_sub_texture_ensure_non_quad_rendering (CoglTexture *tex) { - /* pos and end may be negative or greater than the size of the - texture. We want to calculate the next largest range we can copy - in one chunk */ - - if (pos < 0) - /* The behaviour of % for negative numbers is implementation - dependant in C89 so we have to do this */ - *chunk_start = (tex_size - pos) % tex_size; - else - *chunk_start = pos % tex_size; - - /* If the region is larger than the remaining size of the texture - then we need to crop it */ - if (end - pos > tex_size - *chunk_start) - end = pos + tex_size - *chunk_start; - - if (end < 0) - *chunk_end = (tex_size - end) % tex_size; - else - *chunk_end = end % tex_size; - - if (*chunk_end == 0) - *chunk_end = tex_size; -} - -static void -_cogl_sub_texture_get_x_pixel_pos (CoglSubTexture *sub_tex, - gint *px1, gint *px2) -{ - gint full_width = cogl_texture_get_width (sub_tex->full_texture); - - *px1 = full_width * sub_tex->tx1; - *px2 = full_width * sub_tex->tx2; - - if (*px1 > *px2) - { - gint temp = *px1; - *px1 = *px2; - *px2 = temp; - } -} - -static void -_cogl_sub_texture_get_y_pixel_pos (CoglSubTexture *sub_tex, - gint *py1, gint *py2) -{ - gint full_height = cogl_texture_get_height (sub_tex->full_texture); - - *py1 = full_height * sub_tex->ty1; - *py2 = full_height * sub_tex->ty2; - - if (*py1 > *py2) - { - gint temp = *py1; - *py1 = *py2; - *py2 = temp; - } } static gboolean @@ -397,144 +389,17 @@ _cogl_sub_texture_set_region (CoglTexture *tex, unsigned int rowstride, const guint8 *data) { - CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); - gint full_tex_width, full_tex_height; - gint bpp; - gint px1, py1, px2, py2; - gint it_x, it_y; - gint src_x1, src_y1, src_x2, src_y2; - CoglBitmap source_bmp; - CoglBitmap temp_bmp; - gboolean source_bmp_owner = FALSE; - CoglPixelFormat closest_format; - GLenum closest_gl_format; - GLenum closest_gl_type; - gboolean success; - CoglPixelFormat tex_format; + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); - /* Check for valid format */ - if (format == COGL_PIXEL_FORMAT_ANY) - return FALSE; - - /* Shortcut out early if the image is empty */ - if (width == 0 || height == 0) - return TRUE; - - /* FIXME: If the sub texture coordinates are swapped around then we - should flip the bitmap */ - - _cogl_sub_texture_get_x_pixel_pos (sub_tex, &px1, &px2); - _cogl_sub_texture_get_y_pixel_pos (sub_tex, &py1, &py2); - - full_tex_width = cogl_texture_get_width (sub_tex->full_texture); - full_tex_height = cogl_texture_get_height (sub_tex->full_texture); - - /* Init source bitmap */ - source_bmp.width = width; - source_bmp.height = height; - source_bmp.format = format; - source_bmp.data = (guchar*) data; - - /* Rowstride from texture width if none specified */ - bpp = _cogl_get_format_bpp (format); - source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; - - /* Find closest format to internal that's supported by GL */ - tex_format = cogl_texture_get_format (sub_tex->full_texture); - closest_format = _cogl_pixel_format_to_gl (tex_format, - NULL, /* don't need */ - &closest_gl_format, - &closest_gl_type); - - /* If no direct match, convert */ - if (closest_format != format) - { - /* Convert to required format */ - success = _cogl_bitmap_convert_and_premult (&source_bmp, - &temp_bmp, - closest_format); - - /* Swap bitmaps if succeeded */ - if (!success) return FALSE; - source_bmp = temp_bmp; - source_bmp_owner = TRUE; - } - - for (it_y = py1; it_y < py2; it_y += src_y2 - src_y1) - { - _cogl_sub_texture_get_next_chunk (it_y, py2, full_tex_width, - &src_y1, &src_y2); - - for (it_x = px1; it_x < px2; it_x += src_x2 - src_x1) - { - gint virt_x_1, virt_y_1, virt_width, virt_height; - gint copy_dst_x, copy_dst_y, copy_dst_width, copy_dst_height; - - _cogl_sub_texture_get_next_chunk (it_x, px2, full_tex_height, - &src_x1, &src_x2); - - /* Offset of the chunk from the left edge in the virtual sub - texture coordinates */ - virt_x_1 = it_x - px1; - /* Pixel width covered by this chunk */ - virt_width = src_x2 - src_x1; - /* Offset of the chunk from the top edge in the virtual sub - texture coordinates */ - virt_y_1 = it_y - py1; - /* Pixel height covered by this chunk */ - virt_height = src_y2 - src_y1; - - /* Check if this chunk intersects with the update region */ - if (dst_x + dst_width <= virt_x_1 || - dst_x >= virt_x_1 + virt_width || - dst_y + dst_height <= it_y - py1 || - dst_y >= virt_y_1 + virt_height) - continue; - - /* Calculate the intersection in virtual coordinates */ - copy_dst_width = dst_width; - if (dst_x < virt_x_1) - { - copy_dst_width -= virt_x_1 - dst_x; - copy_dst_x = virt_x_1; - } - else - copy_dst_x = dst_x; - if (copy_dst_width + copy_dst_x > virt_x_1 + virt_width) - copy_dst_width = virt_x_1 + virt_width - copy_dst_x; - - copy_dst_height = dst_height; - if (dst_y < virt_y_1) - { - copy_dst_height -= virt_y_1 - dst_y; - copy_dst_y = virt_y_1; - } - else - copy_dst_y = dst_y; - if (copy_dst_height + copy_dst_y > virt_y_1 + virt_height) - copy_dst_height = virt_y_1 + virt_height - copy_dst_y; - - /* Update the region in the full texture */ - cogl_texture_set_region (sub_tex->full_texture, - src_x + copy_dst_x - dst_x, - src_y + copy_dst_y - dst_y, - src_x1 + copy_dst_x - virt_x_1, - src_y1 + copy_dst_y - virt_y_1, - copy_dst_width, - copy_dst_height, - width, - height, - format, - rowstride, - data); - } - } - - /* Free data if owner */ - if (source_bmp_owner) - g_free (source_bmp.data); - - return TRUE; + return cogl_texture_set_region (sub_tex->full_texture, + src_x, src_y, + dst_x + sub_tex->sub_x, + dst_y + sub_tex->sub_y, + dst_width, dst_height, + width, height, + format, + rowstride, + data); } static void @@ -571,7 +436,6 @@ _cogl_sub_texture_get_data (CoglTexture *tex, guint8 *full_data; int byte_size, full_size; gint bpp; - gint px1, py1, px2, py2; gint full_tex_width, full_tex_height; /* FIXME: This gets the full data from the full texture and then @@ -583,19 +447,16 @@ _cogl_sub_texture_get_data (CoglTexture *tex, if (format == COGL_PIXEL_FORMAT_ANY) format = cogl_texture_get_format (sub_tex->full_texture); - _cogl_sub_texture_get_x_pixel_pos (sub_tex, &px1, &px2); - _cogl_sub_texture_get_y_pixel_pos (sub_tex, &py1, &py2); - full_tex_width = cogl_texture_get_width (sub_tex->full_texture); full_tex_height = cogl_texture_get_height (sub_tex->full_texture); /* Rowstride from texture width if none specified */ bpp = _cogl_get_format_bpp (format); if (rowstride == 0) - rowstride = px2 - px1; + rowstride = sub_tex->sub_width * bpp; /* Return byte size if only that requested */ - byte_size = (py2 - py1) * rowstride; + byte_size = sub_tex->sub_height * rowstride; if (data == NULL) return byte_size; @@ -606,32 +467,15 @@ _cogl_sub_texture_get_data (CoglTexture *tex, full_rowstride, full_data); if (full_size) - { - int dst_x, dst_y; - int src_x1, src_y1; - int src_x2, src_y2; - - for (dst_y = py1; dst_y < py2; dst_y += src_y2 - src_y1) - { - _cogl_sub_texture_get_next_chunk (dst_y, py2, full_tex_width, - &src_y1, &src_y2); - - for (dst_x = px1; dst_x < px2; dst_x += src_x2 - src_x1) - { - _cogl_sub_texture_get_next_chunk (dst_x, px2, full_tex_height, - &src_x1, &src_x2); - - _cogl_sub_texture_copy_region (data, full_data, - dst_x - px1, dst_y - py1, - src_x1, src_y1, - src_x2 - src_x1, - src_y2 - src_y1, - rowstride, - full_rowstride, - bpp); - } - } - } + _cogl_sub_texture_copy_region (data, full_data, + 0, 0, + sub_tex->sub_x, + sub_tex->sub_y, + sub_tex->sub_width, + sub_tex->sub_height, + rowstride, + full_rowstride, + bpp); else byte_size = 0; @@ -660,22 +504,16 @@ static gint _cogl_sub_texture_get_width (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); - gint px1, px2; - _cogl_sub_texture_get_x_pixel_pos (sub_tex, &px1, &px2); - - return px2 - px1; + return sub_tex->sub_width; } static gint _cogl_sub_texture_get_height (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); - gint py1, py2; - _cogl_sub_texture_get_y_pixel_pos (sub_tex, &py1, &py2); - - return py2 - py1; + return sub_tex->sub_height; } static const CoglTextureVtable @@ -688,9 +526,11 @@ cogl_sub_texture_vtable = _cogl_sub_texture_is_sliced, _cogl_sub_texture_can_hardware_repeat, _cogl_sub_texture_transform_coords_to_gl, + _cogl_sub_texture_transform_quad_coords_to_gl, _cogl_sub_texture_get_gl_texture, _cogl_sub_texture_set_filters, _cogl_sub_texture_ensure_mipmaps, + _cogl_sub_texture_ensure_non_quad_rendering, _cogl_sub_texture_set_wrap_mode_parameter, _cogl_sub_texture_get_format, _cogl_sub_texture_get_gl_format, diff --git a/clutter/cogl/cogl/cogl-texture-2d-sliced.c b/clutter/cogl/cogl/cogl-texture-2d-sliced.c index 0f53bc1dc..7743f9f2f 100644 --- a/clutter/cogl/cogl/cogl-texture-2d-sliced.c +++ b/clutter/cogl/cogl/cogl-texture-2d-sliced.c @@ -1266,6 +1266,19 @@ _cogl_texture_2d_sliced_transform_coords_to_gl (CoglTexture *tex, #endif } +static gboolean +_cogl_texture_2d_sliced_transform_quad_coords_to_gl (CoglTexture *tex, + float *coords) +{ + if (_cogl_texture_2d_sliced_is_sliced (tex)) + return FALSE; + + _cogl_texture_2d_sliced_transform_coords_to_gl (tex, coords + 0, coords + 1); + _cogl_texture_2d_sliced_transform_coords_to_gl (tex, coords + 2, coords + 3); + + return TRUE; +} + static gboolean _cogl_texture_2d_sliced_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, @@ -1362,6 +1375,12 @@ _cogl_texture_2d_sliced_ensure_mipmaps (CoglTexture *tex) tex_2ds->mipmaps_dirty = FALSE; } +static void +_cogl_texture_2d_sliced_ensure_non_quad_rendering (CoglTexture *tex) +{ + /* Nothing needs to be done */ +} + static gboolean _cogl_texture_2d_sliced_set_region (CoglTexture *tex, int src_x, @@ -1673,9 +1692,11 @@ cogl_texture_2d_sliced_vtable = _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_transform_quad_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_ensure_non_quad_rendering, _cogl_texture_2d_sliced_set_wrap_mode_parameter, _cogl_texture_2d_sliced_get_format, _cogl_texture_2d_sliced_get_gl_format, diff --git a/clutter/cogl/cogl/cogl-texture-2d.c b/clutter/cogl/cogl/cogl-texture-2d.c index f6bf603b2..cd3f3a1ef 100644 --- a/clutter/cogl/cogl/cogl-texture-2d.c +++ b/clutter/cogl/cogl/cogl-texture-2d.c @@ -342,6 +342,15 @@ _cogl_texture_2d_transform_coords_to_gl (CoglTexture *tex, anything */ } +static gboolean +_cogl_texture_2d_transform_quad_coords_to_gl (CoglTexture *tex, + float *coords) +{ + /* The texture coordinates map directly so we don't need to do + anything */ + return TRUE; +} + static gboolean _cogl_texture_2d_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, @@ -399,6 +408,12 @@ _cogl_texture_2d_ensure_mipmaps (CoglTexture *tex) tex_2d->mipmaps_dirty = FALSE; } +static void +_cogl_texture_2d_ensure_non_quad_rendering (CoglTexture *tex) +{ + /* Nothing needs to be done */ +} + static gboolean _cogl_texture_2d_set_region (CoglTexture *tex, int src_x, @@ -612,9 +627,11 @@ cogl_texture_2d_vtable = _cogl_texture_2d_is_sliced, _cogl_texture_2d_can_hardware_repeat, _cogl_texture_2d_transform_coords_to_gl, + _cogl_texture_2d_transform_quad_coords_to_gl, _cogl_texture_2d_get_gl_texture, _cogl_texture_2d_set_filters, _cogl_texture_2d_ensure_mipmaps, + _cogl_texture_2d_ensure_non_quad_rendering, _cogl_texture_2d_set_wrap_mode_parameter, _cogl_texture_2d_get_format, _cogl_texture_2d_get_gl_format, diff --git a/clutter/cogl/cogl/cogl-texture-private.h b/clutter/cogl/cogl/cogl-texture-private.h index ad6449d6d..e59374334 100644 --- a/clutter/cogl/cogl/cogl-texture-private.h +++ b/clutter/cogl/cogl/cogl-texture-private.h @@ -84,6 +84,8 @@ struct _CoglTextureVtable void (* transform_coords_to_gl) (CoglTexture *tex, float *s, float *t); + gboolean (* transform_quad_coords_to_gl) (CoglTexture *tex, + float *coords); gboolean (* get_gl_texture) (CoglTexture *tex, GLuint *out_gl_handle, @@ -94,6 +96,7 @@ struct _CoglTextureVtable GLenum mag_filter); void (* ensure_mipmaps) (CoglTexture *tex); + void (* ensure_non_quad_rendering) (CoglTexture *tex); void (* set_wrap_mode_parameter) (CoglTexture *tex, GLenum wrap_mode); @@ -137,6 +140,10 @@ void _cogl_texture_transform_coords_to_gl (CoglHandle handle, float *s, float *t); +gboolean +_cogl_texture_transform_quad_coords_to_gl (CoglHandle handle, + float *coords); + GLenum _cogl_texture_get_gl_format (CoglHandle handle); @@ -152,6 +159,9 @@ _cogl_texture_set_filters (CoglHandle handle, void _cogl_texture_ensure_mipmaps (CoglHandle handle); +void +_cogl_texture_ensure_non_quad_rendering (CoglHandle handle); + /* Utility functions to help uploading a bitmap. These are intended to * be used by CoglTexture implementations or drivers... */ diff --git a/clutter/cogl/cogl/cogl-texture.c b/clutter/cogl/cogl/cogl-texture.c index 85a6de7cc..09acb0182 100644 --- a/clutter/cogl/cogl/cogl-texture.c +++ b/clutter/cogl/cogl/cogl-texture.c @@ -428,12 +428,13 @@ cogl_texture_new_from_foreign (GLuint gl_handle, CoglHandle cogl_texture_new_from_sub_texture (CoglHandle full_texture, - gfloat tx1, - gfloat ty1, - gfloat tx2, - gfloat ty2) + gint sub_x, + gint sub_y, + gint sub_width, + gint sub_height) { - return _cogl_sub_texture_new (full_texture, tx1, ty1, tx2, ty2); + return _cogl_sub_texture_new (full_texture, sub_x, sub_y, + sub_width, sub_height); } guint @@ -574,6 +575,15 @@ _cogl_texture_transform_coords_to_gl (CoglHandle handle, tex->vtable->transform_coords_to_gl (tex, s, t); } +gboolean +_cogl_texture_transform_quad_coords_to_gl (CoglHandle handle, + float *coords) +{ + CoglTexture *tex = COGL_TEXTURE (handle); + + return tex->vtable->transform_quad_coords_to_gl (tex, coords); +} + GLenum _cogl_texture_get_gl_format (CoglHandle handle) { @@ -625,6 +635,19 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle) tex->vtable->ensure_mipmaps (tex); } +void +_cogl_texture_ensure_non_quad_rendering (CoglHandle handle) +{ + CoglTexture *tex; + + if (!cogl_is_texture (handle)) + return; + + tex = COGL_TEXTURE (handle); + + return tex->vtable->ensure_non_quad_rendering (tex); +} + gboolean cogl_texture_set_region (CoglHandle handle, gint src_x, diff --git a/clutter/cogl/cogl/cogl-texture.h b/clutter/cogl/cogl/cogl-texture.h index 2ab90c841..c0becf944 100644 --- a/clutter/cogl/cogl/cogl-texture.h +++ b/clutter/cogl/cogl/cogl-texture.h @@ -320,18 +320,18 @@ gboolean cogl_texture_set_region (CoglHandle handle, /** * cogl_texture_new_from_sub_texture: * @full_texture: a #CoglHandle to an existing texture - * @tx1: X coordinate of the top-left of the subregion - * @ty1: Y coordinate of the top-left of the subregion - * @tx2: X coordinate of the bottom-right of the subregion - * @ty2: Y coordinate of the bottom-right of the subregion + * @sub_x: X coordinate of the top-left of the subregion + * @sub_y: Y coordinate of the top-left of the subregion + * @sub_width: Width in pixels of the subregion + * @sub_height: Height in pixels of the subregion * * Creates a new texture which represents a subregion of another * texture. The GL resources will be shared so that no new texture * data is actually allocated. * - * You can also specify texture coordinates outside the range of [0,1] - * to make a texture that represents a repeated version of another - * texture. + * Sub textures have undefined behaviour texture coordinates outside + * of the range [0,1] are used. They also do not work with + * CoglVertexBuffers. * * Return value: a #CoglHandle to the new texture. * @@ -339,10 +339,10 @@ gboolean cogl_texture_set_region (CoglHandle handle, */ CoglHandle cogl_texture_new_from_sub_texture (CoglHandle full_texture, - gfloat tx1, - gfloat ty1, - gfloat tx2, - gfloat ty2); + gint sub_x, + gint sub_y, + gint sub_width, + gint sub_height); #ifndef COGL_DISABLE_DEPRECATED diff --git a/clutter/cogl/cogl/cogl-vertex-buffer.c b/clutter/cogl/cogl/cogl-vertex-buffer.c index 26d09ce01..943b77776 100644 --- a/clutter/cogl/cogl/cogl-vertex-buffer.c +++ b/clutter/cogl/cogl/cogl-vertex-buffer.c @@ -1637,6 +1637,11 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer) if (tex_handle == COGL_INVALID_HANDLE) continue; + /* Give the texture a chance to know that we're rendering + non-quad shaped primitives. If the texture is in an atlas it + will be migrated */ + _cogl_texture_ensure_non_quad_rendering (tex_handle); + if (!_cogl_texture_can_hardware_repeat (tex_handle)) { g_warning ("Disabling layer %d of the current source material, " diff --git a/tests/conform/test-cogl-sub-texture.c b/tests/conform/test-cogl-sub-texture.c index 45449b9e5..ea0f6123a 100644 --- a/tests/conform/test-cogl-sub-texture.c +++ b/tests/conform/test-cogl-sub-texture.c @@ -74,9 +74,10 @@ draw_frame (TestState *state) /* Create a sub texture of the bottom right quarter of the texture */ sub_texture = cogl_texture_new_from_sub_texture (state->tex, - 1.0f / SOURCE_DIVISIONS_X, - 1.0f / SOURCE_DIVISIONS_Y, - 1.0f, 1.0f); + DIVISION_WIDTH, + DIVISION_HEIGHT, + DIVISION_WIDTH, + DIVISION_HEIGHT); /* Paint it */ cogl_set_source_texture (sub_texture); @@ -84,22 +85,19 @@ draw_frame (TestState *state) cogl_handle_unref (sub_texture); - /* Repeat a sub texture of the top half of the full texture */ + /* Repeat a sub texture of the top half of the full texture. This is + documented to be undefined so it doesn't technically have to work + but it will with the current implementation */ sub_texture = cogl_texture_new_from_sub_texture (state->tex, - 0.0f, 0.0f, 1.0f, 0.5f); + 0, 0, + SOURCE_SIZE, + DIVISION_HEIGHT); cogl_set_source_texture (sub_texture); cogl_rectangle_with_texture_coords (0.0f, SOURCE_SIZE, SOURCE_SIZE * 2.0f, SOURCE_SIZE * 1.5f, 0.0f, 0.0f, 2.0f, 1.0f); cogl_handle_unref (sub_texture); - - /* Create a texture that repeats the source texture twice */ - sub_texture = cogl_texture_new_from_sub_texture (state->tex, - 0.0f, 0.0f, 2.0f, 2.0f); - cogl_set_source_texture (sub_texture); - cogl_rectangle (0.0f, SOURCE_SIZE * 2, SOURCE_SIZE * 2, SOURCE_SIZE * 4); - cogl_handle_unref (sub_texture); } static gboolean @@ -209,22 +207,12 @@ validate_result (TestState *state) DIVISION_WIDTH, DIVISION_HEIGHT, corner_colors + division_num)); - /* Sub texture that repeats the texture (the opposite of a sub-texture?) */ - for (y = 0; y < SOURCE_DIVISIONS_Y * 2; y++) - for (x = 0; x < SOURCE_DIVISIONS_X * 2; x++) - { - guint color_num = (y % SOURCE_DIVISIONS_Y * SOURCE_DIVISIONS_X + - x % SOURCE_DIVISIONS_X); - g_assert (validate_part (state, - x * DIVISION_WIDTH, - y * DIVISION_WIDTH + SOURCE_SIZE * 2, - DIVISION_WIDTH, DIVISION_HEIGHT, - corner_colors + color_num)); - } - /* Try reading back the texture data */ sub_texture = cogl_texture_new_from_sub_texture (state->tex, - 0.25f, 0.25f, 0.75f, 0.75f); + SOURCE_SIZE / 4, + SOURCE_SIZE / 4, + SOURCE_SIZE / 2, + SOURCE_SIZE / 2); tex_width = cogl_texture_get_width (sub_texture); tex_height = cogl_texture_get_height (sub_texture); p = texture_data = g_malloc (tex_width * tex_height * 4); @@ -248,39 +236,14 @@ validate_result (TestState *state) g_free (texture_data); cogl_handle_unref (sub_texture); - /* Try reading back the repeated texture data */ - sub_texture = cogl_texture_new_from_sub_texture (state->tex, - 0.0f, 0.0f, 2.0f, 2.0f); - tex_width = cogl_texture_get_width (sub_texture); - tex_height = cogl_texture_get_height (sub_texture); - p = texture_data = g_malloc (tex_width * tex_height * 4); - cogl_texture_get_data (sub_texture, COGL_PIXEL_FORMAT_RGBA_8888, - tex_width * 4, - texture_data); - for (y = 0; y < tex_height; y++) - for (x = 0; x < tex_width; x++) - { - int div_x = x / DIVISION_WIDTH % SOURCE_DIVISIONS_X; - int div_y = y / DIVISION_HEIGHT % SOURCE_DIVISIONS_Y; - const ClutterColor *color = (corner_colors + div_x + - div_y * SOURCE_DIVISIONS_X); - g_assert (p[0] == color->red); - g_assert (p[1] == color->green); - g_assert (p[2] == color->blue); - p += 4; - } - g_free (texture_data); - cogl_handle_unref (sub_texture); - /* Create a 256x256 test texture */ test_tex = create_test_texture (); - /* Create a sub texture the views the bottom right and top left of - the texture by wrapping around */ + /* Create a sub texture the views the center half of the texture */ sub_texture = cogl_texture_new_from_sub_texture (test_tex, - 0.5f, 0.5f, 1.5f, 1.5f); - /* Update the center of the sub texture */ + 64, 64, 128, 128); + /* Update the center half of the sub texture */ texture_data = create_update_data (); - cogl_texture_set_region (sub_texture, 0, 0, 64, 64, 128, 128, 256, 256, + cogl_texture_set_region (sub_texture, 0, 0, 32, 32, 64, 64, 256, 256, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4, texture_data); g_free (texture_data); @@ -294,13 +257,13 @@ validate_result (TestState *state) for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { - /* If we're in the center of the subregion.. */ - if ((x < 64 || x >= 192) && (y < 64 || y >= 192)) + /* If we're in the center quarter */ + if (x >= 96 && x < 160 && y >= 96 && y < 160) { g_assert ((*p++) == 0); g_assert ((*p++) == 0); - g_assert ((*p++) == ((x + 64) & 0xff)); - g_assert ((*p++) == ((y + 64) & 0xff)); + g_assert ((*p++) == x - 96); + g_assert ((*p++) == y - 96); } else { diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index 3b55ebb30..3681fe25e 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -145,7 +145,6 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/opacity", test_paint_opacity); TEST_CONFORM_SIMPLE ("/texture", test_texture_fbo); - TEST_CONFORM_SIMPLE ("/texture", test_cogl_sub_texture); TEST_CONFORM_SIMPLE ("/path", test_path); @@ -189,6 +188,7 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_npot_texture); TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_multitexture); TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_texture_mipmaps); + TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_sub_texture); TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_contiguous); TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_interleved);