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