summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/.gitignore13
-rw-r--r--test/Makefile.am30
-rw-r--r--test/README3
-rw-r--r--test/basic-copyarea-size.c102
-rw-r--r--test/basic-copyarea.c301
-rw-r--r--test/basic-fillrect.c263
-rw-r--r--test/basic-putimage.c283
-rw-r--r--test/basic-stress.c155
-rw-r--r--test/mixed-stress.c208
-rw-r--r--test/render-composite-solid.c255
-rw-r--r--test/render-copyarea-size.c115
-rw-r--r--test/render-copyarea.c324
-rw-r--r--test/render-fill-copy.c279
-rw-r--r--test/render-fill.c247
-rw-r--r--test/render-trapezoid-image.c615
-rw-r--r--test/render-trapezoid.c434
-rw-r--r--test/test.h118
-rw-r--r--test/test_display.c150
-rw-r--r--test/test_image.c217
-rw-r--r--test/test_log.c17
-rw-r--r--test/test_render.c149
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