1 #include <assert.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <float.h>
5 #include <math.h>
6 #include "utils.h"
7
8 #define MAX_WIDTH 16
9 #define MAX_HEIGHT 16
10 #define MAX_STRIDE 4
11
12 static const pixman_format_code_t formats[] =
13 {
14 PIXMAN_a2r10g10b10,
15 PIXMAN_x2r10g10b10,
16 PIXMAN_a8r8g8b8,
17 PIXMAN_a4r4g4b4,
18 PIXMAN_a2r2g2b2,
19 PIXMAN_r5g6b5,
20 PIXMAN_r3g3b2,
21 };
22
23 static const pixman_op_t operators[] =
24 {
25 PIXMAN_OP_CLEAR,
26 PIXMAN_OP_SRC,
27 PIXMAN_OP_DST,
28 PIXMAN_OP_OVER,
29 PIXMAN_OP_OVER_REVERSE,
30 PIXMAN_OP_IN,
31 PIXMAN_OP_IN_REVERSE,
32 PIXMAN_OP_OUT,
33 PIXMAN_OP_OUT_REVERSE,
34 PIXMAN_OP_ATOP,
35 PIXMAN_OP_ATOP_REVERSE,
36 PIXMAN_OP_XOR,
37 PIXMAN_OP_ADD,
38 PIXMAN_OP_SATURATE,
39
40 PIXMAN_OP_DISJOINT_CLEAR,
41 PIXMAN_OP_DISJOINT_SRC,
42 PIXMAN_OP_DISJOINT_DST,
43 PIXMAN_OP_DISJOINT_OVER,
44 PIXMAN_OP_DISJOINT_OVER_REVERSE,
45 PIXMAN_OP_DISJOINT_IN,
46 PIXMAN_OP_DISJOINT_IN_REVERSE,
47 PIXMAN_OP_DISJOINT_OUT,
48 PIXMAN_OP_DISJOINT_OUT_REVERSE,
49 PIXMAN_OP_DISJOINT_ATOP,
50 PIXMAN_OP_DISJOINT_ATOP_REVERSE,
51 PIXMAN_OP_DISJOINT_XOR,
52
53 PIXMAN_OP_CONJOINT_CLEAR,
54 PIXMAN_OP_CONJOINT_SRC,
55 PIXMAN_OP_CONJOINT_DST,
56 PIXMAN_OP_CONJOINT_OVER,
57 PIXMAN_OP_CONJOINT_OVER_REVERSE,
58 PIXMAN_OP_CONJOINT_IN,
59 PIXMAN_OP_CONJOINT_IN_REVERSE,
60 PIXMAN_OP_CONJOINT_OUT,
61 PIXMAN_OP_CONJOINT_OUT_REVERSE,
62 PIXMAN_OP_CONJOINT_ATOP,
63 PIXMAN_OP_CONJOINT_ATOP_REVERSE,
64 PIXMAN_OP_CONJOINT_XOR,
65
66 PIXMAN_OP_MULTIPLY,
67 PIXMAN_OP_SCREEN,
68 PIXMAN_OP_OVERLAY,
69 PIXMAN_OP_DARKEN,
70 PIXMAN_OP_LIGHTEN,
71 PIXMAN_OP_COLOR_DODGE,
72 PIXMAN_OP_COLOR_BURN,
73 PIXMAN_OP_HARD_LIGHT,
74 PIXMAN_OP_SOFT_LIGHT,
75 PIXMAN_OP_DIFFERENCE,
76 PIXMAN_OP_EXCLUSION,
77 };
78
79 static const pixman_dither_t dithers[] =
80 {
81 PIXMAN_DITHER_ORDERED_BAYER_8,
82 PIXMAN_DITHER_ORDERED_BLUE_NOISE_64,
83 };
84
85 #define RANDOM_ELT(array) \
86 (array[prng_rand_n (ARRAY_LENGTH (array))])
87
88 static void
free_bits(pixman_image_t * image,void * data)89 free_bits (pixman_image_t *image, void *data)
90 {
91 free (image->bits.bits);
92 }
93
94 static pixman_image_t *
create_image(pixman_image_t ** clone)95 create_image (pixman_image_t **clone)
96 {
97 pixman_format_code_t format = RANDOM_ELT (formats);
98 pixman_image_t *image;
99 int width = prng_rand_n (MAX_WIDTH);
100 int height = prng_rand_n (MAX_HEIGHT);
101 int stride = ((width * (PIXMAN_FORMAT_BPP (format) / 8)) + 3) & ~3;
102 uint32_t *bytes = malloc (stride * height);
103
104 prng_randmemset (bytes, stride * height, RANDMEMSET_MORE_00_AND_FF);
105
106 image = pixman_image_create_bits (
107 format, width, height, bytes, stride);
108
109 pixman_image_set_destroy_function (image, free_bits, NULL);
110
111 assert (image);
112
113 if (clone)
114 {
115 uint32_t *bytes_dup = malloc (stride * height);
116
117 memcpy (bytes_dup, bytes, stride * height);
118
119 *clone = pixman_image_create_bits (
120 format, width, height, bytes_dup, stride);
121
122 pixman_image_set_destroy_function (*clone, free_bits, NULL);
123 }
124
125 return image;
126 }
127
128 static pixman_bool_t
access(pixman_image_t * image,int x,int y,uint32_t * pixel)129 access (pixman_image_t *image, int x, int y, uint32_t *pixel)
130 {
131 int bytes_per_pixel;
132 int stride;
133 uint8_t *location;
134
135 if (x < 0 || x >= image->bits.width || y < 0 || y >= image->bits.height)
136 return FALSE;
137
138 bytes_per_pixel = PIXMAN_FORMAT_BPP (image->bits.format) / 8;
139 stride = image->bits.rowstride * 4;
140
141 location = (uint8_t *)image->bits.bits + y * stride + x * bytes_per_pixel;
142
143 if (bytes_per_pixel == 4)
144 *pixel = *(uint32_t *)location;
145 else if (bytes_per_pixel == 2)
146 *pixel = *(uint16_t *)location;
147 else if (bytes_per_pixel == 1)
148 *pixel = *(uint8_t *)location;
149 else
150 assert (0);
151
152 return TRUE;
153 }
154
155 static void
get_color(pixel_checker_t * checker,pixman_image_t * image,int x,int y,color_t * color,uint32_t * pixel)156 get_color (pixel_checker_t *checker,
157 pixman_image_t *image,
158 int x, int y,
159 color_t *color,
160 uint32_t *pixel)
161 {
162 if (!access (image, x, y, pixel))
163 {
164 color->a = 0.0;
165 color->r = 0.0;
166 color->g = 0.0;
167 color->b = 0.0;
168 }
169 else
170 {
171 pixel_checker_convert_pixel_to_color (
172 checker, *pixel, color);
173 }
174 }
175
176 static pixman_bool_t
verify(int test_no,pixman_op_t op,pixman_image_t * source,pixman_image_t * mask,pixman_image_t * dest,pixman_image_t * orig_dest,int x,int y,int width,int height,pixman_bool_t component_alpha,pixman_dither_t dither)177 verify (int test_no,
178 pixman_op_t op,
179 pixman_image_t *source,
180 pixman_image_t *mask,
181 pixman_image_t *dest,
182 pixman_image_t *orig_dest,
183 int x, int y,
184 int width, int height,
185 pixman_bool_t component_alpha,
186 pixman_dither_t dither)
187 {
188 pixel_checker_t dest_checker, src_checker, mask_checker;
189 int i, j;
190
191 pixel_checker_init (&src_checker, source->bits.format);
192 pixel_checker_init (&dest_checker, dest->bits.format);
193 pixel_checker_init (&mask_checker, mask->bits.format);
194
195 if (dest->bits.dither != PIXMAN_DITHER_NONE)
196 pixel_checker_allow_dither (&dest_checker);
197
198 assert (dest->bits.format == orig_dest->bits.format);
199
200 for (j = y; j < y + height; ++j)
201 {
202 for (i = x; i < x + width; ++i)
203 {
204 color_t src_color, mask_color, orig_dest_color, result;
205 uint32_t dest_pixel, orig_dest_pixel, src_pixel, mask_pixel;
206
207 access (dest, i, j, &dest_pixel);
208
209 get_color (&src_checker,
210 source, i - x, j - y,
211 &src_color, &src_pixel);
212
213 get_color (&mask_checker,
214 mask, i - x, j - y,
215 &mask_color, &mask_pixel);
216
217 get_color (&dest_checker,
218 orig_dest, i, j,
219 &orig_dest_color, &orig_dest_pixel);
220
221 do_composite (op,
222 &src_color, &mask_color, &orig_dest_color,
223 &result, component_alpha);
224
225 if (!pixel_checker_check (&dest_checker, dest_pixel, &result))
226 {
227 int a, r, g, b;
228
229 printf ("--------- Test 0x%x failed ---------\n", test_no);
230
231 printf (" operator: %s (%s alpha)\n", operator_name (op),
232 component_alpha? "component" : "unified");
233 printf (" dither: %s\n", dither_name (dither));
234 printf (" dest_x, dest_y: %d %d\n", x, y);
235 printf (" width, height: %d %d\n", width, height);
236 printf (" source: format: %-14s size: %2d x %2d\n",
237 format_name (source->bits.format),
238 source->bits.width, source->bits.height);
239 printf (" mask: format: %-14s size: %2d x %2d\n",
240 format_name (mask->bits.format),
241 mask->bits.width, mask->bits.height);
242 printf (" dest: format: %-14s size: %2d x %2d\n",
243 format_name (dest->bits.format),
244 dest->bits.width, dest->bits.height);
245 printf (" -- Failed pixel: (%d, %d) --\n", i, j);
246 printf (" source ARGB: %f %f %f %f (pixel: %x)\n",
247 src_color.a, src_color.r, src_color.g, src_color.b,
248 src_pixel);
249 printf (" mask ARGB: %f %f %f %f (pixel: %x)\n",
250 mask_color.a, mask_color.r, mask_color.g, mask_color.b,
251 mask_pixel);
252 printf (" dest ARGB: %f %f %f %f (pixel: %x)\n",
253 orig_dest_color.a, orig_dest_color.r, orig_dest_color.g, orig_dest_color.b,
254 orig_dest_pixel);
255 printf (" expected ARGB: %f %f %f %f\n",
256 result.a, result.r, result.g, result.b);
257
258 pixel_checker_get_min (&dest_checker, &result, &a, &r, &g, &b);
259 printf (" min acceptable: %8d %8d %8d %8d\n", a, r, g, b);
260
261 pixel_checker_split_pixel (&dest_checker, dest_pixel, &a, &r, &g, &b);
262 printf (" got: %8d %8d %8d %8d (pixel: %x)\n", a, r, g, b, dest_pixel);
263
264 pixel_checker_get_max (&dest_checker, &result, &a, &r, &g, &b);
265 printf (" max acceptable: %8d %8d %8d %8d\n", a, r, g, b);
266 printf ("\n");
267 printf (" { %s,\n", operator_name (op));
268 printf (" PIXMAN_%s,\t0x%x,\n", format_name (source->bits.format), src_pixel);
269 printf (" PIXMAN_%s,\t0x%x,\n", format_name (mask->bits.format), mask_pixel);
270 printf (" PIXMAN_%s,\t0x%x\n", format_name (dest->bits.format), orig_dest_pixel);
271 printf (" },\n");
272 return FALSE;
273 }
274 }
275 }
276
277 return TRUE;
278 }
279
280 static pixman_bool_t
do_check(int i)281 do_check (int i)
282 {
283 pixman_image_t *source, *dest, *mask;
284 pixman_op_t op;
285 int x, y, width, height;
286 pixman_image_t *dest_copy;
287 pixman_bool_t result = TRUE;
288 pixman_bool_t component_alpha;
289 pixman_dither_t dither = PIXMAN_DITHER_NONE;
290
291 prng_srand (i);
292 op = RANDOM_ELT (operators);
293 x = prng_rand_n (MAX_WIDTH);
294 y = prng_rand_n (MAX_HEIGHT);
295 width = prng_rand_n (MAX_WIDTH) + 4;
296 height = prng_rand_n (MAX_HEIGHT) + 4;
297
298 source = create_image (NULL);
299 mask = create_image (NULL);
300 dest = create_image (&dest_copy);
301
302 if (x >= dest->bits.width)
303 x = dest->bits.width / 2;
304 if (y >= dest->bits.height)
305 y = dest->bits.height / 2;
306 if (x + width > dest->bits.width)
307 width = dest->bits.width - x;
308 if (y + height > dest->bits.height)
309 height = dest->bits.height - y;
310
311 if (prng_rand_n (2))
312 {
313 dither = RANDOM_ELT (dithers);
314 pixman_image_set_dither (dest, dither);
315 }
316
317 component_alpha = prng_rand_n (2);
318
319 pixman_image_set_component_alpha (mask, component_alpha);
320
321 pixman_image_composite32 (op, source, mask, dest,
322 0, 0, 0, 0,
323 x, y, width, height);
324
325 if (!verify (i, op, source, mask, dest, dest_copy,
326 x, y, width, height, component_alpha,
327 dither))
328 {
329 result = FALSE;
330 }
331
332 pixman_image_unref (source);
333 pixman_image_unref (mask);
334 pixman_image_unref (dest);
335 pixman_image_unref (dest_copy);
336
337 return result;
338 }
339
340 #define N_TESTS 10000000
341
342 int
main(int argc,const char * argv[])343 main (int argc, const char *argv[])
344 {
345 int i;
346 int result = 0;
347
348 if (argc == 2)
349 {
350 if (strcmp (argv[1], "--forever") == 0)
351 {
352 uint32_t n;
353
354 prng_srand (time (0));
355
356 n = prng_rand();
357
358 for (;;)
359 do_check (n++);
360 }
361 else
362 {
363 do_check (strtol (argv[1], NULL, 0));
364 }
365 }
366 else
367 {
368 #ifdef USE_OPENMP
369 # pragma omp parallel for default(none) reduction(|:result)
370 #endif
371 for (i = 0; i < N_TESTS; ++i)
372 {
373 if (!do_check (i))
374 result |= 1;
375 }
376 }
377
378 return result;
379 }
380