mutter/tests/conform/test-cogl-texture-rectangle.c

269 lines
6.9 KiB
C
Raw Normal View History

#include <clutter/clutter.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
typedef struct _TestState
{
ClutterActor *stage;
guint frame;
} TestState;
static CoglHandle
create_source_rect (void)
{
#ifdef GL_TEXTURE_RECTANGLE_ARB
int x, y;
guint8 *data = g_malloc (256 * 256 * 4), *p = data;
CoglHandle tex;
GLuint gl_tex;
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
*(p++) = x;
*(p++) = y;
*(p++) = 0;
*(p++) = 255;
}
glPixelStorei (GL_UNPACK_ROW_LENGTH, 256);
glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glGenTextures (1, &gl_tex);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, gl_tex);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
GL_RGBA, 256, 256, 0,
GL_RGBA,
GL_UNSIGNED_BYTE,
data);
g_assert (glGetError () == GL_NO_ERROR);
g_free (data);
tex = cogl_texture_new_from_foreign (gl_tex,
GL_TEXTURE_RECTANGLE_ARB,
256, 256, 0, 0,
COGL_PIXEL_FORMAT_RGBA_8888);
return tex;
#else /* GL_TEXTURE_RECTANGLE_ARB */
return COGL_INVALID_HANDLE;
#endif /* GL_TEXTURE_RECTANGLE_ARB */
}
static CoglHandle
create_source_2d (void)
{
int x, y;
guint8 *data = g_malloc (256 * 256 * 4), *p = data;
CoglHandle tex;
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
*(p++) = 0;
*(p++) = x;
*(p++) = y;
*(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)
{
GLuint gl_tex;
CoglHandle tex_rect = create_source_rect ();
CoglHandle material_rect = cogl_material_new ();
CoglHandle tex_2d = create_source_2d ();
CoglHandle material_2d = cogl_material_new ();
g_assert (tex_rect != COGL_INVALID_HANDLE);
cogl_material_set_layer (material_rect, 0, tex_rect);
cogl_material_set_layer_filters (material_rect, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_material_set_layer (material_2d, 0, tex_2d);
cogl_material_set_layer_filters (material_2d, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_set_source (material_rect);
/* Render the texture repeated horizontally twice */
cogl_rectangle_with_texture_coords (0.0f, 0.0f, 512.0f, 256.0f,
0.0f, 0.0f, 2.0f, 1.0f);
/* Render the top half of the texture to test without repeating */
cogl_rectangle_with_texture_coords (0.0f, 256.0f, 256.0f, 384.0f,
0.0f, 0.0f, 1.0f, 0.5f);
cogl_set_source (material_2d);
/* Render the top half of a regular 2D texture */
cogl_rectangle_with_texture_coords (256.0f, 256.0f, 512.0f, 384.0f,
0.0f, 0.0f, 1.0f, 0.5f);
/* Flush the rendering now so we can safely delete the texture */
cogl_flush ();
cogl_handle_unref (material_rect);
/* Cogl doesn't destroy foreign textures so we have to do it manually */
cogl_texture_get_gl_texture (tex_rect, &gl_tex, NULL);
glDeleteTextures (1, &gl_tex);
cogl_handle_unref (tex_rect);
}
static void
validate_result (TestState *state)
{
guint8 *data, *p;
int x, y;
p = data = g_malloc (512 * 256 * 4);
cogl_read_pixels (0, 0, 512, 384,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888,
data);
for (y = 0; y < 384; y++)
for (x = 0; x < 512; x++)
{
if (x >= 256 && y >= 256)
{
g_assert_cmpint (p[0], ==, 0);
g_assert_cmpint (p[1], ==, x & 0xff);
g_assert_cmpint (p[2], ==, y & 0xff);
}
else
{
g_assert_cmpint (p[0], ==, x & 0xff);
g_assert_cmpint (p[1], ==, y & 0xff);
g_assert_cmpint (p[2], ==, 0);
}
p += 4;
}
g_free (data);
/* Comment this out to see what the test paints */
clutter_main_quit ();
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
int frame_num;
draw_frame (state);
/* XXX: Experiments have shown that for some buggy drivers, when using
* glReadPixels there is some kind of race, so we delay our test for a
* few frames and a few seconds:
*/
/* Need to increment frame first because clutter_stage_read_pixels
fires a redraw */
frame_num = state->frame++;
if (frame_num == 2)
validate_result (state);
else if (frame_num < 2)
g_usleep (G_USEC_PER_SEC);
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
static gboolean
check_rectangle_extension (void)
{
static const char rect_extension[] = "GL_ARB_texture_rectangle";
const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
const char *extensions_end;
extensions_end = extensions + strlen (extensions);
while (extensions < extensions_end)
{
const char *end = strchr (extensions, ' ');
if (end == NULL)
end = extensions_end;
if (end - extensions == sizeof (rect_extension) - 1 &&
!memcmp (extensions, rect_extension, sizeof (rect_extension) - 1))
return TRUE;
extensions = end + 1;
}
return FALSE;
}
void
test_cogl_texture_rectangle (TestConformSimpleFixture *fixture,
gconstpointer data)
{
TestState state;
guint idle_source;
guint paint_handler;
state.frame = 0;
state.stage = clutter_stage_get_default ();
/* Check whether GL supports the rectangle extension. If not we'll
just assume the test passes */
if (check_rectangle_extension ())
{
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, state.stage);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (on_paint), &state);
clutter_actor_show_all (state.stage);
clutter_main ();
g_source_remove (idle_source);
g_signal_handler_disconnect (state.stage, paint_handler);
if (g_test_verbose ())
g_print ("OK\n");
}
else if (g_test_verbose ())
g_print ("Skipping\n");
}