diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index cc04d44a9..26bbd70fc 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-texture-pixmap-x11.c \ test-cogl-wrap-modes.c \ test-cogl-pixel-buffer.c \ test-cogl-path.c \ diff --git a/tests/conform/test-cogl-texture-pixmap-x11.c b/tests/conform/test-cogl-texture-pixmap-x11.c new file mode 100644 index 000000000..f9b40993a --- /dev/null +++ b/tests/conform/test-cogl-texture-pixmap-x11.c @@ -0,0 +1,247 @@ +#include + +#include "test-conform-common.h" + +static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; + +#ifdef COGL_HAS_XLIB + +#include +/* This gets installed to a different location so a real application + would use */ +#include "cogl/winsys/cogl-texture-pixmap-x11.h" + +#define PIXMAP_WIDTH 512 +#define PIXMAP_HEIGHT 256 +#define GRID_SQUARE_SIZE 16 + +/* Coordinates of a square that we'll update */ +#define PIXMAP_CHANGE_X 1 +#define PIXMAP_CHANGE_Y 1 + +typedef struct _TestState +{ + ClutterActor *stage; + CoglHandle tfp; + Pixmap pixmap; + guint frame_count; + Display *display; +} TestState; + +static Pixmap +create_pixmap (TestState *state) +{ + Pixmap pixmap; + XGCValues gc_values = { 0, }; + GC black_gc, white_gc; + int screen = DefaultScreen (state->display); + int x, y; + + pixmap = XCreatePixmap (state->display, + DefaultRootWindow (state->display), + PIXMAP_WIDTH, PIXMAP_HEIGHT, + DefaultDepth (state->display, screen)); + + gc_values.foreground = BlackPixel (state->display, screen); + black_gc = XCreateGC (state->display, pixmap, GCForeground, &gc_values); + gc_values.foreground = WhitePixel (state->display, screen); + white_gc = XCreateGC (state->display, pixmap, GCForeground, &gc_values); + + /* Draw a grid of alternative black and white rectangles to the + pixmap */ + for (y = 0; y < PIXMAP_HEIGHT / GRID_SQUARE_SIZE; y++) + for (x = 0; x < PIXMAP_WIDTH / GRID_SQUARE_SIZE; x++) + XFillRectangle (state->display, pixmap, + ((x ^ y) & 1) ? black_gc : white_gc, + x * GRID_SQUARE_SIZE, + y * GRID_SQUARE_SIZE, + GRID_SQUARE_SIZE, + GRID_SQUARE_SIZE); + + XFreeGC (state->display, black_gc); + XFreeGC (state->display, white_gc); + + return pixmap; +} + +static void +update_pixmap (TestState *state) +{ + XGCValues gc_values = { 0, }; + GC black_gc; + int screen = DefaultScreen (state->display); + + gc_values.foreground = BlackPixel (state->display, screen); + black_gc = XCreateGC (state->display, state->pixmap, + GCForeground, &gc_values); + + /* Fill in one the rectangles with black */ + XFillRectangle (state->display, state->pixmap, + black_gc, + PIXMAP_CHANGE_X * GRID_SQUARE_SIZE, + PIXMAP_CHANGE_Y * GRID_SQUARE_SIZE, + GRID_SQUARE_SIZE, GRID_SQUARE_SIZE); + + XFreeGC (state->display, black_gc); +} + +static gboolean +check_paint (TestState *state, int x, int y, int scale) +{ + guint8 *data, *p, update_value = 0; + + p = data = g_malloc (PIXMAP_WIDTH * PIXMAP_HEIGHT * 4); + + cogl_read_pixels (x, y, PIXMAP_WIDTH / scale, PIXMAP_HEIGHT / scale, + COGL_READ_PIXELS_COLOR_BUFFER, + COGL_PIXEL_FORMAT_RGBA_8888_PRE, + data); + + for (y = 0; y < PIXMAP_HEIGHT / scale; y++) + for (x = 0; x < PIXMAP_WIDTH / scale; x++) + { + int grid_x = x * scale / GRID_SQUARE_SIZE; + int grid_y = y * scale / GRID_SQUARE_SIZE; + + /* If this is the updatable square then we'll let it be either + color but we'll return which one it was */ + if (grid_x == PIXMAP_CHANGE_X && grid_y == PIXMAP_CHANGE_Y) + { + if (x % (GRID_SQUARE_SIZE / scale) == 0 && + y % (GRID_SQUARE_SIZE / scale) == 0) + update_value = *p; + else + g_assert_cmpint (p[0], ==, update_value); + + g_assert (p[1] == update_value); + g_assert (p[2] == update_value); + p += 4; + } + else + { + guint8 value = ((grid_x ^ grid_y) & 1) ? 0x00 : 0xff; + g_assert_cmpint (*(p++), ==, value); + g_assert_cmpint (*(p++), ==, value); + g_assert_cmpint (*(p++), ==, value); + p++; + } + } + + g_free (data); + + return update_value == 0x00; +} + +/* We skip these frames first */ +#define FRAME_COUNT_BASE 5 +/* First paint the tfp with no mipmaps */ +#define FRAME_COUNT_NORMAL 6 +/* Then use mipmaps */ +#define FRAME_COUNT_MIPMAP 7 +/* After this frame will start waiting for the pixmap to change */ +#define FRAME_COUNT_UPDATED 8 + +static void +on_paint (ClutterActor *actor, TestState *state) +{ + CoglHandle material; + + material = cogl_material_new (); + cogl_material_set_layer (material, 0, state->tfp); + if (state->frame_count == FRAME_COUNT_MIPMAP) + { + const CoglMaterialFilter min_filter = + COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST; + cogl_material_set_layer_filters (material, 0, + min_filter, + COGL_MATERIAL_FILTER_NEAREST); + } + else + cogl_material_set_layer_filters (material, 0, + COGL_MATERIAL_FILTER_NEAREST, + COGL_MATERIAL_FILTER_NEAREST); + cogl_set_source (material); + + cogl_rectangle (0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT); + + cogl_rectangle (0, PIXMAP_HEIGHT, + PIXMAP_WIDTH / 4, PIXMAP_HEIGHT * 5 / 4); + + if (state->frame_count >= 5) + { + gboolean big_updated, small_updated; + + big_updated = check_paint (state, 0, 0, 1); + small_updated = check_paint (state, 0, PIXMAP_HEIGHT, 4); + + g_assert (big_updated == small_updated); + + if (state->frame_count < FRAME_COUNT_UPDATED) + g_assert (big_updated == FALSE); + else if (state->frame_count == FRAME_COUNT_UPDATED) + /* Change the pixmap and keep drawing until it updates */ + update_pixmap (state); + else if (big_updated) + /* If we successfully got the update then the test is over */ + clutter_main_quit (); + } + + state->frame_count++; +} + +static gboolean +queue_redraw (gpointer stage) +{ + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); + + return TRUE; +} + +#endif /* COGL_HAS_XLIB */ + +void +test_cogl_texture_pixmap_x11 (TestConformSimpleFixture *fixture, + gconstpointer data) +{ +#ifdef COGL_HAS_XLIB + + TestState state; + guint idle_handler; + guint paint_handler; + + state.frame_count = 0; + state.stage = clutter_stage_get_default (); + + state.display = clutter_x11_get_default_display (); + + state.pixmap = create_pixmap (&state); + state.tfp = cogl_texture_pixmap_x11_new (state.pixmap, TRUE); + + clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color); + + paint_handler = g_signal_connect_after (state.stage, "paint", + G_CALLBACK (on_paint), &state); + + idle_handler = g_idle_add (queue_redraw, state.stage); + + clutter_actor_show_all (state.stage); + + clutter_main (); + + g_signal_handler_disconnect (state.stage, paint_handler); + + g_source_remove (idle_handler); + + XFreePixmap (state.display, state.pixmap); + + if (g_test_verbose ()) + g_print ("OK\n"); + +#else /* COGL_HAS_XLIB */ + + if (g_test_verbose ()) + g_print ("Skipping\n"); + +#endif /* COGL_HAS_XLIB */ +} + diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index a2a48a422..d9307f940 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -207,6 +207,7 @@ main (int argc, char **argv) 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/texture", test_cogl_texture_pixmap_x11); TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_contiguous); TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_interleved);