diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/.gitignore | 13 | ||||
-rw-r--r-- | test/Makefile.am | 30 | ||||
-rw-r--r-- | test/README | 3 | ||||
-rw-r--r-- | test/basic-copyarea-size.c | 102 | ||||
-rw-r--r-- | test/basic-copyarea.c | 301 | ||||
-rw-r--r-- | test/basic-fillrect.c | 263 | ||||
-rw-r--r-- | test/basic-putimage.c | 283 | ||||
-rw-r--r-- | test/basic-stress.c | 155 | ||||
-rw-r--r-- | test/mixed-stress.c | 208 | ||||
-rw-r--r-- | test/render-composite-solid.c | 255 | ||||
-rw-r--r-- | test/render-copyarea-size.c | 115 | ||||
-rw-r--r-- | test/render-copyarea.c | 324 | ||||
-rw-r--r-- | test/render-fill-copy.c | 279 | ||||
-rw-r--r-- | test/render-fill.c | 247 | ||||
-rw-r--r-- | test/render-trapezoid-image.c | 615 | ||||
-rw-r--r-- | test/render-trapezoid.c | 434 | ||||
-rw-r--r-- | test/test.h | 118 | ||||
-rw-r--r-- | test/test_display.c | 150 | ||||
-rw-r--r-- | test/test_image.c | 217 | ||||
-rw-r--r-- | test/test_log.c | 17 | ||||
-rw-r--r-- | test/test_render.c | 149 |
21 files changed, 4278 insertions, 0 deletions
diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 00000000..e44eb3f3 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,13 @@ +basic-copyarea +basic-copyarea-size +basic-fillrect +basic-putimage +basic-stress +render-fill +render-trapezoid +render-trapezoid-image +render-fill-copy +render-composite-solid +render-copyarea +render-copyarea-size +mixed-stress diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 00000000..8cacc9e4 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,30 @@ +TESTS = \ + basic-fillrect \ + basic-copyarea \ + basic-copyarea-size \ + basic-putimage \ + basic-stress \ + render-fill \ + render-trapezoid \ + render-trapezoid-image \ + render-fill-copy \ + render-composite-solid \ + render-copyarea \ + render-copyarea-size \ + mixed-stress \ + $(NULL) + +check_PROGRAMS = $(TESTS) + +AM_CFLAGS = @CWARNFLAGS@ @X11_CFLAGS@ +LDADD = libtest.la @X11_LIBS@ + +noinst_LTLIBRARIES = libtest.la +libtest_la_SOURCES = \ + test_display.c \ + test_image.c \ + test_log.c \ + test_render.c \ + $(NULL) + +EXTRA_DIST = README diff --git a/test/README b/test/README new file mode 100644 index 00000000..72b44508 --- /dev/null +++ b/test/README @@ -0,0 +1,3 @@ +These are no substitute for xts, rendercheck and cairo-test-suite. They +are intended to exercise corner cases in the batch management of long +drawing commands and more explicit checking of the acceleration paths. diff --git a/test/basic-copyarea-size.c b/test/basic-copyarea-size.c new file mode 100644 index 00000000..3c4249e3 --- /dev/null +++ b/test/basic-copyarea-size.c @@ -0,0 +1,102 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ + +#include "test.h" + +#define SIZE 20000 +struct draw { + Pixmap a, b; + GC gc; + XRenderPictFormat *format; +}; + +static void target_init(struct test_display *t, struct draw *tt, int size) +{ + XGCValues val; + + tt->a = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy), + size, size, 32); + tt->b = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy), + size, size, 32); + + val.graphics_exposures = 0; + tt->gc = XCreateGC(t->dpy, tt->a, GCGraphicsExposures, &val); + + tt->format = XRenderFindStandardFormat(t->dpy, PictStandardARGB32); + + val.foreground = 0xffff0000; + XChangeGC(t->dpy, tt->gc, GCForeground, &val); + XFillRectangle(t->dpy, tt->a, tt->gc, 0, 0, size, size); + + val.foreground = 0xff0000ff; + XChangeGC(t->dpy, tt->gc, GCForeground, &val); + XFillRectangle(t->dpy, tt->b, tt->gc, 0, 0, size, size); +} + +static void target_fini(struct test_display *t, struct draw *tt) +{ + XFreePixmap(t->dpy, tt->a); + XFreePixmap(t->dpy, tt->b); +} + +int main(int argc, char **argv) +{ + struct test test; + struct draw real, ref; + int size, i; + + test_init(&test, argc, argv); + + /* Copy back and forth betwenn two pixmaps, gradually getting larger */ + for (size = 1; size <= SIZE; size = (size * 3 + 1) / 2) { + target_init(&test.real, &real, size); + target_init(&test.ref, &ref, size); + + printf("size=%d\n", size); + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + do { + int sx = rand() % (2*size) - size; + int sy = rand() % (2*size) - size; + + int dx = rand() % (2*size) - size; + int dy = rand() % (2*size) - size; + + int order = rand() & 1; + + XCopyArea(test.real.dpy, + order ? real.a : real.b, + (!order) ? real.a : real.b, + real.gc, + sx, sy, + size, size, + dx, dy); + + XCopyArea(test.ref.dpy, + order ? ref.a : ref.b, + (!order) ? ref.a : ref.b, + ref.gc, + sx, sy, + size, size, + dx, dy); + } while (--reps); + } + + test_compare(&test, + real.a, real.format, + ref.a, ref.format, + 0, 0, size, size); + test_compare(&test, + real.b, real.format, + ref.b, ref.format, + 0, 0, size, size); + + target_fini(&test.real, &real); + target_fini(&test.ref, &ref); + } + + return 0; +} diff --git a/test/basic-copyarea.c b/test/basic-copyarea.c new file mode 100644 index 00000000..a4302f3a --- /dev/null +++ b/test/basic-copyarea.c @@ -0,0 +1,301 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +static void +show_cells(char *buf, + const uint32_t *real, const uint32_t *ref, + int x, int y, int w, int h) +{ + int i, j, len = 0; + + for (j = y - 2; j <= y + 2; j++) { + if (j < 0 || j >= h) + continue; + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", real[j*w+i]); + } + + len += sprintf(buf+len, "\t"); + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", ref[j*w+i]); + } + + len += sprintf(buf+len, "\n"); + } +} + +static void fill_rect(struct test_display *t, + Drawable d, + XRenderPictFormat *format, + int use_window, int tx, int ty, + uint8_t alu, int x, int y, int w, int h, uint32_t fg) +{ + XGCValues val; + Drawable tmp; + GC gc; + + val.graphics_exposures = 0; + val.function = alu; + val.foreground = fg; + + if (use_window) { + XSetWindowAttributes attr; + + attr.override_redirect = 1; + tmp = XCreateWindow(t->dpy, DefaultRootWindow(t->dpy), + tx, ty, + w, h, + 0, format->depth, + InputOutput, + DefaultVisual(t->dpy, + DefaultScreen(t->dpy)), + CWOverrideRedirect, &attr); + XMapWindow(t->dpy, tmp); + } else + tmp = XCreatePixmap(t->dpy, d, w, h, format->depth); + + gc = XCreateGC(t->dpy, d, GCGraphicsExposures | GCForeground, &val); + XFillRectangle(t->dpy, tmp, gc, 0, 0, w, h); + + XChangeGC(t->dpy, gc, GCFunction, &val); + XCopyArea(t->dpy, tmp, d, gc, 0, 0, w, h, x, y); + + XFreeGC(t->dpy, gc); + if (use_window) + XDestroyWindow(t->dpy, tmp); + else + XFreePixmap(t->dpy, tmp); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + test_target_create_render(&t->real, target, &tt); + + printf("Testing setting of single pixels (%s): ", + test_target_name(target)); + fflush(stdout); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + uint32_t fg = rand(); + + fill_rect(&t->real, tt.draw, tt.format, + 0, 0, 0, + GXcopy, x, y, 1, 1, fg); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*tt.width+x] = fg; + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + uint32_t result; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask = depth_mask(image.depth); + + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int w = 1 + rand() % (tt.width - 1); + int h = 1 + rand() % (tt.height - 1); + uint32_t fg = rand(); + + x = rand() % (2*tt.width) - tt.width; + y = rand() % (2*tt.height) - tt.height; + + fill_rect(&t->real, tt.draw, tt.format, + 0, 0, 0, + GXcopy, x, y, w, h, fg); + + if (x < 0) + w += x, x = 0; + if (y < 0) + h += y, y = 0; + if (x >= tt.width || y >= tt.height) + continue; + + if (x + w > tt.width) + w = tt.width - x; + if (y + h > tt.height) + h = tt.height - y; + if (w <= 0 || h <= 0) + continue; + + pixman_fill(cells, tt.width, 32, x, y, w, h, fg); + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = *(uint32_t *) + (image.data + + y*image.bytes_per_line + + x*image.bits_per_pixel/8); + if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { + char buf[600]; + uint32_t mask = depth_mask(image.depth); + show_cells(buf, + (uint32_t*)image.data, cells, + x, y, tt.width, tt.height); + + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n%s", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result, buf); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, int reps, int sets, enum target target, int use_window) +{ + struct test_target real, ref; + int r, s; + + printf("Testing area fills (%s, using %s source): ", + test_target_name(target), use_window ? "window" : "pixmap"); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (real.width - 1); + int y = rand() % (real.height - 1); + int w = 1 + rand() % (real.width - x - 1); + int h = 1 + rand() % (real.height - y - 1); + int tmpx = w == real.width ? 0 : rand() % (real.width - w); + int tmpy = h == real.height ? 0 : rand() % (real.height - h); + uint8_t alu = rand() % (GXset + 1); + uint32_t fg = rand(); + + fill_rect(&t->real, real.draw, real.format, + use_window, tmpx, tmpy, + alu, x, y, w, h, fg); + fill_rect(&t->ref, ref.draw, ref.format, + use_window, tmpx, tmpy, + alu, x, y, w, h, fg); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} + +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + enum target t; + + if (sets < 2) + sets = 2; + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + pixel_tests(&test, reps, sets, t); + area_tests(&test, reps, sets, t); + rect_tests(&test, reps, sets, t, 0); + if (t != PIXMAP) + rect_tests(&test, reps, sets, t, 1); + } + } + + return 0; +} diff --git a/test/basic-fillrect.c b/test/basic-fillrect.c new file mode 100644 index 00000000..55dacb63 --- /dev/null +++ b/test/basic-fillrect.c @@ -0,0 +1,263 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +static void +show_cells(char *buf, + const uint32_t *real, const uint32_t *ref, + int x, int y, int w, int h) +{ + int i, j, len = 0; + + for (j = y - 2; j <= y + 2; j++) { + if (j < 0 || j >= h) + continue; + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", real[j*w+i]); + } + + len += sprintf(buf+len, "\t"); + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", ref[j*w+i]); + } + + len += sprintf(buf+len, "\n"); + } +} + +static void fill_rect(struct test_display *t, Drawable d, uint8_t alu, + int x, int y, int w, int h, uint32_t fg) +{ + XGCValues val; + GC gc; + + val.function = alu; + val.foreground = fg; + + gc = XCreateGC(t->dpy, d, GCForeground | GCFunction, &val); + XFillRectangle(t->dpy, d, gc, x, y, w, h); + XFreeGC(t->dpy, gc); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + test_target_create_render(&t->real, target, &tt); + + printf("Testing setting of single pixels (%s): ", + test_target_name(target)); + fflush(stdout); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + uint32_t fg = rand(); + + fill_rect(&t->real, tt.draw, GXcopy, + x, y, 1, 1, fg); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*tt.width+x] = fg; + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + uint32_t result; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask = depth_mask(image.depth); + + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int w = rand() % tt.width; + int h = rand() % tt.height; + uint32_t fg = rand(); + + x = rand() % (2*tt.width) - tt.width; + y = rand() % (2*tt.height) - tt.height; + + fill_rect(&t->real, tt.draw, GXcopy, + x, y, w, h, fg); + + if (x < 0) + w += x, x = 0; + if (y < 0) + h += y, y = 0; + if (x >= tt.width || y >= tt.height) + continue; + + if (x + w > tt.width) + w = tt.width - x; + if (y + h > tt.height) + h = tt.height - y; + if (w <= 0 || h <= 0) + continue; + + pixman_fill(cells, tt.width, 32, x, y, w, h, fg); + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = *(uint32_t *) + (image.data + + y*image.bytes_per_line + + x*image.bits_per_pixel/8); + if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { + char buf[600]; + uint32_t mask = depth_mask(image.depth); + show_cells(buf, + (uint32_t*)image.data, cells, + x, y, tt.width, tt.height); + + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n%s", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result, buf); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target real, ref; + int r, s; + + printf("Testing area fills (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (2*real.width) - real.width; + int y = rand() % (2*real.height) - real.height; + int w = rand() % (2*real.width); + int h = rand() % (2*real.height); + uint8_t alu = rand() % (GXset + 1); + uint32_t fg = rand(); + + fill_rect(&t->real, real.draw, alu, + x, y, w, h, fg); + fill_rect(&t->ref, ref.draw, alu, + x, y, w, h, fg); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} + +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + enum target t; + + if (sets < 2) + sets = 2; + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + pixel_tests(&test, reps, sets, t); + area_tests(&test, reps, sets, t); + rect_tests(&test, reps, sets, t); + } + } + + return 0; +} diff --git a/test/basic-putimage.c b/test/basic-putimage.c new file mode 100644 index 00000000..ce319764 --- /dev/null +++ b/test/basic-putimage.c @@ -0,0 +1,283 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +static void +show_cells(char *buf, + const uint32_t *real, const uint32_t *ref, + int x, int y, int w, int h) +{ + int i, j, len = 0; + + for (j = y - 2; j <= y + 2; j++) { + if (j < 0 || j >= h) + continue; + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", real[j*w+i]); + } + + len += sprintf(buf+len, "\t"); + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", ref[j*w+i]); + } + + len += sprintf(buf+len, "\n"); + } +} + +static void fill_rect(struct test_display *dpy, + Drawable d, XRenderPictFormat *format, + int use_shm, + uint8_t alu, int x, int y, int w, int h, uint32_t fg) +{ + XImage image; + XGCValues val; + GC gc; + + test_init_image(&image, &dpy->shm, format, w, h); + + pixman_fill((uint32_t*)image.data, + image.bytes_per_line/sizeof(uint32_t), + image.bits_per_pixel, + 0, 0, w, h, fg); + + val.function = alu; + gc = XCreateGC(dpy->dpy, d, GCFunction, &val); + if (use_shm) { + XShmPutImage(dpy->dpy, d, gc, &image, 0, 0, x, y, w, h, 0); + XSync(dpy->dpy, 1); + } else { + XPutImage(dpy->dpy, d, gc, &image, 0, 0, x, y, w, h); + } + XFreeGC(dpy->dpy, gc); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target, int use_shm) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + test_target_create_render(&t->real, target, &tt); + + printf("Testing setting of single pixels (%s %s shm): ", + test_target_name(target), use_shm ? "with" : "without" ); + fflush(stdout); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + uint32_t fg = color(red, green, blue, alpha); + + fill_rect(&t->real, tt.draw, tt.format, use_shm, + GXcopy, x, y, 1, 1, fg); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*tt.width+x] = fg; + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t result; + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask; + + if (image.depth == 32) + mask = 0xffffffff; + else + mask = (1 << image.depth) - 1; + die("failed to set pixel (%d,%d) to %08x[%08x], found %08x instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target, int use_shm) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s %s shm): ", + test_target_name(target), use_shm ? "with" : "without" ); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + uint32_t fg = color(red, green, blue, alpha); + int w, h; + + x = rand() % tt.width; + y = rand() % tt.height; + w = rand() % (tt.width - x); + h = rand() % (tt.height - y); + + fill_rect(&t->real, tt.draw, tt.format, use_shm, + GXcopy, x, y, w, h, fg); + + pixman_fill(cells, tt.width, 32, x, y, w, h, fg); + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = + *(uint32_t *)(image.data + + y*image.bytes_per_line + + image.bits_per_pixel*x/8); + if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { + uint32_t mask = depth_mask(image.depth); + char buf[600]; + + show_cells(buf, + (uint32_t*)image.data, cells, + x, y, tt.width, tt.height); + + die("failed to set pixel (%d,%d) to %08x[%08x], found %08x [%08x] instead\n%s", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, result, + buf); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, int reps, int sets, enum target target, int use_shm) +{ + struct test_target real, ref; + int r, s; + + printf("Testing area fills (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % real.width; + int y = rand() % real.height; + int w = rand() % (real.width - x); + int h = rand() % (real.height - y); + uint8_t alu = rand() % (GXset + 1); + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + uint8_t fg = color(red, green, blue, alpha); + + fill_rect(&t->real, real.draw, real.format, use_shm, + alu, x, y, w, h, fg); + fill_rect(&t->ref, ref.draw, ref.format, use_shm, + alu, x, y, w, h, fg); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + enum target t; + + if (sets < 2) + sets = 2; + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + pixel_tests(&test, reps, sets, t, 0); + area_tests(&test, reps, sets, t, 0); + rect_tests(&test, reps, sets, t, 0); + + pixel_tests(&test, reps, sets, t, 1); + area_tests(&test, reps, sets, t, 1); + rect_tests(&test, reps, sets, t, 1); + } + } + + return 0; +} diff --git a/test/basic-stress.c b/test/basic-stress.c new file mode 100644 index 00000000..28fe5c96 --- /dev/null +++ b/test/basic-stress.c @@ -0,0 +1,155 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> + +#include "test.h" + +static void fill_rect(struct test_target *tt, + int alu, int color, + int x, int y, int w, int h) +{ + XGCValues val; + + val.function = alu; + val.foreground = color; + XChangeGC(tt->dpy->dpy, tt->gc, GCFunction | GCForeground, &val); + + XFillRectangle(tt->dpy->dpy, tt->draw, tt->gc, x, y, w, h); +} + +static void clear(struct test_target *tt) +{ + fill_rect(tt, + GXcopy, 0, + 0, 0, tt->width, tt->height); +} + +static void fill(struct test_target *real, + struct test_target *ref) +{ + int x = rand() % (2*real->width) - real->width; + int y = rand() % (2*real->height) - real->height; + int w = rand() % (2*real->width); + int h = rand() % (2*real->height); + int color = rand(); + int alu = rand() % 16; + + fill_rect(real, alu, color, x, y, w, h); + fill_rect(ref, alu, color, x, y, w, h); +} + +static void copy(struct test_target *real, + struct test_target *ref) +{ + int sx = rand() % (2*real->width) - ref->width; + int sy = rand() % (2*real->height) - ref->height; + int dx = rand() % (2*real->width) - ref->width; + int dy = rand() % (2*real->height) - ref->height; + int w = rand() % (2*real->width); + int h = rand() % (2*real->height); + XGCValues val; + + val.function = rand() % 16; + + XChangeGC(real->dpy->dpy, real->gc, GCFunction, &val); + XCopyArea(real->dpy->dpy, + real->draw, real->draw, real->gc, + sx, sy, w, h, dx, dy); + + XChangeGC(ref->dpy->dpy, ref->gc, GCFunction, &val); + XCopyArea(ref->dpy->dpy, + ref->draw, ref->draw, ref->gc, + sx, sy, w, h, dx, dy); +} + +static void _put(struct test_target *tt, + int x, int y, int w,int h, int color, int alu) +{ + XImage image; + XGCValues val; + + val.function = alu; + + test_init_image(&image, &tt->dpy->shm, tt->format, w, h); + pixman_fill((uint32_t*)image.data, + image.bytes_per_line/sizeof(uint32_t), + image.bits_per_pixel, + 0, 0, w, h, color); + + XChangeGC(tt->dpy->dpy, tt->gc, GCFunction, &val); + if (rand() & 1) { + XShmPutImage(tt->dpy->dpy, tt->draw, tt->gc, &image, + 0, 0, x, y, w, h, 0); + XSync(tt->dpy->dpy, 1); + } else { + XPutImage(tt->dpy->dpy, tt->draw, tt->gc, &image, + 0, 0, x, y, w, h); + } +} + +static void put(struct test_target *real, + struct test_target *ref) +{ + int x = rand() % (2*real->width) - real->width; + int y = rand() % (2*real->height) - real->height; + int w = rand() % real->width; + int h = rand() % real->height; + int color = rand(); + int alu = rand() % 16; + + _put(real, x, y, w, h, color, alu); + _put(ref, x, y, w, h, color, alu); +} + +static void rect_tests(struct test *test, int iterations, enum target target) +{ + struct test_target real, ref; + void (* const ops[])(struct test_target *, struct test_target *) = { + copy, + fill, + put, + }; + int n; + + printf("Running mixed ops stress against %s: ", + test_target_name(target)); + fflush(stdout); + + test_target_create_render(&test->real, target, &real); + test_target_create_render(&test->ref, target, &ref); + + clear(&real); + clear(&ref); + + for (n = 0; n < iterations; n++) + ops[rand() % ARRAY_SIZE(ops)](&real, &ref); + + test_compare(test, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + + printf("passed [%d iterations]\n", n); + + test_target_destroy_render(&test->real, &real); + test_target_destroy_render(&test->ref, &ref); +} + +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int iterations = 1 << i; + rect_tests(&test, iterations, 0); + rect_tests(&test, iterations, 1); + } + + return 0; +} diff --git a/test/mixed-stress.c b/test/mixed-stress.c new file mode 100644 index 00000000..8aa7ca91 --- /dev/null +++ b/test/mixed-stress.c @@ -0,0 +1,208 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> + +#include "test.h" + +static void _render_copy(struct test_target *tt, + int x, int y, int w, int h, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + XRenderColor color; + Picture src; + Pixmap tmp; + + tmp = XCreatePixmap(tt->dpy->dpy, DefaultRootWindow(tt->dpy->dpy), + 10+w, 20+h, tt->format->depth); + src = XRenderCreatePicture(tt->dpy->dpy, tmp, tt->format, 0, NULL); + + /* magenta border */ + color.red = 0xffff; + color.green = 0; + color.blue = 0xffff; + color.alpha = 0xffff; + XRenderFillRectangle(tt->dpy->dpy, PictOpSrc, src, &color, 0, 0, w+10, h+20); + + color.red = red * alpha; + color.green = green * alpha; + color.blue = blue * alpha; + color.alpha = alpha << 8 | alpha; + XRenderFillRectangle(tt->dpy->dpy, PictOpSrc, src, &color, 5, 10, w, h); + + XRenderComposite(tt->dpy->dpy, PictOpSrc, + src, 0, tt->picture, + 5, 10, + 0, 0, + x, y, + w, h); + + XRenderFreePicture(tt->dpy->dpy, src); + XFreePixmap(tt->dpy->dpy, tmp); +} + +static void render_copy(struct test_target *real, + struct test_target *ref) +{ + int x = rand() % (2*real->width) - real->width; + int y = rand() % (2*real->height) - real->height; + int w = rand() % (2*real->width); + int h = rand() % (2*real->height); + int red = rand() & 0xff; + int green = rand() & 0xff; + int blue = rand() & 0xff; + int alpha = rand() & 0xff; + + _render_copy(real, x, y, w, h, red, green, blue, alpha); + _render_copy(ref, x, y, w, h, red, green, blue, alpha); +} + +static void fill_rect(struct test_target *tt, + int alu, int color, + int x, int y, int w, int h) +{ + XGCValues val; + + val.function = alu; + val.foreground = color; + XChangeGC(tt->dpy->dpy, tt->gc, GCFunction | GCForeground, &val); + + XFillRectangle(tt->dpy->dpy, tt->draw, tt->gc, x, y, w, h); +} + +static void clear(struct test_target *tt) +{ + fill_rect(tt, + GXcopy, 0, + 0, 0, tt->width, tt->height); +} + +static void basic_fill(struct test_target *real, + struct test_target *ref) +{ + int x = rand() % (2*real->width) - real->width; + int y = rand() % (2*real->height) - real->height; + int w = rand() % (2*real->width); + int h = rand() % (2*real->height); + int color = rand(); + int alu = rand() % 16; + + fill_rect(real, alu, color, x, y, w, h); + fill_rect(ref, alu, color, x, y, w, h); +} + +static void basic_copy(struct test_target *real, + struct test_target *ref) +{ + int sx = rand() % (2*real->width) - ref->width; + int sy = rand() % (2*real->height) - ref->height; + int dx = rand() % (2*real->width) - ref->width; + int dy = rand() % (2*real->height) - ref->height; + int w = rand() % (2*real->width); + int h = rand() % (2*real->height); + XGCValues val; + + val.function = rand() % 16; + + XChangeGC(real->dpy->dpy, real->gc, GCFunction, &val); + XCopyArea(real->dpy->dpy, + real->draw, real->draw, real->gc, + sx, sy, w, h, dx, dy); + + XChangeGC(ref->dpy->dpy, ref->gc, GCFunction, &val); + XCopyArea(ref->dpy->dpy, + ref->draw, ref->draw, ref->gc, + sx, sy, w, h, dx, dy); +} + +static void _put(struct test_target *tt, + int x, int y, int w,int h, int color, int alu) +{ + XImage image; + XGCValues val; + + val.function = alu; + + test_init_image(&image, &tt->dpy->shm, tt->format, w, h); + pixman_fill((uint32_t*)image.data, + image.bytes_per_line/sizeof(uint32_t), + image.bits_per_pixel, + 0, 0, w, h, color); + + XChangeGC(tt->dpy->dpy, tt->gc, GCFunction, &val); + if (rand() & 1) { + XShmPutImage(tt->dpy->dpy, tt->draw, tt->gc, &image, + 0, 0, x, y, w, h, 0); + XSync(tt->dpy->dpy, 1); + } else { + XPutImage(tt->dpy->dpy, tt->draw, tt->gc, &image, + 0, 0, x, y, w, h); + } +} + +static void basic_put(struct test_target *real, + struct test_target *ref) +{ + int x = rand() % (2*real->width) - real->width; + int y = rand() % (2*real->height) - real->height; + int w = rand() % real->width; + int h = rand() % real->height; + int color = rand(); + int alu = rand() % 16; + + _put(real, x, y, w, h, color, alu); + _put(ref, x, y, w, h, color, alu); +} + +static void rect_tests(struct test *test, int iterations, enum target target) +{ + struct test_target real, ref; + void (* const ops[])(struct test_target *, struct test_target *) = { + basic_copy, + basic_fill, + basic_put, + render_copy, + }; + int n; + + printf("Running mixed ops stress against %s: ", + test_target_name(target)); + fflush(stdout); + + test_target_create_render(&test->real, target, &real); + test_target_create_render(&test->ref, target, &ref); + + clear(&real); + clear(&ref); + + for (n = 0; n < iterations; n++) + ops[rand() % ARRAY_SIZE(ops)](&real, &ref); + + test_compare(test, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + + printf("passed [%d iterations]\n", n); + + test_target_destroy_render(&test->real, &real); + test_target_destroy_render(&test->ref, &ref); +} + +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int iterations = 1 << i; + rect_tests(&test, iterations, 0); + rect_tests(&test, iterations, 1); + } + + return 0; +} diff --git a/test/render-composite-solid.c b/test/render-composite-solid.c new file mode 100644 index 00000000..3918247d --- /dev/null +++ b/test/render-composite-solid.c @@ -0,0 +1,255 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +static const uint8_t ops[] = { + PictOpClear, + PictOpSrc, + PictOpDst, +}; + +static void fill_rect(struct test_display *dpy, Picture p, uint8_t op, + int x, int y, int w, int h, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + XRenderColor render_color; + Picture solid; + + render_color.red = red * alpha; + render_color.green = green * alpha; + render_color.blue = blue * alpha; + render_color.alpha = alpha << 8 | alpha; + + solid = XRenderCreateSolidFill(dpy->dpy, &render_color); + XRenderComposite(dpy->dpy, op, solid, 0, p, 0, 0, 0, 0, x, y, w,h); + XRenderFreePicture(dpy->dpy, solid); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + test_target_create_render(&t->real, target, &tt); + + printf("Testing setting of single pixels (%s): ", + test_target_name(target)); + fflush(stdout); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + fill_rect(&t->real, tt.picture, PictOpSrc, + x, y, 1, 1, + red, green, blue, alpha); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*tt.width+x] = color(red, green, blue, alpha); + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t result; + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask; + + if (image.depth == 32) + mask = 0xffffffff; + else + mask = (1 << image.depth) - 1; + die("failed to set pixel (%d,%d) to %08x[%08x], found %08x instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int w = rand() % tt.width; + int h = rand() % tt.height; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + x = rand() % (2*tt.width) - tt.width; + y = rand() % (2*tt.height) - tt.height; + + fill_rect(&t->real, tt.picture, PictOpSrc, + x, y, w, h, red, green, blue, alpha); + + if (x < 0) + w += x, x = 0; + if (y < 0) + h += y, y = 0; + if (x >= tt.width || y >= tt.height) + continue; + + if (x + w > tt.width) + w = tt.width - x; + if (y + h > tt.height) + h = tt.height - y; + if (w <= 0 || h <= 0) + continue; + + pixman_fill(cells, tt.width, 32, x, y, w, h, + color(red, green, blue, alpha)); + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = + *(uint32_t *)(image.data + + y*image.bytes_per_line + + image.bits_per_pixel*x/8); + if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { + uint32_t mask; + if (image.depth == 32) + mask = 0xffffffff; + else + mask = (1 << image.depth) - 1; + die("failed to set pixel (%d,%d) to %08x[%08x], found %08x instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target real, ref; + int r, s; + + printf("Testing area fills (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (2*real.width) - real.width; + int y = rand() % (2*real.height) - real.height; + int w = rand() % real.width; + int h = rand() % real.height; + int op = ops[rand() % sizeof(ops)]; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + fill_rect(&t->real, real.picture, + op, x, y, w, h, + red, green, blue, alpha); + fill_rect(&t->ref, ref.picture, + op, x, y, w, h, + red, green, blue, alpha); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} + +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + enum target t; + + if (sets < 2) + sets = 2; + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + pixel_tests(&test, reps, sets, t); + area_tests(&test, reps, sets, t); + rect_tests(&test, reps, sets, t); + } + } + + return 0; +} diff --git a/test/render-copyarea-size.c b/test/render-copyarea-size.c new file mode 100644 index 00000000..89d1ed31 --- /dev/null +++ b/test/render-copyarea-size.c @@ -0,0 +1,115 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ + +#include "test.h" + +#define SIZE 20000 +struct draw { + Pixmap a, b; + Picture pa, pb; + GC gc; + XRenderPictFormat *format; +}; + +static void target_init(struct test_display *t, struct draw *tt, int size) +{ + XRenderColor color; + + tt->format = XRenderFindStandardFormat(t->dpy, PictStandardARGB32); + + tt->a = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy), + size, size, tt->format->depth); + tt->pa = XRenderCreatePicture(t->dpy, tt->a, tt->format, 0, NULL); + + color.alpha = 0xffff; + color.red = 0xffff; + color.green = 0; + color.blue = 0; + XRenderFillRectangle(t->dpy, PictOpSrc, tt->pa, &color, 0, 0, size, size); + + tt->b = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy), + size, size, tt->format->depth); + tt->pb = XRenderCreatePicture(t->dpy, tt->b, tt->format, 0, NULL); + + color.alpha = 0xffff; + color.red = 0; + color.green = 0; + color.blue = 0xffff; + XRenderFillRectangle(t->dpy, PictOpSrc, tt->pb, &color, 0, 0, size, size); +} + +static void target_fini(struct test_display *t, struct draw *tt) +{ + XRenderFreePicture(t->dpy, tt->pa); + XFreePixmap(t->dpy, tt->a); + + XRenderFreePicture(t->dpy, tt->pb); + XFreePixmap(t->dpy, tt->b); +} + +int main(int argc, char **argv) +{ + struct test test; + struct draw real, ref; + int size, i; + + test_init(&test, argc, argv); + + /* Copy back and forth betwenn two pixmaps, gradually getting larger */ + for (size = 1; size <= SIZE; size = (size * 3 + 1) / 2) { + target_init(&test.real, &real, size); + target_init(&test.ref, &ref, size); + + printf("size=%d\n", size); + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + do { + int sx = rand() % (2*size) - size; + int sy = rand() % (2*size) - size; + + int dx = rand() % (2*size) - size; + int dy = rand() % (2*size) - size; + + int w = rand() % size; + int h = rand() % size; + + int order = rand() & 1; + + XRenderComposite(test.real.dpy, PictOpSrc, + order ? real.pa : real.pb, + 0, + (!order) ? real.pa : real.pb, + sx, sy, + 0, 0, + dx, dy, + w, h); + + XRenderComposite(test.ref.dpy, PictOpSrc, + order ? ref.pa : ref.pb, + 0, + (!order) ? ref.pa : ref.pb, + sx, sy, + 0, 0, + dx, dy, + w, h); + } while (--reps); + } + + test_compare(&test, + real.a, real.format, + ref.a, ref.format, + 0, 0, size, size); + test_compare(&test, + real.b, real.format, + ref.b, ref.format, + 0, 0, size, size); + + target_fini(&test.real, &real); + target_fini(&test.ref, &ref); + } + + return 0; +} diff --git a/test/render-copyarea.c b/test/render-copyarea.c new file mode 100644 index 00000000..d45a4569 --- /dev/null +++ b/test/render-copyarea.c @@ -0,0 +1,324 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +static void +show_cells(char *buf, + const uint32_t *real, const uint32_t *ref, + int x, int y, int w, int h) +{ + int i, j, len = 0; + + for (j = y - 2; j <= y + 2; j++) { + if (j < 0 || j >= h) + continue; + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", real[j*w+i]); + } + + len += sprintf(buf+len, "\t"); + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", ref[j*w+i]); + } + + len += sprintf(buf+len, "\n"); + } +} + +static void fill_rect(struct test_display *t, + Picture p, + XRenderPictFormat *format, + int use_window, int tx, int ty, + uint8_t op, int x, int y, int w, int h, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + Drawable tmp; + XRenderColor color; + Picture src; + + if (use_window) { + XSetWindowAttributes attr; + + attr.override_redirect = 1; + tmp = XCreateWindow(t->dpy, DefaultRootWindow(t->dpy), + tx, ty, + w, h, + 0, format->depth, + InputOutput, + DefaultVisual(t->dpy, + DefaultScreen(t->dpy)), + CWOverrideRedirect, &attr); + XMapWindow(t->dpy, tmp); + } else + tmp = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy), + w, h, format->depth); + + src = XRenderCreatePicture(t->dpy, tmp, format, 0, NULL); + color.red = red * alpha; + color.green = green * alpha; + color.blue = blue * alpha; + color.alpha = alpha << 8 | alpha; + XRenderFillRectangle(t->dpy, PictOpSrc, src, &color, 0, 0, w, h); + XRenderComposite(t->dpy, op, src, 0, p, 0, 0, 0, 0, x, y, w, h); + + XRenderFreePicture(t->dpy, src); + if (use_window) + XDestroyWindow(t->dpy, tmp); + else + XFreePixmap(t->dpy, tmp); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + test_target_create_render(&t->real, target, &tt); + + printf("Testing setting of single pixels (%s): ", + test_target_name(target)); + fflush(stdout); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + uint8_t red = rand(); + uint8_t green = rand(); + uint8_t blue = rand(); + uint8_t alpha = rand(); + + fill_rect(&t->real, tt.picture, tt.format, + 0, 0, 0, + PictOpSrc, x, y, 1, 1, + red, green, blue, alpha); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*tt.width+x] = color(red, green, blue, alpha); + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + uint32_t result; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask = depth_mask(image.depth); + + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int w = 1 + rand() % (tt.width - 1); + int h = 1 + rand() % (tt.height - 1); + uint8_t red = rand(); + uint8_t green = rand(); + uint8_t blue = rand(); + uint8_t alpha = rand(); + + x = rand() % (2*tt.width) - tt.width; + y = rand() % (2*tt.height) - tt.height; + + fill_rect(&t->real, tt.picture, tt.format, + 0, 0, 0, + PictOpSrc, x, y, w, h, + red, green, blue, alpha); + + if (x < 0) + w += x, x = 0; + if (y < 0) + h += y, y = 0; + if (x >= tt.width || y >= tt.height) + continue; + + if (x + w > tt.width) + w = tt.width - x; + if (y + h > tt.height) + h = tt.height - y; + if (w <= 0 || h <= 0) + continue; + + pixman_fill(cells, tt.width, 32, x, y, w, h, + color(red, green, blue, alpha)); + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = *(uint32_t *) + (image.data + + y*image.bytes_per_line + + x*image.bits_per_pixel/8); + if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { + char buf[600]; + uint32_t mask = depth_mask(image.depth); + show_cells(buf, + (uint32_t*)image.data, cells, + x, y, tt.width, tt.height); + + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n%s", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result, buf); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, int reps, int sets, enum target target, int use_window) +{ + struct test_target real, ref; + int r, s; + printf("Testing area fills (%s, using %s source): ", + test_target_name(target), use_window ? "window" : "pixmap"); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x, y, w, h; + int tmpx, tmpy; + uint8_t red = rand(); + uint8_t green = rand(); + uint8_t blue = rand(); + uint8_t alpha = rand(); + int try = 50; + + do { + x = rand() % (real.width - 1); + y = rand() % (real.height - 1); + w = 1 + rand() % (real.width - x - 1); + h = 1 + rand() % (real.height - y - 1); + tmpx = w == real.width ? 0 : rand() % (real.width - w); + tmpy = h == real.height ? 0 : rand() % (real.height - h); + } while (((tmpx+w > x && tmpx < x+w) || + (tmpy+h > y && tmpy < y+h)) && + --try); + + + if (try) { + fill_rect(&t->real, real.picture, real.format, + use_window, tmpx, tmpy, + PictOpSrc, x, y, w, h, + red, green, blue, alpha); + fill_rect(&t->ref, ref.picture, ref.format, + use_window, tmpx, tmpy, + PictOpSrc, x, y, w, h, + red, green, blue, alpha); + } + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} + +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + enum target t; + + if (sets < 2) + sets = 2; + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + pixel_tests(&test, reps, sets, t); + area_tests(&test, reps, sets, t); + rect_tests(&test, reps, sets, t, 0); + if (t != PIXMAP) + rect_tests(&test, reps, sets, t, 1); + } + } + + return 0; +} diff --git a/test/render-fill-copy.c b/test/render-fill-copy.c new file mode 100644 index 00000000..2017e083 --- /dev/null +++ b/test/render-fill-copy.c @@ -0,0 +1,279 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +static const uint8_t ops[] = { + PictOpClear, + PictOpSrc, + PictOpDst, +}; + +static void fill_rect(struct test_display *dpy, + Picture p, + XRenderPictFormat *format, + uint8_t op, int x, int y, int w, int h, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + Display *d = dpy->dpy; + XRenderColor render_color; + Pixmap pixmap1, pixmap2; + Picture tmp1, tmp2; + XRenderPictureAttributes pa; + GC gc; + + render_color.red = red * alpha; + render_color.green = green * alpha; + render_color.blue = blue * alpha; + render_color.alpha = alpha << 8; + + pixmap1 = XCreatePixmap(d, dpy->root, 1, 1, format->depth); + tmp1 = XRenderCreatePicture(d, pixmap1, format, 0, NULL); + + pixmap2 = XCreatePixmap(d, dpy->root, 1, 1, format->depth); + pa.repeat = 1; + tmp2 = XRenderCreatePicture(d, pixmap2, format, CPRepeat, &pa); + + gc = XCreateGC(d, pixmap1, 0, NULL); + + XRenderFillRectangle(d, PictOpSrc, tmp1, &render_color, 0, 0, 1,1); + XCopyArea(d, pixmap1, pixmap2, gc, 0, 0, 1, 1, 0, 0); + XRenderComposite(d, PictOpSrc, tmp2, 0, p, 0, 0, 0, 0, x, y, w,h); + + XFreeGC(d, gc); + + XRenderFreePicture(d, tmp2); + XFreePixmap(d, pixmap2); + + XRenderFreePicture(d, tmp1); + XFreePixmap(d, pixmap1); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + test_target_create_render(&t->real, target, &tt); + + printf("Testing setting of single pixels (%s): ", + test_target_name(target)); + fflush(stdout); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + fill_rect(&t->real, tt.picture, tt.format, + PictOpSrc, x, y, 1, 1, + red, green, blue, alpha); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*tt.width+x] = color(red, green, blue, alpha); + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t result; + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask; + + if (image.depth == 32) + mask = 0xffffffff; + else + mask = (1 << image.depth) - 1; + die("failed to set pixel (%d,%d) to %08x, found %08x instead\n", + x, y, + cells[y*tt.width+x] & mask, + result & mask); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int w = rand() % tt.width; + int h = rand() % tt.height; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + x = rand() % (2*tt.width) - tt.width; + y = rand() % (2*tt.height) - tt.height; + + fill_rect(&t->real, tt.picture, tt.format, + PictOpSrc, x, y, w, h, + red, green, blue, alpha); + + if (x < 0) + w += x, x = 0; + if (y < 0) + h += y, y = 0; + if (x >= tt.width || y >= tt.height) + continue; + + if (x + w > tt.width) + w = tt.width - x; + if (y + h > tt.height) + h = tt.height - y; + if (w <= 0 || h <= 0) + continue; + + pixman_fill(cells, tt.width, 32, x, y, w, h, + color(red, green, blue, alpha)); + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = + *(uint32_t *)(image.data + + y*image.bytes_per_line + + image.bits_per_pixel*x/8); + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask; + + if (image.depth == 32) + mask = 0xffffffff; + else + mask = (1 << image.depth) - 1; + die("failed to set pixel (%d,%d) to %08x, found %08x instead\n", + x, y, + cells[y*tt.width+x] & mask, + result & mask); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target real, ref; + int r, s; + + printf("Testing area fills (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (2*real.width) - real.width; + int y = rand() % (2*real.height) - real.height; + int w = rand() % real.width; + int h = rand() % real.height; + int op = ops[rand() % sizeof(ops)]; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + fill_rect(&t->real, real.picture, real.format, + op, x, y, w, h, + red, green, blue, alpha); + fill_rect(&t->ref, ref.picture, ref.format, + op, x, y, w, h, + red, green, blue, alpha); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} + +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + enum target t; + + if (sets < 2) + sets = 2; + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + pixel_tests(&test, reps, sets, t); + area_tests(&test, reps, sets, t); + rect_tests(&test, reps, sets, t); + } + } + + return 0; +} diff --git a/test/render-fill.c b/test/render-fill.c new file mode 100644 index 00000000..709c2175 --- /dev/null +++ b/test/render-fill.c @@ -0,0 +1,247 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +static const uint8_t ops[] = { + PictOpClear, + PictOpSrc, + PictOpDst, +}; + +static void fill_rect(struct test_display *dpy, Picture p, uint8_t op, + int x, int y, int w, int h, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + XRenderColor render_color; + + render_color.red = red * alpha; + render_color.green = green * alpha; + render_color.blue = blue * alpha; + render_color.alpha = alpha << 8; + + XRenderFillRectangle(dpy->dpy, op, p, &render_color, x, y, w,h); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + test_target_create_render(&t->real, target, &tt); + + printf("Testing setting of single pixels (%s): ", + test_target_name(target)); + fflush(stdout); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + fill_rect(&t->real, tt.picture, PictOpSrc, + x, y, 1, 1, + red, green, blue, alpha); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*tt.width+x] = color(red, green, blue, alpha); + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t result; + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask = depth_mask(image.depth); + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int w = rand() % tt.width; + int h = rand() % tt.height; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + x = rand() % (2*tt.width) - tt.width; + y = rand() % (2*tt.height) - tt.height; + + fill_rect(&t->real, tt.picture, PictOpSrc, + x, y, w, h, red, green, blue, alpha); + + if (x < 0) + w += x, x = 0; + if (y < 0) + h += y, y = 0; + if (x >= tt.width || y >= tt.height) + continue; + + if (x + w > tt.width) + w = tt.width - x; + if (y + h > tt.height) + h = tt.height - y; + if (w <= 0 || h <= 0) + continue; + + pixman_fill(cells, tt.width, 32, x, y, w, h, + color(red, green, blue, alpha)); + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = + *(uint32_t *)(image.data + + y*image.bytes_per_line + + image.bits_per_pixel*x/8); + if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { + uint32_t mask; + if (image.depth == 32) + mask = 0xffffffff; + else + mask = (1 << image.depth) - 1; + die("failed to set pixel (%d,%d) to %08x[%08x], found %08x instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target real, ref; + int r, s; + + printf("Testing area fills (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (2*real.width) - real.width; + int y = rand() % (2*real.height) - real.height; + int w = rand() % real.width; + int h = rand() % real.height; + int op = ops[rand() % sizeof(ops)]; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + fill_rect(&t->real, real.picture, + op, x, y, w, h, + red, green, blue, alpha); + fill_rect(&t->ref, ref.picture, + op, x, y, w, h, + red, green, blue, alpha); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} + +int main(int argc, char **argv) +{ + struct test test; + int i; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + enum target t; + + if (sets < 2) + sets = 2; + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + pixel_tests(&test, reps, sets, t); + area_tests(&test, reps, sets, t); + rect_tests(&test, reps, sets, t); + } + } + + return 0; +} diff --git a/test/render-trapezoid-image.c b/test/render-trapezoid-image.c new file mode 100644 index 00000000..4f6ddd78 --- /dev/null +++ b/test/render-trapezoid-image.c @@ -0,0 +1,615 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +enum trapezoid { + RECT_ALIGN, + RECT_UNALIGN, + GENERAL +}; + +static const uint8_t ops[] = { + PictOpClear, + PictOpSrc, + PictOpDst, +}; + +static XRenderPictFormat *mask_format(Display *dpy, enum mask mask) +{ + switch (mask) { + default: + case MASK_NONE: + case MASK_NONE_AA: + return NULL; + case MASK_A1: + return XRenderFindStandardFormat(dpy, PictStandardA1); + case MASK_A8: + return XRenderFindStandardFormat(dpy, PictStandardA8); + } +} + +static const char *mask_name(enum mask mask) +{ + switch (mask) { + default: + case MASK_NONE: return "none"; + case MASK_NONE_AA: return "none/aa"; + case MASK_A1: return "a1"; + case MASK_A8: return "a8"; + } +} + +static const char *trapezoid_name(enum trapezoid trapezoid) +{ + switch (trapezoid) { + default: + case RECT_ALIGN: return "pixel-aligned"; + case RECT_UNALIGN: return "rectilinear"; + case GENERAL: return "general"; + } +} + +static void +show_cells(char *buf, + const uint32_t *real, const uint32_t *ref, + int x, int y, int w, int h) +{ + int i, j, len = 0; + + for (j = y - 2; j <= y + 2; j++) { + if (j < 0 || j >= h) + continue; + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", real[j*w+i]); + } + + len += sprintf(buf+len, "\t"); + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, "%08x ", ref[j*w+i]); + } + + len += sprintf(buf+len, "\n"); + } +} + + +static void fill_rect(struct test_display *t, Picture p, XRenderPictFormat *format, + uint8_t op, int x, int y, int w, int h, + int dx, int dy, enum mask mask, + int use_window, int tx, int ty, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + XRenderColor color; + XTrapezoid trap; + Drawable tmp; + Picture src; + int w1 = w + (dx!=0); + int h1 = h + (dy!=0); + + if (use_window) { + XSetWindowAttributes attr; + + attr.override_redirect = 1; + tmp = XCreateWindow(t->dpy, DefaultRootWindow(t->dpy), + tx, ty, + w1, h1, + 0, format->depth, + InputOutput, + DefaultVisual(t->dpy, + DefaultScreen(t->dpy)), + CWOverrideRedirect, &attr); + XMapWindow(t->dpy, tmp); + } else + tmp = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy), + w1, h1, format->depth); + + src = XRenderCreatePicture(t->dpy, tmp, format, 0, NULL); + color.red = red * alpha; + color.green = green * alpha; + color.blue = blue * alpha; + color.alpha = alpha << 8 | alpha; + XRenderFillRectangle(t->dpy, PictOpSrc, src, &color, 0, 0, w1, h1); + + trap.left.p1.x = trap.left.p2.x = (x << 16) + dx; + trap.top = trap.left.p1.y = trap.right.p1.y = (y << 16) + dy; + trap.right.p1.x = trap.right.p2.x = ((x + w) << 16) + dx; + trap.bottom = trap.left.p2.y = trap.right.p2.y = ((y + h) << 16) + dy; + + XRenderCompositeTrapezoids(t->dpy, + op, src, p, mask_format(t->dpy, mask), + 0, 0, &trap, 1); + + XRenderFreePicture(t->dpy, src); + if (use_window) + XDestroyWindow(t->dpy, tmp); + else + XFreePixmap(t->dpy, tmp); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target, int use_window) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + printf("Testing setting of single pixels (%s using %s): ", + test_target_name(target), + use_window ? "window" : "pixmap"); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + int tx, ty; + + do { + tx = rand() % (tt.width - 1); + ty = rand() % (tt.height - 1); + } while (tx == x && ty == y); + + fill_rect(&t->real, tt.picture, + use_window ? t->real.format : tt.format, + PictOpSrc, x, y, 1, 1, + 0, 0, MASK_NONE, + use_window, tx, ty, + red, green, blue, alpha); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*t->real.width+x] = color(red, green, blue, alpha); + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t result; + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask = depth_mask(image.depth); + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void set_mask(struct test_display *t, struct test_target *tt, enum mask mask) +{ + XRenderPictureAttributes pa; + + switch (mask) { + case MASK_NONE: + pa.poly_edge = PolyEdgeSharp; + break; + default: + pa.poly_edge = PolyEdgeSmooth; + break; + } + + XRenderChangePicture(t->dpy, tt->picture, CPPolyEdge, &pa); +} + +static void fill(uint32_t *cells, + int x, int y, + int w, int h, + int max_width, int max_height, + uint32_t pixel) +{ + if (x < 0) + w += x, x = 0; + if (y < 0) + h += y, y = 0; + if (x >= max_width || y >= max_height) + return; + + if (x + w > max_width) + w = max_width - x; + if (y + h > max_height) + h = max_height - y; + if (w <= 0 || h <= 0) + return; + + pixman_fill(cells, max_width, 32, x, y, w, h, pixel); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target, int use_window) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s using %s source): ", + test_target_name(target), + use_window ? "window" : "pixmap"); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + int tx, ty, try = 50; + int w, h; + + x = rand() % (2*tt.width) - tt.width; + y = rand() % (2*tt.height) - tt.height; + if (use_window) { + do { + w = 1 + rand() % (tt.width - 1); + h = 1 + rand() % (tt.height - 1); + + tx = w == tt.width ? 0 : rand() % (tt.width - w); + ty = h == tt.height ? 0 : rand() % (tt.height - h); + } while (((tx+w > x && tx < x+w) && + (ty+h > y && ty < y+h)) && + --try); + + if (!try) + continue; + } else { + w = 1 + rand() % (2*tt.width); + h = 1 + rand() % (2*tt.height); + tx = ty = 0; + } + + fill_rect(&t->real, tt.picture, + use_window ? t->real.format : tt.format, + PictOpSrc, x, y, w, h, + 0, 0, MASK_NONE, + use_window, tx, ty, + red, green, blue, alpha); + + if (use_window) + fill(cells, tx, ty, w, h, tt.width, tt.height, + color(red, green, blue, alpha)); + fill(cells, x, y, w, h, tt.width, tt.height, + color(red, green, blue, alpha)); + + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = + *(uint32_t *)(image.data + + y*image.bytes_per_line + + image.bits_per_pixel*x/8); + if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { + char buf[600]; + uint32_t mask = depth_mask(image.depth); + show_cells(buf, + (uint32_t*)image.data, cells, + x, y, tt.width, tt.height); + + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n%s", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result, buf); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, + int dx, int dy, + enum mask mask, + int reps, int sets, + enum target target, + int use_window) +{ + struct test_target real, ref; + int r, s; + + printf("Testing area fills (offset %dx%d, mask %s) (%s using %s source): ", + dx, dy, mask_name(mask), test_target_name(target), + use_window ? "window" : "pixmap"); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + set_mask(&t->real, &real, mask); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + set_mask(&t->ref, &ref, mask); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x, y, w, h; + int op = ops[rand() % sizeof(ops)]; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + int tx, ty, try = 50; + + do { + x = rand() % (real.width - 1); + y = rand() % (real.height - 1); + w = 1 + rand() % (real.width - x - 1); + h = 1 + rand() % (real.height - y - 1); + tx = w == real.width ? 0 : rand() % (real.width - w); + ty = h == real.height ? 0 : rand() % (real.height - h); + } while (((tx+w > x && tx < x+w) && + (ty+h > y && ty < y+h)) && + --try); + + if (try) { + fill_rect(&t->real, real.picture, + use_window ? t->real.format : real.format, + op, x, y, w, h, + dx, dy, mask, + use_window, tx, ty, + red, green, blue, alpha); + fill_rect(&t->ref, ref.picture, + use_window ? t->ref.format : ref.format, + op, x, y, w, h, + dx, dy, mask, + use_window, tx, ty, + red, green, blue, alpha); + } + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} + +static void random_trapezoid(XTrapezoid *trap, enum trapezoid trapezoid, + int x1, int y1, int x2, int y2) +{ + switch (trapezoid) { + case RECT_ALIGN: + x1 = x1 + rand() % (x2 - x1); + x2 = x1 + rand() % (x2 - x1); + y1 = y1 + rand() % (y2 - y1); + y2 = y1 + rand() % (y2 - y1); + + trap->left.p1.x = trap->left.p2.x = x1 << 16; + trap->top = trap->left.p1.y = trap->right.p1.y = y1 << 16; + trap->right.p1.x = trap->right.p2.x = x2 << 16; + trap->bottom = trap->left.p2.y = trap->right.p2.y = y2 << 16; + break; + + case RECT_UNALIGN: + x1 <<= 16; x2 <<= 16; + y1 <<= 16; y2 <<= 16; + + x1 = x1 + rand() % (x2 - x1); + x2 = x1 + rand() % (x2 - x1); + y1 = y1 + rand() % (y2 - y1); + y2 = y1 + rand() % (y2 - y1); + + trap->left.p1.x = trap->left.p2.x = x1; + trap->top = trap->left.p1.y = trap->right.p1.y = y1; + trap->right.p1.x = trap->right.p2.x = x2; + trap->bottom = trap->left.p2.y = trap->right.p2.y = y2; + break; + + case GENERAL: + x1 <<= 16; x2 <<= 16; + y1 <<= 16; y2 <<= 16; + + trap->top = y1 + rand() % (y2 - y1); + trap->bottom = y1 + rand() % (y2 - y1); + + trap->left.p1.x = x1 + rand() % (x2 - x1); + trap->left.p2.x = x1 + rand() % (x2 - x1); + + trap->right.p1.x = x1 + rand() % (x2 - x1); + trap->right.p2.x = x1 + rand() % (x2 - x1); + break; + } +} + +static void fill_traps(struct test_display *t, Picture p, XRenderPictFormat *format, + uint8_t op, XTrapezoid *traps, int ntraps, enum mask mask, + int srcx, int srcy, int srcw, int srch, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + XRenderColor color; + Drawable tmp; + Picture src; + + tmp = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy), + srcw, srch, format->depth); + + src = XRenderCreatePicture(t->dpy, tmp, format, 0, NULL); + color.red = red * alpha; + color.green = green * alpha; + color.blue = blue * alpha; + color.alpha = alpha << 8 | alpha; + XRenderFillRectangle(t->dpy, PictOpSrc, src, &color, 0, 0, srcw, srch); + + XRenderCompositeTrapezoids(t->dpy, + op, src, p, mask_format(t->dpy, mask), + srcx, srcy, traps, ntraps); + + XRenderFreePicture(t->dpy, src); + XFreePixmap(t->dpy, tmp); +} + +static void trap_tests(struct test *t, + enum mask mask, + enum trapezoid trapezoid, + int reps, int sets, + enum target target) +{ + struct test_target real, ref; + XTrapezoid *traps; + int max_traps = 65536; + int r, s, n; + + traps = malloc(sizeof(*traps) * max_traps); + if (traps == NULL) + return; + + printf("Testing trapezoids (%s with mask %s) (%s): ", + trapezoid_name(trapezoid), + mask_name(mask), + test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + set_mask(&t->real, &real, mask); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + set_mask(&t->ref, &ref, mask); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int op = ops[rand() % sizeof(ops)]; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + int num_traps = rand() % max_traps; + int srcx = rand() % 2*real.width - real.width; + int srcy = rand() % 2*real.height - real.height; + int srcw = rand() % real.width; + int srch = rand() % real.height; + + for (n = 0; n < num_traps; n++) + random_trapezoid(&traps[n], 0, + 0, 0, real.width, real.height); + + + fill_traps(&t->real, real.picture, real.format, + op, traps, num_traps, mask, + srcx, srcy, srcw, srch, + red, green, blue, alpha); + + fill_traps(&t->ref, ref.picture, ref.format, + op, traps, num_traps, mask, + srcx, srcy, srcw, srch, + red, green, blue, alpha); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); + free(traps); +} + +int main(int argc, char **argv) +{ + struct test test; + int i, dx, dy; + enum target target; + enum mask mask; + enum trapezoid trapezoid; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + + if (sets < 2) + sets = 2; + + for (target = TARGET_FIRST; target <= TARGET_LAST; target++) { + pixel_tests(&test, reps, sets, target, 0); + area_tests(&test, reps, sets, target, 0); + for (dy = 0; dy < 1 << 16; dy += 1 << 14) + for (dx = 0; dx < 1 << 16; dx += 1 << 14) + for (mask = MASK_NONE; mask <= MASK_A8; mask++) + rect_tests(&test, dx, dy, mask, reps, sets, target, 0); + if (target != CHILD) { + pixel_tests(&test, reps, sets, target, 1); + area_tests(&test, reps, sets, target, 1); + for (dy = 0; dy < 1 << 16; dy += 1 << 14) + for (dx = 0; dx < 1 << 16; dx += 1 << 14) + for (mask = MASK_NONE; mask <= MASK_A8; mask++) + rect_tests(&test, dx, dy, mask, reps, sets, target, 1); + } + } + + for (target = TARGET_FIRST; target <= TARGET_LAST; target++) + for (trapezoid = RECT_ALIGN; trapezoid <= GENERAL; trapezoid++) + trap_tests(&test, mask, trapezoid, reps, sets, target); + } + + return 0; +} diff --git a/test/render-trapezoid.c b/test/render-trapezoid.c new file mode 100644 index 00000000..13683e1d --- /dev/null +++ b/test/render-trapezoid.c @@ -0,0 +1,434 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +enum trapezoid { + RECT_ALIGN, + RECT_UNALIGN, + GENERAL +}; + +static const uint8_t ops[] = { + PictOpClear, + PictOpSrc, + PictOpDst, +}; + +static XRenderPictFormat *mask_format(Display *dpy, enum mask mask) +{ + switch (mask) { + default: + case MASK_NONE: return NULL; + case MASK_A1: return XRenderFindStandardFormat(dpy, PictStandardA1); + case MASK_A8: return XRenderFindStandardFormat(dpy, PictStandardA8); + } +} + +static const char *mask_name(enum mask mask) +{ + switch (mask) { + default: + case MASK_NONE: return "none"; + case MASK_A1: return "a1"; + case MASK_A8: return "a8"; + } +} + +static const char *trapezoid_name(enum trapezoid trapezoid) +{ + switch (trapezoid) { + default: + case RECT_ALIGN: return "pixel-aligned"; + case RECT_UNALIGN: return "rectilinear"; + case GENERAL: return "general"; + } +} + +static void fill_rect(struct test_display *dpy, Picture p, uint8_t op, + int x, int y, int w, int h, + int dx, int dy, enum mask mask, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + XRenderColor render_color; + XTrapezoid trap; + Picture src; + + render_color.red = red * alpha; + render_color.green = green * alpha; + render_color.blue = blue * alpha; + render_color.alpha = alpha << 8; + + trap.left.p1.x = trap.left.p2.x = (x << 16) + dx; + trap.top = trap.left.p1.y = trap.right.p1.y = (y << 16) + dy; + trap.right.p1.x = trap.right.p2.x = ((x + w) << 16) + dx; + trap.bottom = trap.left.p2.y = trap.right.p2.y = ((y + h) << 16) + dy; + + src = XRenderCreateSolidFill(dpy->dpy, &render_color); + XRenderCompositeTrapezoids(dpy->dpy, + op, src, p, mask_format(dpy->dpy, mask), + 0, 0, &trap, 1); + XRenderFreePicture(dpy->dpy, src); +} + +static void pixel_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = malloc(t->real.width*t->real.height*4); + struct { + uint16_t x, y; + } *pixels = malloc(reps*sizeof(*pixels)); + int r, s; + + printf("Testing setting of single pixels (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (tt.width - 1); + int y = rand() % (tt.height - 1); + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + fill_rect(&t->real, tt.picture, PictOpSrc, + x, y, 1, 1, + 0, 0, MASK_NONE, + red, green, blue, alpha); + + pixels[r].x = x; + pixels[r].y = y; + cells[y*t->real.width+x] = color(red, green, blue, alpha); + } + + test_init_image(&image, &t->real.shm, tt.format, 1, 1); + + for (r = 0; r < reps; r++) { + uint32_t result; + uint32_t x = pixels[r].x; + uint32_t y = pixels[r].y; + + XShmGetImage(t->real.dpy, tt.draw, &image, + x, y, AllPlanes); + + result = *(uint32_t *)image.data; + if (!pixel_equal(image.depth, result, + cells[y*tt.width+x])) { + uint32_t mask = depth_mask(image.depth); + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result); + } + } + } + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + + free(pixels); + free(cells); +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void area_tests(struct test *t, int reps, int sets, enum target target) +{ + struct test_target tt; + XImage image; + uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height); + int r, s, x, y; + + printf("Testing area sets (%s): ", test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &tt); + clear(&t->real, &tt); + + test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int w = rand() % tt.width; + int h = rand() % tt.height; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + x = rand() % (2*tt.width) - tt.width; + y = rand() % (2*tt.height) - tt.height; + + fill_rect(&t->real, tt.picture, PictOpSrc, + x, y, w, h, + 0, 0, MASK_NONE, + red, green, blue, alpha); + + if (x < 0) + w += x, x = 0; + if (y < 0) + h += y, y = 0; + if (x >= tt.width || y >= tt.height) + continue; + + if (x + w > tt.width) + w = tt.width - x; + if (y + h > tt.height) + h = tt.height - y; + if (w <= 0 || h <= 0) + continue; + + pixman_fill(cells, tt.width, 32, x, y, w, h, + color(red, green, blue, alpha)); + } + + XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes); + + for (y = 0; y < tt.height; y++) { + for (x = 0; x < tt.width; x++) { + uint32_t result = + *(uint32_t *)(image.data + + y*image.bytes_per_line + + image.bits_per_pixel*x/8); + if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { + uint32_t mask = depth_mask(image.depth); + + die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", + x, y, + cells[y*tt.width+x] & mask, + cells[y*tt.width+x], + result & mask, + result); + } + } + } + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &tt); + free(cells); +} + +static void rect_tests(struct test *t, + int dx, int dy, + enum mask mask, + int reps, int sets, + enum target target) +{ + struct test_target real, ref; + int r, s; + + printf("Testing area fills (offset %dx%d, mask %s) (%s): ", + dx, dy, mask_name(mask), test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + int x = rand() % (2*real.width) - real.width; + int y = rand() % (2*real.height) - real.height; + int w = rand() % real.width; + int h = rand() % real.height; + int op = ops[rand() % sizeof(ops)]; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + + fill_rect(&t->real, real.picture, op, + x, y, w, h, dx, dy, mask, + red, green, blue, alpha); + fill_rect(&t->ref, ref.picture, op, + x, y, w, h, dx, dy, mask, + red, green, blue, alpha); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); +} + +static void random_trapezoid(XTrapezoid *trap, enum trapezoid trapezoid, + int x1, int y1, int x2, int y2) +{ + switch (trapezoid) { + case RECT_ALIGN: + x1 = x1 + rand() % (x2 - x1); + x2 = x1 + rand() % (x2 - x1); + y1 = y1 + rand() % (y2 - y1); + y2 = y1 + rand() % (y2 - y1); + + trap->left.p1.x = trap->left.p2.x = x1 << 16; + trap->top = trap->left.p1.y = trap->right.p1.y = y1 << 16; + trap->right.p1.x = trap->right.p2.x = x2 << 16; + trap->bottom = trap->left.p2.y = trap->right.p2.y = y2 << 16; + break; + + case RECT_UNALIGN: + x1 <<= 16; x2 <<= 16; + y1 <<= 16; y2 <<= 16; + + x1 = x1 + rand() % (x2 - x1); + x2 = x1 + rand() % (x2 - x1); + y1 = y1 + rand() % (y2 - y1); + y2 = y1 + rand() % (y2 - y1); + + trap->left.p1.x = trap->left.p2.x = x1; + trap->top = trap->left.p1.y = trap->right.p1.y = y1; + trap->right.p1.x = trap->right.p2.x = x2; + trap->bottom = trap->left.p2.y = trap->right.p2.y = y2; + break; + + case GENERAL: + x1 <<= 16; x2 <<= 16; + y1 <<= 16; y2 <<= 16; + + trap->top = y1 + rand() % (y2 - y1); + trap->bottom = y1 + rand() % (y2 - y1); + + trap->left.p1.x = x1 + rand() % (x2 - x1); + trap->left.p2.x = x1 + rand() % (x2 - x1); + + trap->right.p1.x = x1 + rand() % (x2 - x1); + trap->right.p2.x = x1 + rand() % (x2 - x1); + break; + + } +} + +static void trap_tests(struct test *t, + enum mask mask, + enum trapezoid trapezoid, + int reps, int sets, + enum target target) +{ + struct test_target real, ref; + XTrapezoid *traps; + int max_traps = 65536; + int r, s, n; + + traps = malloc(sizeof(*traps) * max_traps); + if (traps == NULL) + return; + + printf("Testing trapezoids (%s with mask %s) (%s): ", + trapezoid_name(trapezoid), + mask_name(mask), + test_target_name(target)); + fflush(stdout); + + test_target_create_render(&t->real, target, &real); + clear(&t->real, &real); + + test_target_create_render(&t->ref, target, &ref); + clear(&t->ref, &ref); + + for (s = 0; s < sets; s++) { + for (r = 0; r < reps; r++) { + XRenderColor render_color; + int op = ops[rand() % sizeof(ops)]; + int red = rand() % 0xff; + int green = rand() % 0xff; + int blue = rand() % 0xff; + int alpha = rand() % 0xff; + int num_traps = rand() % max_traps; + Picture src; + + for (n = 0; n < num_traps; n++) + random_trapezoid(&traps[n], 0, + 0, 0, real.width, real.height); + + render_color.red = red * alpha; + render_color.green = green * alpha; + render_color.blue = blue * alpha; + render_color.alpha = alpha << 8; + + src = XRenderCreateSolidFill(t->real.dpy, + &render_color); + XRenderCompositeTrapezoids(t->real.dpy, + op, src, real.picture, + mask_format(t->real.dpy, mask), + 0, 0, traps, num_traps); + XRenderFreePicture(t->real.dpy, src); + + src = XRenderCreateSolidFill(t->ref.dpy, + &render_color); + XRenderCompositeTrapezoids(t->ref.dpy, + op, src, ref.picture, + mask_format(t->ref.dpy, mask), + 0, 0, traps, num_traps); + XRenderFreePicture(t->ref.dpy, src); + } + + test_compare(t, + real.draw, real.format, + ref.draw, ref.format, + 0, 0, real.width, real.height); + } + + printf("passed [%d iterations x %d]\n", reps, sets); + + test_target_destroy_render(&t->real, &real); + test_target_destroy_render(&t->ref, &ref); + free(traps); +} + +int main(int argc, char **argv) +{ + struct test test; + int i, dx, dy; + enum target target; + enum mask mask; + enum trapezoid trapezoid; + + test_init(&test, argc, argv); + + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { + int reps = 1 << i; + int sets = 1 << (12 - i); + + if (sets < 2) + sets = 2; + + for (target = TARGET_FIRST; target <= TARGET_LAST; target++) { + pixel_tests(&test, reps, sets, target); + area_tests(&test, reps, sets, target); + for (dy = 0; dy < 1 << 16; dy += 1 << 14) + for (dx = 0; dx < 1 << 16; dx += 1 << 14) + for (mask = MASK_NONE; mask <= MASK_A8; mask++) + rect_tests(&test, dx, dy, mask, reps, sets, target); + for (trapezoid = RECT_ALIGN; trapezoid <= GENERAL; trapezoid++) + trap_tests(&test, mask, trapezoid, reps, sets, target); + } + } + + return 0; +} diff --git a/test/test.h b/test/test.h new file mode 100644 index 00000000..b46dbb5d --- /dev/null +++ b/test/test.h @@ -0,0 +1,118 @@ +#ifndef TEST_H +#define TEST_H + +#include <stdint.h> +#include <X11/Xlib.h> +#include <X11/extensions/XShm.h> +#include <X11/extensions/Xrender.h> + +#define DEFAULT_ITERATIONS 20 + +enum target { + ROOT, + CHILD, + PIXMAP, +}; +#define TARGET_FIRST ROOT +#define TARGET_LAST PIXMAP + +enum mask { + MASK_NONE, + MASK_NONE_AA, + MASK_A1, + MASK_A8, +}; + +struct test { + struct test_display { + Display *dpy; + Window root; + XShmSegmentInfo shm; + int max_shm_size; + int width, height; + XRenderPictFormat *format; + } real, ref; +}; + +void die(const char *fmt, ...); + +#define die_unless(expr) do{ if (!(expr)) die("verification failed: %s\n", #expr); } while(0) + +void test_init(struct test *test, int argc, char **argv); + +void test_compare(struct test *real, + Drawable real_draw, XRenderPictFormat *real_format, + Drawable ref_draw, XRenderPictFormat *ref_format, + int x, int y, int w, int h); + +#define MAX_DELTA 3 +int pixel_difference(uint32_t a, uint32_t b); + +static inline int pixel_equal(int depth, uint32_t a, uint32_t b) +{ + uint32_t mask; + + if (depth == 32) + mask = 0xffffffff; + else + mask = (1 << depth) - 1; + + a &= mask; + b &= mask; + + if (a == b) + return 1; + + return pixel_difference(a, b) < MAX_DELTA; +} + +void +test_init_image(XImage *ximage, + XShmSegmentInfo *shm, + XRenderPictFormat *format, + int width, int height); + +const char *test_target_name(enum target target); + +struct test_target { + struct test_display *dpy; + Drawable draw; + GC gc; + XRenderPictFormat *format; + Picture picture; + int width, height; + enum target target; +}; + +void test_target_create_render(struct test_display *dpy, + enum target target, + struct test_target *tt); +void test_target_destroy_render(struct test_display *dpy, + struct test_target *tt); + +static inline uint32_t depth_mask(int depth) +{ + if (depth == 32) + return 0xffffffff; + else + return (1 << depth) - 1; +} + +static inline uint32_t color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + uint16_t ra = red * alpha; + uint16_t ga = green * alpha; + uint16_t ba = blue * alpha; + + return alpha << 24 | ra >> 8 << 16 | ga >> 8 << 8 | ba >> 8; +} + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + +#endif diff --git a/test/test_display.c b/test/test_display.c new file mode 100644 index 00000000..ad3e40bc --- /dev/null +++ b/test/test_display.c @@ -0,0 +1,150 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ipc.h> +#include <sys/shm.h> + +#include "test.h" + +static Window get_root(struct test_display *t) +{ + XSetWindowAttributes attr; + Window w; + + /* Be nasty and install a fullscreen window on top so that we + * can guarantee we do not get clipped by children. + */ + attr.override_redirect = 1; + w= XCreateWindow(t->dpy, DefaultRootWindow(t->dpy), + 0, 0, t->width, t->height, 0, + DefaultDepth(t->dpy, DefaultScreen(t->dpy)), + InputOutput, + DefaultVisual(t->dpy, DefaultScreen(t->dpy)), + CWOverrideRedirect, &attr); + XMapWindow(t->dpy, w); + + return w; +} + +static Display *real_display(int argc, char **argv) +{ + Display *dpy; + const char *name = NULL; + int i; + + for (i = 0; i < argc; i++) { + if (strncmp(argv[i], "-d", 2) == 0) { + if (argv[i][2] == '\0') { + if (i+1 < argc) { + name = argv[i+1]; + i++; + } + } else + name = argv[i] + 2; + } + } + + if (name == NULL) + name = getenv("DISPLAY"); + if (name == NULL) + name = ":0"; /* useful default */ + + dpy = XOpenDisplay(name); + if (dpy == NULL) + die("unable to open real display %s\n", name); + + printf("Opened connection to %s for testing.\n", name); + return dpy; +} + +static Display *ref_display(int width, int height, int depth) +{ + Display *dpy; + char buf[160]; + const char *name; + int try; + + name = getenv("REF_DISPLAY"); + if (name) { + dpy = XOpenDisplay(name); + if (dpy == NULL) + die("unable to open reference display %s\n", name); + + printf("Opened connection to %s for reference.\n", name); + return dpy; + } + + snprintf(buf, sizeof(buf), + "Xvfb -ac -terminate -screen 0 %dx%dx%d :99 >/dev/null 2>&1 &", + width, height, depth); + if (system(buf)) + die("unable to spawn '%s' for reference display\n", buf); + + try = 0; + while (try++ < 1000) { + dpy = XOpenDisplay(":99"); + if (dpy) + break; + usleep(1000); + } + + if (dpy == NULL) + die("unable to open reference display\n"); + + return dpy; +} + +static void shm_setup(struct test_display *d) +{ + int major, minor, has_pixmaps; + int size; + + XShmQueryVersion(d->dpy, &major, &minor, &has_pixmaps); + if (major == 0 && minor == 0) + die("XSHM not supported\n"); + + size = d->width * d->height * 4; + d->max_shm_size = size; + + d->shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600); + if (d->shm.shmid == -1) + die("failed to allocated %d bytes for a shm segment\n", size); + + d->shm.shmaddr = shmat(d->shm.shmid, NULL, 0); + d->shm.readOnly = 0; + XShmAttach(d->dpy, &d->shm); + XSync(d->dpy, 1); +} + +static void default_setup(struct test_display *dpy) +{ + dpy->width = WidthOfScreen(DefaultScreenOfDisplay(dpy->dpy)); + dpy->height = HeightOfScreen(DefaultScreenOfDisplay(dpy->dpy)); + dpy->format = + XRenderFindVisualFormat(dpy->dpy, + DefaultVisual(dpy->dpy, + DefaultScreen(dpy->dpy))); +} + +static void test_get_displays(int argc, char **argv, + struct test_display *real, + struct test_display *ref) +{ + real->dpy = real_display(argc, argv); + default_setup(real); + shm_setup(real); + real->root = get_root(real); + + ref->dpy = ref_display(real->width, real->height, + DefaultDepth(real->dpy, DefaultScreen(real->dpy))); + default_setup(ref); + shm_setup(ref); + ref->root = get_root(ref); +} + +void test_init(struct test *test, int argc, char **argv) +{ + memset(test, 0, sizeof(*test)); + test_get_displays(argc, argv, &test->real, &test->ref); +} diff --git a/test/test_image.c b/test/test_image.c new file mode 100644 index 00000000..a2fdbf0b --- /dev/null +++ b/test/test_image.c @@ -0,0 +1,217 @@ +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "test.h" + +#define MAX_DELTA 3 + +int pixel_difference(uint32_t a, uint32_t b) +{ + int max = 0; + int i; + + for (i = 0; i < 32; i += 8) { + uint8_t ac = (a >> i) & 0xff; + uint8_t bc = (b >> i) & 0xff; + int d; + + if (ac > bc) + d = ac - bc; + else + d = bc - ac; + if (d > max) + max = d; + } + + return max; +} + +static void +show_pixels(char *buf, + const XImage *real, const XImage *ref, + int x, int y, int w, int h) +{ + int i, j, len = 0; + + for (j = y - 2; j <= y + 2; j++) { + if (j < 0 || j >= h) + continue; + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, + "%08x ", + *(uint32_t*)(real->data + + j*real->bytes_per_line + + i*real->bits_per_pixel/8)); + } + + len += sprintf(buf+len, "\t"); + + for (i = x - 2; i <= x + 2; i++) { + if (i < 0 || i >= w) + continue; + + len += sprintf(buf+len, + "%08x ", + *(uint32_t*)(ref->data + + j*real->bytes_per_line + + i*real->bits_per_pixel/8)); + } + + len += sprintf(buf+len, "\n"); + } +} + +static void test_compare_fallback(struct test *t, + Drawable real_draw, XRenderPictFormat *real_format, + Drawable ref_draw, XRenderPictFormat *ref_format, + int x, int y, int w, int h) +{ + XImage *real_image, *ref_image; + char *real, *ref; + char buf[600]; + uint32_t mask; + int i, j; + + die_unless(real_format->depth == ref_format->depth); + + real_image = XGetImage(t->real.dpy, real_draw, + x, y, w, h, + AllPlanes, ZPixmap); + real = real_image->data; + + ref_image = XGetImage(t->ref.dpy, ref_draw, + x, y, w, h, + AllPlanes, ZPixmap); + ref = ref_image->data; + + mask = depth_mask(real_image->depth); + + /* Start with an exact comparison. However, one quicky desires + * a fuzzy comparator to hide hardware inaccuracies... + */ + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + uint32_t a = ((uint32_t *)real)[i] & mask; + uint32_t b = ((uint32_t *)ref)[i] & mask; + if (a != b && pixel_difference(a, b) > MAX_DELTA) { + show_pixels(buf, + real_image, ref_image, + i, j, w, h); + die("discrepancy found at (%d+%d, %d+%d): found %08x, expected %08x (delta: %d)\n%s", + x,i, y,j, a, b, pixel_difference(a, b), buf); + } + } + real += real_image->bytes_per_line; + ref += ref_image->bytes_per_line; + } + + XDestroyImage(real_image); + XDestroyImage(ref_image); +} + +void test_compare(struct test *t, + Drawable real_draw, XRenderPictFormat *real_format, + Drawable ref_draw, XRenderPictFormat *ref_format, + int x, int y, int w, int h) +{ + XImage real_image, ref_image; + Pixmap tmp; + char *real, *ref; + char buf[600]; + uint32_t mask; + int i, j; + XGCValues gcv; + GC gc; + + if (w * h * 4 > t->real.max_shm_size) + return test_compare_fallback(t, + real_draw, real_format, + ref_draw, ref_format, + x, y, w, h); + + test_init_image(&real_image, &t->real.shm, real_format, w, h); + test_init_image(&ref_image, &t->ref.shm, ref_format, w, h); + + gcv.graphics_exposures = 0; + + die_unless(real_image.depth == ref_image.depth); + die_unless(real_image.bits_per_pixel == ref_image.bits_per_pixel); + die_unless(real_image.bits_per_pixel == 32); + + mask = depth_mask(real_image.depth); + + tmp = XCreatePixmap(t->real.dpy, real_draw, w, h, real_image.depth); + gc = XCreateGC(t->real.dpy, tmp, GCGraphicsExposures, &gcv); + XCopyArea(t->real.dpy, real_draw, tmp, gc, x, y, w, h, 0, 0); + XShmGetImage(t->real.dpy, tmp, &real_image, 0, 0, AllPlanes); + XFreeGC(t->real.dpy, gc); + XFreePixmap(t->real.dpy, tmp); + real = real_image.data; + + tmp = XCreatePixmap(t->ref.dpy, ref_draw, w, h, ref_image.depth); + gc = XCreateGC(t->ref.dpy, tmp, GCGraphicsExposures, &gcv); + XCopyArea(t->ref.dpy, ref_draw, tmp, gc, x, y, w, h, 0, 0); + XShmGetImage(t->ref.dpy, tmp, &ref_image, 0, 0, AllPlanes); + XFreeGC(t->ref.dpy, gc); + XFreePixmap(t->ref.dpy, tmp); + ref = ref_image.data; + + /* Start with an exact comparison. However, one quicky desires + * a fuzzy comparator to hide hardware inaccuracies... + */ + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + uint32_t a = ((uint32_t *)real)[i] & mask; + uint32_t b = ((uint32_t *)ref)[i] & mask; + if (a != b && pixel_difference(a, b) > MAX_DELTA) { + show_pixels(buf, + &real_image, &ref_image, + i, j, w, h); + die("discrepancy found at (%d+%d, %d+%d): found %08x, expected %08x (delta: %d)\n%s", + x,i, y,j, a, b, pixel_difference(a, b), buf); + } + } + real += real_image.bytes_per_line; + ref += ref_image.bytes_per_line; + } +} + +static int +_native_byte_order_lsb(void) +{ + int x = 1; + return *((char *) &x) == 1; +} + +void +test_init_image(XImage *ximage, + XShmSegmentInfo *shm, + XRenderPictFormat *format, + int width, int height) +{ + int native_byte_order = _native_byte_order_lsb() ? LSBFirst : MSBFirst; + + ximage->width = width; + ximage->height = height; + ximage->format = ZPixmap; + ximage->data = shm->shmaddr; + ximage->obdata = (void *)shm; + ximage->byte_order = native_byte_order; + ximage->bitmap_unit = 32; + ximage->bitmap_bit_order = native_byte_order; + ximage->bitmap_pad = 32; + ximage->depth = format->depth; + ximage->bytes_per_line = 4*width; + ximage->bits_per_pixel = 32; + ximage->red_mask = 0xff << 16; + ximage->green_mask = 0xff << 8; + ximage->blue_mask = 0xff << 0; + ximage->xoffset = 0; + + XInitImage(ximage); +} diff --git a/test/test_log.c b/test/test_log.c new file mode 100644 index 00000000..55e07e5c --- /dev/null +++ b/test/test_log.c @@ -0,0 +1,17 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "test.h" + +void die(const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); + + exit(1); +} + diff --git a/test/test_render.c b/test/test_render.c new file mode 100644 index 00000000..67889acc --- /dev/null +++ b/test/test_render.c @@ -0,0 +1,149 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ipc.h> +#include <sys/shm.h> + +#include "test.h" + +const char *test_target_name(enum target target) +{ + switch (target) { + default: + case ROOT: return "root"; + case CHILD: return "child"; + case PIXMAP: return "pixmap"; + } +} + +void test_target_create_render(struct test_display *dpy, + enum target target, + struct test_target *tt) +{ + XSetWindowAttributes attr; + XGCValues gcv; + + tt->dpy = dpy; + tt->target = target; + + tt->draw = dpy->root; + tt->format = dpy->format; + tt->width = dpy->width; + tt->height = dpy->height; + + switch (target) { + case ROOT: + break; + + case CHILD: + attr.override_redirect = 1; + tt->width /= 4; + tt->height /= 4; + tt->draw = XCreateWindow(dpy->dpy, tt->draw, + dpy->width/2, dpy->height/2, + tt->width, tt->height, + 0, tt->format->depth, + InputOutput, + DefaultVisual(dpy->dpy, + DefaultScreen(dpy->dpy)), + CWOverrideRedirect, &attr); + XMapWindow(dpy->dpy, tt->draw); + break; + + case PIXMAP: + tt->format = XRenderFindStandardFormat(dpy->dpy, PictStandardARGB32); + tt->draw = XCreatePixmap(dpy->dpy, tt->draw, + dpy->width, dpy->height, + tt->format->depth); + break; + } + + tt->picture = + XRenderCreatePicture(dpy->dpy, tt->draw, tt->format, 0, NULL); + + gcv.graphics_exposures = 0; + tt->gc = XCreateGC(dpy->dpy, tt->draw, GCGraphicsExposures, &gcv); +} + +void test_target_destroy_render(struct test_display *dpy, + struct test_target *tt) +{ + XRenderFreePicture(dpy->dpy, tt->picture); + switch (tt->target) { + case ROOT: + break; + case CHILD: + XDestroyWindow(dpy->dpy, tt->draw); + break; + case PIXMAP: + XFreePixmap(dpy->dpy, tt->draw); + break; + } +} + +#if 0 +static int random_bool(void) +{ + return rand() > RAND_MAX/2; +} + +static Picture create_alpha_map(void) +{ + return 0; +} + +static Pixmap create_clip_mask(void) +{ + return 0; +} + +unsigned int test_render_randomize_picture_attributes(XRenderPictureAttributes *pa) +{ + unsigned int flags = 0; + + memset(pa, 0, sizeof(*pa)); + + if (random_bool()) { + pa->repeat = repeat_modes[rand() % ARRAY_SIZE(repeat_modes)]; + flags |= CPRepeat; + + } + + if (random_bool()) { + pa->alpha_map = create_alpha_map(); + pa->alpha_x_origin = rand() % 1024; + pa->alpha_y_origin = rand() % 1024; + flags |= CPAlphaMap; + } + + if (random_bool()) { + pa->clip_mask = create_clip_mask(); + pa->clip_x_orgin = rand() % 1024; + pa->clip_y_orgin = rand() % 1024; + flags |= CPClipMask; + } + + if (random_bool()) { + pa->subwindow_mode = random_bool(); + flags |= CPSubwindowMode; + } + + if (random_bool()) { + pa->poly_edge = random_bool(); + flags |= CPPolyEdge; + } + + if (random_bool()) { + pa->poly_mode = random_bool(); + flags |= CPPolyMode; + } + + if (random_bool()) { + pa->component_alpha = random_bool(); + flags |= CPComponentAlpha; + } + + return flags; +} +#endif |