af7398788a
Texture allocation is now consistently handled lazily such that the internal format can now be controlled using cogl_texture_set_components() and cogl_texture_set_premultiplied() before allocating the texture with cogl_texture_allocate(). This means that the internal_format arguments to texture constructors are now redundant and since most of the texture constructors now can't ever fail the error arguments are also redundant. This now means we no longer use CoglPixelFormat in the public api for describing the internal format of textures which had been bad solution originally due to how specific CoglPixelFormat is which is missleading when we don't support such explicit control over the internal format. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit 99a53c82e9ab0a1e5ee35941bf83dc334b1fbe87) Note: there are numerous API changes for functions currently marked as 'unstable' which we don't think are in use by anyone depending on a stable 1.x api. Compared to the original patch though this avoids changing the cogl_texture_rectangle_new_with_size() api which we know is used by Mutter.
325 lines
10 KiB
C
325 lines
10 KiB
C
#include <cogl/cogl.h>
|
|
#include <string.h>
|
|
|
|
#include "test-utils.h"
|
|
|
|
#define SOURCE_SIZE 32
|
|
#define SOURCE_DIVISIONS_X 2
|
|
#define SOURCE_DIVISIONS_Y 2
|
|
#define DIVISION_WIDTH (SOURCE_SIZE / SOURCE_DIVISIONS_X)
|
|
#define DIVISION_HEIGHT (SOURCE_SIZE / SOURCE_DIVISIONS_Y)
|
|
|
|
#define TEST_INSET 1
|
|
|
|
static const uint32_t
|
|
corner_colors[SOURCE_DIVISIONS_X * SOURCE_DIVISIONS_Y] =
|
|
{
|
|
0xff0000ff, /* red top left */
|
|
0x00ff00ff, /* green top right */
|
|
0x0000ffff, /* blue bottom left */
|
|
0xff00ffff /* purple bottom right */
|
|
};
|
|
|
|
typedef struct _TestState
|
|
{
|
|
CoglTexture2D *tex;
|
|
} TestState;
|
|
|
|
static CoglTexture2D *
|
|
create_source (TestState *state)
|
|
{
|
|
int dx, dy;
|
|
uint8_t *data = g_malloc (SOURCE_SIZE * SOURCE_SIZE * 4);
|
|
CoglTexture2D *tex;
|
|
|
|
/* Create a texture with a different coloured rectangle at each
|
|
corner */
|
|
for (dy = 0; dy < SOURCE_DIVISIONS_Y; dy++)
|
|
for (dx = 0; dx < SOURCE_DIVISIONS_X; dx++)
|
|
{
|
|
uint8_t *p = (data + dy * DIVISION_HEIGHT * SOURCE_SIZE * 4 +
|
|
dx * DIVISION_WIDTH * 4);
|
|
int x, y;
|
|
|
|
for (y = 0; y < DIVISION_HEIGHT; y++)
|
|
{
|
|
for (x = 0; x < DIVISION_WIDTH; x++)
|
|
{
|
|
uint32_t color = GUINT32_FROM_BE (corner_colors[dx + dy * SOURCE_DIVISIONS_X]);
|
|
memcpy (p, &color, 4);
|
|
p += 4;
|
|
}
|
|
|
|
p += SOURCE_SIZE * 4 - DIVISION_WIDTH * 4;
|
|
}
|
|
}
|
|
|
|
tex = cogl_texture_2d_new_from_data (test_ctx,
|
|
SOURCE_SIZE, SOURCE_SIZE,
|
|
COGL_PIXEL_FORMAT_RGBA_8888,
|
|
SOURCE_SIZE * 4,
|
|
data,
|
|
NULL);
|
|
return tex;
|
|
}
|
|
|
|
static CoglTexture2D *
|
|
create_test_texture (TestState *state)
|
|
{
|
|
CoglTexture2D *tex;
|
|
uint8_t *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_2d_new_from_data (test_ctx,
|
|
256, 256,
|
|
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
|
256 * 4,
|
|
data,
|
|
NULL);
|
|
g_free (data);
|
|
|
|
return tex;
|
|
}
|
|
|
|
static void
|
|
paint (TestState *state)
|
|
{
|
|
CoglTexture2D *full_texture;
|
|
CoglSubTexture *sub_texture, *sub_sub_texture;
|
|
CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
|
|
|
|
/* Create a sub texture of the bottom right quarter of the texture */
|
|
sub_texture = cogl_sub_texture_new (test_ctx,
|
|
state->tex,
|
|
DIVISION_WIDTH,
|
|
DIVISION_HEIGHT,
|
|
DIVISION_WIDTH,
|
|
DIVISION_HEIGHT);
|
|
|
|
/* Paint it */
|
|
cogl_pipeline_set_layer_texture (pipeline, 0, sub_texture);
|
|
cogl_object_unref (sub_texture);
|
|
cogl_framebuffer_draw_rectangle (test_fb, pipeline,
|
|
0.0f, 0.0f, DIVISION_WIDTH, DIVISION_HEIGHT);
|
|
|
|
|
|
/* 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_sub_texture_new (test_ctx,
|
|
state->tex,
|
|
0, 0,
|
|
SOURCE_SIZE,
|
|
DIVISION_HEIGHT);
|
|
cogl_pipeline_set_layer_texture (pipeline, 0, sub_texture);
|
|
cogl_object_unref (sub_texture);
|
|
cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline,
|
|
0.0f,
|
|
SOURCE_SIZE,
|
|
SOURCE_SIZE * 2.0f,
|
|
SOURCE_SIZE * 1.5f,
|
|
0.0f, 0.0f,
|
|
2.0f, 1.0f);
|
|
|
|
/* Create a sub texture of a sub texture */
|
|
full_texture = create_test_texture (state);
|
|
sub_texture = cogl_sub_texture_new (test_ctx,
|
|
full_texture,
|
|
20, 10, 30, 20);
|
|
cogl_object_unref (full_texture);
|
|
sub_sub_texture = cogl_sub_texture_new (test_ctx,
|
|
sub_texture,
|
|
20, 10, 10, 10);
|
|
cogl_object_unref (sub_texture);
|
|
cogl_pipeline_set_layer_texture (pipeline, 0, sub_sub_texture);
|
|
cogl_object_unref (sub_sub_texture);
|
|
cogl_framebuffer_draw_rectangle (test_fb, pipeline,
|
|
0.0f, SOURCE_SIZE * 2.0f,
|
|
10.0f, SOURCE_SIZE * 2.0f + 10.0f);
|
|
|
|
cogl_object_unref (pipeline);
|
|
}
|
|
|
|
static void
|
|
validate_part (int xpos, int ypos,
|
|
int width, int height,
|
|
uint32_t color)
|
|
{
|
|
test_utils_check_region (test_fb,
|
|
xpos + TEST_INSET,
|
|
ypos + TEST_INSET,
|
|
width - TEST_INSET - 2,
|
|
height - TEST_INSET - 2,
|
|
color);
|
|
}
|
|
|
|
static uint8_t *
|
|
create_update_data (void)
|
|
{
|
|
uint8_t *data = g_malloc (256 * 256 * 4), *p = data;
|
|
int x, y;
|
|
|
|
/* Create some image data that is 256x256 where the blue component
|
|
ranges from 0->255 along the x axis and the alpha component
|
|
ranges from 0->255 along the y axis. The red and green components
|
|
are all zero */
|
|
for (y = 0; y < 256; y++)
|
|
for (x = 0; x < 256; x++)
|
|
{
|
|
*(p++) = 0;
|
|
*(p++) = 0;
|
|
*(p++) = x;
|
|
*(p++) = y;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
validate_result (TestState *state)
|
|
{
|
|
int i, division_num, x, y;
|
|
CoglTexture2D *test_tex;
|
|
CoglSubTexture *sub_texture;
|
|
uint8_t *texture_data, *p;
|
|
int tex_width, tex_height;
|
|
|
|
/* Sub texture of the bottom right corner of the texture */
|
|
validate_part (0, 0, DIVISION_WIDTH, DIVISION_HEIGHT,
|
|
corner_colors[
|
|
(SOURCE_DIVISIONS_Y - 1) * SOURCE_DIVISIONS_X +
|
|
SOURCE_DIVISIONS_X - 1]);
|
|
|
|
/* Sub texture of the top half repeated horizontally */
|
|
for (i = 0; i < 2; i++)
|
|
for (division_num = 0; division_num < SOURCE_DIVISIONS_X; division_num++)
|
|
validate_part (i * SOURCE_SIZE + division_num * DIVISION_WIDTH,
|
|
SOURCE_SIZE,
|
|
DIVISION_WIDTH, DIVISION_HEIGHT,
|
|
corner_colors[division_num]);
|
|
|
|
/* Sub sub texture */
|
|
p = texture_data = g_malloc (10 * 10 * 4);
|
|
cogl_flush ();
|
|
cogl_framebuffer_read_pixels (test_fb,
|
|
0, SOURCE_SIZE * 2, 10, 10,
|
|
COGL_PIXEL_FORMAT_RGBA_8888,
|
|
p);
|
|
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_sub_texture_new (test_ctx,
|
|
state->tex,
|
|
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);
|
|
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 * SOURCE_SIZE / 2 / tex_width + SOURCE_SIZE / 4) /
|
|
DIVISION_WIDTH);
|
|
int div_y = ((y * SOURCE_SIZE / 2 / tex_height + SOURCE_SIZE / 4) /
|
|
DIVISION_HEIGHT);
|
|
uint32_t reference = corner_colors[div_x + div_y * SOURCE_DIVISIONS_X] >> 8;
|
|
uint32_t color = GUINT32_FROM_BE (*((uint32_t *)p)) >> 8;
|
|
g_assert (color == reference);
|
|
p += 4;
|
|
}
|
|
g_free (texture_data);
|
|
cogl_object_unref (sub_texture);
|
|
|
|
/* Create a 256x256 test texture */
|
|
test_tex = create_test_texture (state);
|
|
/* Create a sub texture the views the center half of the texture */
|
|
sub_texture = cogl_sub_texture_new (test_ctx,
|
|
test_tex,
|
|
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, 32, 32, 64, 64, 256, 256,
|
|
COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4,
|
|
texture_data);
|
|
g_free (texture_data);
|
|
cogl_object_unref (sub_texture);
|
|
/* Get the texture data */
|
|
p = texture_data = g_malloc (256 * 256 * 4);
|
|
cogl_texture_get_data (test_tex,
|
|
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
|
256 * 4, texture_data);
|
|
|
|
/* Verify the texture data */
|
|
for (y = 0; y < 256; y++)
|
|
for (x = 0; x < 256; x++)
|
|
{
|
|
/* 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 - 96);
|
|
g_assert ((*p++) == y - 96);
|
|
}
|
|
else
|
|
{
|
|
g_assert ((*p++) == x);
|
|
g_assert ((*p++) == y);
|
|
g_assert ((*p++) == 255);
|
|
g_assert ((*p++) == 255);
|
|
}
|
|
}
|
|
g_free (texture_data);
|
|
cogl_object_unref (test_tex);
|
|
}
|
|
|
|
void
|
|
test_sub_texture (void)
|
|
{
|
|
TestState state;
|
|
|
|
state.tex = create_source (&state);
|
|
|
|
cogl_framebuffer_orthographic (test_fb,
|
|
0, 0,
|
|
cogl_framebuffer_get_width (test_fb),
|
|
cogl_framebuffer_get_height (test_fb),
|
|
-1,
|
|
100);
|
|
|
|
paint (&state);
|
|
validate_result (&state);
|
|
|
|
cogl_object_unref (state.tex);
|
|
|
|
if (cogl_test_verbose ())
|
|
g_print ("OK\n");
|
|
}
|
|
|