diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index cf595e4c2..84878d1f7 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -27,6 +27,7 @@ test_conformance_SOURCES = \ test-cogl-multitexture.c \ test-cogl-texture-mipmaps.c \ test-cogl-texture-rectangle.c \ + test-cogl-wrap-modes.c \ test-cogl-pixel-buffer.c \ test-cogl-path.c \ test-path.c \ diff --git a/tests/conform/test-cogl-wrap-modes.c b/tests/conform/test-cogl-wrap-modes.c new file mode 100644 index 000000000..53e6103b7 --- /dev/null +++ b/tests/conform/test-cogl-wrap-modes.c @@ -0,0 +1,332 @@ +#include +#include + +#include "test-conform-common.h" + +#define TEX_SIZE 4 + +static const ClutterColor stage_color = { 0x80, 0x80, 0x80, 0xff }; + +typedef struct _TestState +{ + ClutterActor *stage; + CoglHandle texture; + guint frame; +} TestState; + +static CoglHandle +create_texture (CoglTextureFlags flags) +{ + guint8 *data = g_malloc (TEX_SIZE * TEX_SIZE * 4), *p = data; + CoglHandle tex; + int x, y; + + for (y = 0; y < TEX_SIZE; y++) + for (x = 0; x < TEX_SIZE; x++) + { + *(p++) = 0; + *(p++) = (x & 1) * 255; + *(p++) = (y & 1) * 255; + *(p++) = 255; + } + + tex = cogl_texture_new_from_data (TEX_SIZE, TEX_SIZE, flags, + COGL_PIXEL_FORMAT_RGBA_8888_PRE, + COGL_PIXEL_FORMAT_ANY, + TEX_SIZE * 4, + data); + + g_free (data); + + return tex; +} + +static CoglHandle +create_material (TestState *state, + CoglMaterialWrapMode wrap_mode_s, + CoglMaterialWrapMode wrap_mode_t) +{ + CoglHandle material; + + material = cogl_material_new (); + cogl_material_set_layer (material, 0, state->texture); + cogl_material_set_layer_filters (material, 0, + COGL_MATERIAL_FILTER_NEAREST, + COGL_MATERIAL_FILTER_NEAREST); + cogl_material_set_layer_wrap_mode_s (material, 0, wrap_mode_s); + cogl_material_set_layer_wrap_mode_t (material, 0, wrap_mode_t); + + return material; +} + +static CoglMaterialWrapMode +test_wrap_modes[] = + { + COGL_MATERIAL_WRAP_MODE_REPEAT, + COGL_MATERIAL_WRAP_MODE_REPEAT, + + COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE, + COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE, + + COGL_MATERIAL_WRAP_MODE_REPEAT, + COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE, + + COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE, + COGL_MATERIAL_WRAP_MODE_REPEAT, + + COGL_MATERIAL_WRAP_MODE_AUTOMATIC, + COGL_MATERIAL_WRAP_MODE_AUTOMATIC, + + COGL_MATERIAL_WRAP_MODE_AUTOMATIC, + COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE + }; + +static void +draw_tests (TestState *state) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (test_wrap_modes); i += 2) + { + CoglMaterialWrapMode wrap_mode_s, wrap_mode_t; + CoglHandle material; + + /* Create a separate material for each pair of wrap modes so + that we can verify whether the batch splitting works */ + wrap_mode_s = test_wrap_modes[i]; + wrap_mode_t = test_wrap_modes[i + 1]; + material = create_material (state, wrap_mode_s, wrap_mode_t); + cogl_set_source (material); + cogl_handle_unref (material); + /* Render the material at four times the size of the texture */ + cogl_rectangle_with_texture_coords (i * TEX_SIZE, 0, + (i + 2) * TEX_SIZE, TEX_SIZE * 2, + 0, 0, 2, 2); + } +} + +static const CoglTextureVertex vertices[4] = + { + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, TEX_SIZE * 2, 0.0f, 0.0f, 2.0f }, + { TEX_SIZE * 2, TEX_SIZE * 2, 0.0f, 2.0f, 2.0f }, + { TEX_SIZE * 2, 0.0f, 0.0f, 2.0f, 0.0f } + }; + +static void +draw_tests_polygon (TestState *state) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (test_wrap_modes); i += 2) + { + CoglMaterialWrapMode wrap_mode_s, wrap_mode_t; + CoglHandle material; + + wrap_mode_s = test_wrap_modes[i]; + wrap_mode_t = test_wrap_modes[i + 1]; + material = create_material (state, wrap_mode_s, wrap_mode_t); + cogl_set_source (material); + cogl_handle_unref (material); + cogl_push_matrix (); + cogl_translate (TEX_SIZE * i, 0.0f, 0.0f); + /* Render the material at four times the size of the texture */ + cogl_polygon (vertices, G_N_ELEMENTS (vertices), FALSE); + cogl_pop_matrix (); + } +} + +static void +draw_tests_vbo (TestState *state) +{ + CoglHandle vbo; + int i; + + vbo = cogl_vertex_buffer_new (4); + cogl_vertex_buffer_add (vbo, "gl_Vertex", 3, + COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, + sizeof (vertices[0]), + &vertices[0].x); + cogl_vertex_buffer_add (vbo, "gl_MultiTexCoord0", 2, + COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, + sizeof (vertices[0]), + &vertices[0].tx); + cogl_vertex_buffer_submit (vbo); + + for (i = 0; i < G_N_ELEMENTS (test_wrap_modes); i += 2) + { + CoglMaterialWrapMode wrap_mode_s, wrap_mode_t; + CoglHandle material; + + wrap_mode_s = test_wrap_modes[i]; + wrap_mode_t = test_wrap_modes[i + 1]; + material = create_material (state, wrap_mode_s, wrap_mode_t); + cogl_set_source (material); + cogl_handle_unref (material); + cogl_push_matrix (); + cogl_translate (TEX_SIZE * i, 0.0f, 0.0f); + /* Render the material at four times the size of the texture */ + cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN, 0, 4); + cogl_pop_matrix (); + } + + cogl_handle_unref (vbo); +} + +static void +draw_frame (TestState *state) +{ + /* Draw the tests first with a non atlased texture */ + state->texture = create_texture (COGL_TEXTURE_NO_ATLAS); + draw_tests (state); + cogl_handle_unref (state->texture); + + /* Draw the tests again with a possible atlased texture. This should + end up testing software repeats */ + state->texture = create_texture (COGL_TEXTURE_NONE); + cogl_push_matrix (); + cogl_translate (0.0f, TEX_SIZE * 2.0f, 0.0f); + draw_tests (state); + cogl_pop_matrix (); + cogl_handle_unref (state->texture); + + /* Draw the tests using cogl_polygon */ + state->texture = create_texture (COGL_TEXTURE_NO_ATLAS); + cogl_push_matrix (); + cogl_translate (0.0f, TEX_SIZE * 4.0f, 0.0f); + draw_tests_polygon (state); + cogl_pop_matrix (); + cogl_handle_unref (state->texture); + + /* Draw the tests using a vertex buffer */ + state->texture = create_texture (COGL_TEXTURE_NO_ATLAS); + cogl_push_matrix (); + cogl_translate (0.0f, TEX_SIZE * 6.0f, 0.0f); + draw_tests_vbo (state); + cogl_pop_matrix (); + cogl_handle_unref (state->texture); +} + +static void +validate_set (TestState *state, int offset) +{ + guint8 data[TEX_SIZE * 2 * TEX_SIZE * 2 * 4], *p; + int x, y, i; + + for (i = 0; i < G_N_ELEMENTS (test_wrap_modes); i += 2) + { + CoglMaterialWrapMode wrap_mode_s, wrap_mode_t; + + wrap_mode_s = test_wrap_modes[i]; + wrap_mode_t = test_wrap_modes[i + 1]; + + cogl_read_pixels (i * TEX_SIZE, offset * TEX_SIZE * 2, + TEX_SIZE * 2, TEX_SIZE * 2, + COGL_READ_PIXELS_COLOR_BUFFER, + COGL_PIXEL_FORMAT_RGBA_8888, + data); + + p = data; + + for (y = 0; y < TEX_SIZE * 2; y++) + for (x = 0; x < TEX_SIZE * 2; x++) + { + guint8 green, blue; + + if (x < TEX_SIZE || + wrap_mode_s == COGL_MATERIAL_WRAP_MODE_REPEAT || + wrap_mode_s == COGL_MATERIAL_WRAP_MODE_AUTOMATIC) + green = (x & 1) * 255; + else + green = ((TEX_SIZE - 1) & 1) * 255; + + if (y < TEX_SIZE || + wrap_mode_t == COGL_MATERIAL_WRAP_MODE_REPEAT || + wrap_mode_t == COGL_MATERIAL_WRAP_MODE_AUTOMATIC) + blue = (y & 1) * 255; + else + blue = ((TEX_SIZE - 1) & 1) * 255; + + g_assert_cmpint (p[0], ==, 0); + g_assert_cmpint (p[1], ==, green); + g_assert_cmpint (p[2], ==, blue); + + p += 4; + } + } +} + +static void +validate_result (TestState *state) +{ + validate_set (state, 0); /* non-atlased rectangle */ +#if 0 /* this doesn't currently work */ + validate_set (state, 1); /* atlased rectangle */ +#endif + validate_set (state, 2); /* cogl_polygon */ + validate_set (state, 3); /* vertex buffer */ + + /* 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; +} + +void +test_cogl_wrap_modes (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + TestState state; + guint idle_source; + guint paint_handler; + + state.frame = 0; + + state.stage = clutter_stage_get_default (); + + 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"); +} diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index e12823033..cecb44508 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -200,6 +200,7 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_sub_texture); TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_pixel_buffer); TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_texture_rectangle); + TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_wrap_modes); TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_contiguous); TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_interleved);