summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-04-08 07:17:14 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-06-04 09:19:46 +0100
commitbcef98af561939aa48d9236b2dfa2c5626adf4cb (patch)
tree9d05558947a97595a6fdece968b50eeae45bbfb1 /test
parent340cfb7f5271fd1df4c8948e5c9336f5b69a6e6c (diff)
sna: Introduce a new acceleration model.
The premise is that switching between rings (i.e. the BLT and RENDER rings) on SandyBridge imposes a large latency overhead whilst rendering. The cause is that in order to switch rings, we need to split the batch earlier than is desired and to add serialisation between the rings. Both of which incur large overhead. By switching to using a pure 3D blit engine (ok, not so pure as the BLT engine still has uses for the core drawing model which can not be easily represented without a combinatorial explosion of shaders) we can take advantage of additional efficiencies, such as relative relocations, that have been incorporated into recent hardware advances. However, even older hardware performs better from avoiding the implicit context switches and from the batching efficiency of the 3D pipeline... But this is X, and PolyGlyphBlt still exists and remains in use. So for the operations that are not worth accelerating in hardware, we introduce a shadow buffer mechanism through out and reintroduce pixmap migration. Doing this efficiently is the cornerstone of ensuring that we do exploit the increased potential of recent hardware for running old applications and environments (i.e. so that the latest and greatest chip is actually faster than gen2!) For the curious, sna is SandyBridge's New Acceleration. If you are running older chipsets and welcome the performance increase offered by this patch, then you may choose to call it Snazzy instead. Speedups ======== gen3 firefox-fishtank 1203584.56 (1203842.75 0.01%) -> 85561.71 (125146.44 14.87%): 14.07x speedup gen5 grads-heat-map 3385.42 (3489.73 1.44%) -> 350.29 (350.75 0.18%): 9.66x speedup gen3 xfce4-terminal-a1 4179.02 (4180.09 0.06%) -> 503.90 (531.88 4.48%): 8.29x speedup gen4 grads-heat-map 2458.66 (2826.34 4.64%) -> 348.82 (349.20 0.29%): 7.05x speedup gen3 grads-heat-map 1443.33 (1445.32 0.09%) -> 298.55 (298.76 0.05%): 4.83x speedup gen3 swfdec-youtube 3836.14 (3894.14 0.95%) -> 889.84 (979.56 5.99%): 4.31x speedup gen6 grads-heat-map 742.11 (744.44 0.15%) -> 172.51 (172.93 0.20%): 4.30x speedup gen3 firefox-talos-svg 71740.44 (72370.13 0.59%) -> 21959.29 (21995.09 0.68%): 3.27x speedup gen5 gvim 8045.51 (8071.47 0.17%) -> 2589.38 (3246.78 10.74%): 3.11x speedup gen6 poppler 3800.78 (3817.92 0.24%) -> 1227.36 (1230.12 0.30%): 3.10x speedup gen6 gnome-terminal-vim 9106.84 (9111.56 0.03%) -> 3459.49 (3478.52 0.25%): 2.63x speedup gen5 midori-zoomed 9564.53 (9586.58 0.17%) -> 3677.73 (3837.02 2.02%): 2.60x speedup gen5 gnome-terminal-vim 38167.25 (38215.82 0.08%) -> 14901.09 (14902.28 0.01%): 2.56x speedup gen5 poppler 13575.66 (13605.04 0.16%) -> 5554.27 (5555.84 0.01%): 2.44x speedup gen5 swfdec-giant-steps 8941.61 (8988.72 0.52%) -> 3851.98 (3871.01 0.93%): 2.32x speedup gen5 xfce4-terminal-a1 18956.60 (18986.90 0.07%) -> 8362.75 (8365.70 0.01%): 2.27x speedup gen5 firefox-fishtank 88750.31 (88858.23 0.14%) -> 39164.57 (39835.54 0.80%): 2.27x speedup gen3 midori-zoomed 2392.13 (2397.82 0.14%) -> 1109.96 (1303.10 30.35%): 2.16x speedup gen6 gvim 2510.34 (2513.34 0.20%) -> 1200.76 (1204.30 0.22%): 2.09x speedup gen5 firefox-planet-gnome 40478.16 (40565.68 0.09%) -> 19606.22 (19648.79 0.16%): 2.06x speedup gen5 gnome-system-monitor 10344.47 (10385.62 0.29%) -> 5136.69 (5256.85 1.15%): 2.01x speedup gen3 poppler 2595.23 (2603.10 0.17%) -> 1297.56 (1302.42 0.61%): 2.00x speedup gen6 firefox-talos-gfx 7184.03 (7194.97 0.13%) -> 3806.31 (3811.66 0.06%): 1.89x speedup gen5 evolution 8739.25 (8766.12 0.27%) -> 4817.54 (5050.96 1.54%): 1.81x speedup gen3 evolution 1684.06 (1696.88 0.35%) -> 1004.99 (1008.55 0.85%): 1.68x speedup gen3 gnome-terminal-vim 4285.13 (4287.68 0.04%) -> 2715.97 (3202.17 13.52%): 1.58x speedup gen5 swfdec-youtube 5843.94 (5951.07 0.91%) -> 3810.86 (3826.04 1.32%): 1.53x speedup gen4 poppler 7496.72 (7558.83 0.58%) -> 5125.08 (5247.65 1.44%): 1.46x speedup gen4 gnome-terminal-vim 21126.24 (21292.08 0.85%) -> 14590.25 (15066.33 1.80%): 1.45x speedup gen5 firefox-talos-svg 99873.69 (100300.95 0.37%) -> 70745.66 (70818.86 0.05%): 1.41x speedup gen4 firefox-planet-gnome 28205.10 (28304.45 0.27%) -> 19996.11 (20081.44 0.56%): 1.41x speedup gen5 firefox-talos-gfx 93070.85 (93194.72 0.10%) -> 67687.93 (70374.37 1.30%): 1.37x speedup gen4 evolution 6696.25 (6854.14 0.85%) -> 4958.62 (5027.73 0.85%): 1.35x speedup gen3 swfdec-giant-steps 2538.03 (2539.30 0.04%) -> 1895.71 (2050.62 62.43%): 1.34x speedup gen4 gvim 4356.18 (4422.78 0.70%) -> 3276.31 (3281.69 0.13%): 1.33x speedup gen6 evolution 1242.13 (1245.44 0.72%) -> 953.76 (954.54 0.07%): 1.30x speedup gen6 firefox-planet-gnome 4554.23 (4560.69 0.08%) -> 3758.76 (3768.97 0.28%): 1.21x speedup gen3 firefox-talos-gfx 6264.13 (6284.65 0.30%) -> 5261.56 (5370.87 1.28%): 1.19x speedup gen4 midori-zoomed 4771.13 (4809.90 0.73%) -> 4037.03 (4118.93 0.85%): 1.18x speedup gen6 swfdec-giant-steps 1557.06 (1560.13 0.12%) -> 1336.34 (1341.29 0.32%): 1.17x speedup gen4 firefox-talos-gfx 80767.28 (80986.31 0.17%) -> 69629.08 (69721.71 0.06%): 1.16x speedup gen6 midori-zoomed 1463.70 (1463.76 0.08%) -> 1331.45 (1336.56 0.22%): 1.10x speedup Slowdowns ========= gen6 xfce4-terminal-a1 2030.25 (2036.23 0.25%) -> 2144.60 (2240.31 4.29%): 1.06x slowdown gen4 swfdec-youtube 3580.00 (3597.23 3.92%) -> 3826.90 (3862.24 0.91%): 1.07x slowdown gen4 firefox-talos-svg 66112.25 (66256.51 0.11%) -> 71433.40 (71584.31 0.14%): 1.08x slowdown gen4 gnome-system-monitor 5691.60 (5724.03 0.56%) -> 6707.56 (6747.83 0.33%): 1.18x slowdown gen3 ocitysmap 3494.05 (3502.44 0.20%) -> 4321.99 (4524.42 2.78%): 1.24x slowdown gen4 ocitysmap 3628.42 (3641.66 9.37%) -> 5177.16 (5828.74 8.38%): 1.43x slowdown gen5 ocitysmap 4027.77 (4068.11 0.80%) -> 5748.26 (6282.25 7.38%): 1.43x slowdown gen6 ocitysmap 1401.61 (1402.24 0.40%) -> 2365.74 (2379.14 4.12%): 1.69x slowdown [Note the performance regression for ocitysmap comes from that we now attempt to support rendering to and (more importantly) from large surfaces. By enabling such operations is the only way to one day be faster than purely using the CPU, in the meantime we suffer regression due to the increased migration and aperture thrashing. The other couple of regressions will be eliminated with improved span and shader support, now that the framework for such is in place.] The performance increase for Cairo completely overlooks the other critical aspects of the architecture: World of Padman: gen3 (800x600): 57.5 -> 96.2 gen4 (800x600): 47.8 -> 74.6 gen6 (1366x768): 100.4 -> 140.3 [F15] 144.3 -> 146.4 [drm-intel-next] x11perf (gen6); aa10text: 3.47 -> 14.3 Mglyphs/s [unthrottled!] copywinwin10: 1.66 -> 1.99 Mops/s copywinpix10: 2.28 -> 2.98 Mops/s And we do not have a good measure for how much improvement the reworking of the fallback paths give, except that xterm is now over 4x faster... PS: This depends upon the Xorg patchset "Remove the cacheing of the last scratch PixmapRec" for correct invalidations of scratch Pixmaps (used by the dix to implement SHM operations, used by chromium and gtk+ pixbufs. PPS: ./configure --enable-sna Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
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