1#include <stdint.h>
2#include <stdio.h>
3#include <stdlib.h>
4
5#include <X11/Xutil.h> /* for XDestroyImage */
6#include <pixman.h> /* for pixman blt functions */
7
8#include "test.h"
9
10static void
11show_cells(char *buf,
12	   const uint32_t *out, const uint32_t *ref,
13	   int x, int y, int w, int h)
14{
15	int i, j, len = 0;
16
17	for (j = y - 2; j <= y + 2; j++) {
18		if (j < 0 || j >= h)
19			continue;
20
21		for (i = x - 2; i <= x + 2; i++) {
22			if (i < 0 || i >= w)
23				continue;
24
25			len += sprintf(buf+len, "%08x ", out[j*w+i]);
26		}
27
28		len += sprintf(buf+len, "\t");
29
30		for (i = x - 2; i <= x + 2; i++) {
31			if (i < 0 || i >= w)
32				continue;
33
34			len += sprintf(buf+len, "%08x ", ref[j*w+i]);
35		}
36
37		len += sprintf(buf+len, "\n");
38	}
39}
40
41static void fill_rect(struct test_display *t, Drawable d, uint8_t alu,
42		      int x, int y, int w, int h, uint32_t fg)
43{
44	XGCValues val;
45	GC gc;
46
47	val.function = alu;
48	val.foreground = fg;
49
50	gc = XCreateGC(t->dpy, d, GCForeground | GCFunction, &val);
51	XFillRectangle(t->dpy, d, gc, x, y, w, h);
52	XFreeGC(t->dpy, gc);
53}
54
55static void pixel_tests(struct test *t, int reps, int sets, enum target target)
56{
57	struct test_target tt;
58	XImage image;
59	uint32_t *cells = malloc(t->out.width*t->out.height*4);
60	struct {
61		uint16_t x, y;
62	} *pixels = malloc(reps*sizeof(*pixels));
63	int r, s;
64
65	test_target_create_render(&t->out, target, &tt);
66
67	printf("Testing setting of single pixels (%s): ",
68	       test_target_name(target));
69	fflush(stdout);
70
71	for (s = 0; s < sets; s++) {
72		for (r = 0; r < reps; r++) {
73			int x = rand() % (tt.width - 1);
74			int y = rand() % (tt.height - 1);
75			uint32_t fg = rand();
76
77			fill_rect(&t->out, tt.draw, GXcopy,
78				  x, y, 1, 1, fg);
79
80			pixels[r].x = x;
81			pixels[r].y = y;
82			cells[y*tt.width+x] = fg;
83		}
84
85		test_init_image(&image, &t->out.shm, tt.format, 1, 1);
86
87		for (r = 0; r < reps; r++) {
88			uint32_t x = pixels[r].x;
89			uint32_t y = pixels[r].y;
90			uint32_t result;
91
92			XShmGetImage(t->out.dpy, tt.draw, &image,
93				     x, y, AllPlanes);
94
95			result = *(uint32_t *)image.data;
96			if (!pixel_equal(image.depth, result,
97					 cells[y*tt.width+x])) {
98				uint32_t mask = depth_mask(image.depth);
99
100				die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n",
101				    x, y,
102				    cells[y*tt.width+x] & mask,
103				    cells[y*tt.width+x],
104				    result & mask,
105				    result);
106			}
107		}
108	}
109	printf("passed [%d iterations x %d]\n", reps, sets);
110
111	test_target_destroy_render(&t->out, &tt);
112	free(pixels);
113	free(cells);
114}
115
116static void clear(struct test_display *dpy, struct test_target *tt)
117{
118	XRenderColor render_color = {0};
119	XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
120			     0, 0, tt->width, tt->height);
121}
122
123static void area_tests(struct test *t, int reps, int sets, enum target target)
124{
125	struct test_target tt;
126	XImage image;
127	uint32_t *cells = calloc(sizeof(uint32_t), t->out.width*t->out.height);
128	int r, s, x, y;
129
130	printf("Testing area sets (%s): ", test_target_name(target));
131	fflush(stdout);
132
133	test_target_create_render(&t->out, target, &tt);
134	clear(&t->out, &tt);
135
136	test_init_image(&image, &t->out.shm, tt.format, tt.width, tt.height);
137
138	for (s = 0; s < sets; s++) {
139		for (r = 0; r < reps; r++) {
140			int w = rand() % tt.width;
141			int h = rand() % tt.height;
142			uint32_t fg = rand();
143
144			x = rand() % (2*tt.width) - tt.width;
145			y = rand() % (2*tt.height) - tt.height;
146
147			fill_rect(&t->out, tt.draw, GXcopy,
148				  x, y, w, h, fg);
149
150			if (x < 0)
151				w += x, x = 0;
152			if (y < 0)
153				h += y, y = 0;
154			if (x >= tt.width || y >= tt.height)
155				continue;
156
157			if (x + w > tt.width)
158				w = tt.width - x;
159			if (y + h > tt.height)
160				h = tt.height - y;
161			if (w <= 0 || h <= 0)
162				continue;
163
164			pixman_fill(cells, tt.width, 32, x, y, w, h, fg);
165		}
166
167		XShmGetImage(t->out.dpy, tt.draw, &image, 0, 0, AllPlanes);
168
169		for (y = 0; y < tt.height; y++) {
170			for (x = 0; x < tt.width; x++) {
171				uint32_t result = *(uint32_t *)
172					(image.data +
173					 y*image.bytes_per_line +
174					 x*image.bits_per_pixel/8);
175				if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) {
176					char buf[600];
177					uint32_t mask = depth_mask(image.depth);
178					show_cells(buf,
179						   (uint32_t*)image.data, cells,
180						   x, y, tt.width, tt.height);
181
182					die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n%s",
183					    x, y,
184					    cells[y*tt.width+x] & mask,
185					    cells[y*tt.width+x],
186					    result & mask,
187					    result, buf);
188				}
189			}
190		}
191	}
192
193	printf("passed [%d iterations x %d]\n", reps, sets);
194
195	test_target_destroy_render(&t->out, &tt);
196	free(cells);
197}
198
199static void rect_tests(struct test *t, int reps, int sets, enum target target)
200{
201	struct test_target out, ref;
202	int r, s;
203
204	printf("Testing area fills (%s): ", test_target_name(target));
205	fflush(stdout);
206
207	test_target_create_render(&t->out, target, &out);
208	clear(&t->out, &out);
209
210	test_target_create_render(&t->ref, target, &ref);
211	clear(&t->ref, &ref);
212
213	for (s = 0; s < sets; s++) {
214		for (r = 0; r < reps; r++) {
215			int x = rand() % (2*out.width) - out.width;
216			int y = rand() % (2*out.height) - out.height;
217			int w = rand() % (2*out.width);
218			int h = rand() % (2*out.height);
219			uint8_t alu = rand() % (GXset + 1);
220			uint32_t fg = rand();
221
222			fill_rect(&t->out, out.draw, alu,
223				  x, y, w, h, fg);
224			fill_rect(&t->ref, ref.draw, alu,
225				  x, y, w, h, fg);
226		}
227
228		test_compare(t,
229			     out.draw, out.format,
230			     ref.draw, ref.format,
231			     0, 0, out.width, out.height,
232			     "");
233	}
234
235	printf("passed [%d iterations x %d]\n", reps, sets);
236
237	test_target_destroy_render(&t->out, &out);
238	test_target_destroy_render(&t->ref, &ref);
239}
240
241int main(int argc, char **argv)
242{
243	struct test test;
244	int i;
245
246	test_init(&test, argc, argv);
247
248	for (i = 0; i <= DEFAULT_ITERATIONS; i++) {
249		int reps = REPS(i), sets = SETS(i);
250		enum target t;
251
252		for (t = TARGET_FIRST; t <= TARGET_LAST; t++) {
253			pixel_tests(&test, reps, sets, t);
254			area_tests(&test, reps, sets, t);
255			rect_tests(&test, reps, sets, t);
256		}
257	}
258
259	return 0;
260}
261