1
0
Fork 0

cogl-sub-texture: Optimise taking a sub texture of a sub texture

When creating a Cogl sub-texture, if the full texture is also a sub
texture it will now just offset the x and y and reference the full
texture instead. This avoids one level of indirection when rendering
the texture which reduces the chances of getting rounding errors in
the calculations.
This commit is contained in:
Neil Roberts 2010-02-12 10:08:51 +00:00
parent 2018b5b167
commit 4be4f56bdf
4 changed files with 99 additions and 40 deletions

View file

@ -35,9 +35,22 @@ struct _CoglSubTexture
{
CoglTexture _parent;
/* This is the texture that was passed in to
_cogl_sub_texture_new. If this is also a sub texture then we will
use the full texture from that to render instead of making a
chain. However we want to preserve the next texture in case the
user is expecting us to keep a reference and also so that we can
later add a cogl_sub_texture_get_full_texture() function. */
CoglHandle next_texture;
/* This is the texture that will actually be used to draw. It will
point to the end of the chain if a sub texture of a sub texture
is created */
CoglHandle full_texture;
/* The region represented by this sub-texture */
/* The region represented by this sub-texture. This is the region of
full_texture which won't necessarily be the same as the region
passed to _cogl_sub_texture_new if next_texture is actually
already a sub texture */
int sub_x;
int sub_y;
int sub_width;
@ -48,7 +61,7 @@ GQuark
_cogl_handle_sub_texture_get_type (void);
CoglHandle
_cogl_sub_texture_new (CoglHandle full_texture,
_cogl_sub_texture_new (CoglHandle next_texture,
int sub_x,
int sub_y,
int sub_width,

View file

@ -235,34 +235,51 @@ _cogl_sub_texture_set_wrap_mode_parameter (CoglTexture *tex,
static void
_cogl_sub_texture_free (CoglSubTexture *sub_tex)
{
cogl_handle_unref (sub_tex->next_texture);
cogl_handle_unref (sub_tex->full_texture);
g_free (sub_tex);
}
CoglHandle
_cogl_sub_texture_new (CoglHandle full_texture,
_cogl_sub_texture_new (CoglHandle next_texture,
int sub_x, int sub_y,
int sub_width, int sub_height)
{
CoglHandle full_texture;
CoglSubTexture *sub_tex;
CoglTexture *tex;
unsigned int full_width, full_height;
unsigned int next_width, next_height;
full_width = cogl_texture_get_width (full_texture);
full_height = cogl_texture_get_height (full_texture);
next_width = cogl_texture_get_width (next_texture);
next_height = cogl_texture_get_height (next_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);
g_return_val_if_fail (sub_x + sub_width <= next_width, COGL_INVALID_HANDLE);
g_return_val_if_fail (sub_y + sub_height <= next_height, COGL_INVALID_HANDLE);
sub_tex = g_new (CoglSubTexture, 1);
tex = COGL_TEXTURE (sub_tex);
tex->vtable = &cogl_sub_texture_vtable;
/* If the next texture is also a sub texture we can avoid one level
of indirection by referencing the full texture of that texture
instead. */
if (cogl_is_sub_texture (next_texture))
{
CoglSubTexture *other_sub_tex =
_cogl_sub_texture_pointer_from_handle (next_texture);
full_texture = other_sub_tex->full_texture;
sub_x += other_sub_tex->sub_x;
sub_y += other_sub_tex->sub_y;
}
else
full_texture = next_texture;
sub_tex->next_texture = cogl_handle_ref (next_texture);
sub_tex->full_texture = cogl_handle_ref (full_texture);
sub_tex->sub_x = sub_x;

View file

@ -348,6 +348,10 @@ cogl_texture_set_region (CoglHandle handle,
* of the range [0,1] are used. They also do not work with
* CoglVertexBuffers.
*
* The sub texture will keep a reference to the full texture so you do
* not need to keep one separately if you only want to use the sub
* texture.
*
* Return value: a #CoglHandle to the new texture.
*
* Since: 1.2

View file

@ -67,10 +67,41 @@ create_source (void)
data);
}
static CoglHandle
create_test_texture (void)
{
CoglHandle tex;
guint8 *data = g_malloc (256 * 256 * 4), *p = data;
int x, y;
/* Create a texture that is 256x256 where the red component ranges
from 0->255 along the x axis and the green component ranges from
0->255 along the y axis. The blue and alpha components are all
255 */
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
*(p++) = x;
*(p++) = y;
*(p++) = 255;
*(p++) = 255;
}
tex = cogl_texture_new_from_data (256, 256, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
256 * 4,
data);
g_free (data);
return tex;
}
static void
draw_frame (TestState *state)
{
CoglHandle sub_texture;
CoglHandle full_texture, sub_texture, sub_sub_texture;
/* Create a sub texture of the bottom right quarter of the texture */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
@ -98,6 +129,19 @@ draw_frame (TestState *state)
0.0f, 0.0f,
2.0f, 1.0f);
cogl_handle_unref (sub_texture);
/* Create a sub texture of a sub texture */
full_texture = create_test_texture ();
sub_texture = cogl_texture_new_from_sub_texture (full_texture,
20, 10, 30, 20);
sub_sub_texture = cogl_texture_new_from_sub_texture (sub_texture,
20, 10, 10, 10);
cogl_set_source_texture (sub_sub_texture);
cogl_rectangle (0.0f, SOURCE_SIZE * 2.0f,
10.0f, SOURCE_SIZE * 2.0f + 10.0f);
cogl_handle_unref (sub_sub_texture);
cogl_handle_unref (sub_texture);
cogl_handle_unref (full_texture);
}
static gboolean
@ -131,37 +175,6 @@ validate_part (TestState *state,
return pass;
}
static CoglHandle
create_test_texture (void)
{
CoglHandle tex;
guint8 *data = g_malloc (256 * 256 * 4), *p = data;
int x, y;
/* Create a texture that is 256x256 where the red component ranges
from 0->255 along the x axis and the green component ranges from
0->255 along the y axis. The blue and alpha components are all
255 */
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
*(p++) = x;
*(p++) = y;
*(p++) = 255;
*(p++) = 255;
}
tex = cogl_texture_new_from_data (256, 256, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
256 * 4,
data);
g_free (data);
return tex;
}
static guint8 *
create_update_data (void)
{
@ -207,6 +220,18 @@ validate_result (TestState *state)
DIVISION_WIDTH, DIVISION_HEIGHT,
corner_colors + division_num));
/* Sub sub texture */
p = texture_data = clutter_stage_read_pixels (CLUTTER_STAGE (state->stage),
0, SOURCE_SIZE * 2, 10, 10);
for (y = 0; y < 10; y++)
for (x = 0; x < 10; x++)
{
g_assert (*(p++) == x + 40);
g_assert (*(p++) == y + 20);
p += 2;
}
g_free (texture_data);
/* Try reading back the texture data */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
SOURCE_SIZE / 4,