1 /*
2 * Copyright © 2005 Eric Anholt
3 * Copyright © 2009 Chris Wilson
4 * Copyright © 2010 Soeren Sandmann
5 * Copyright © 2010 Red Hat, Inc.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of Eric Anholt not be used in
12 * advertising or publicity pertaining to distribution of the software without
13 * specific, written prior permission. Eric Anholt makes no
14 * representations about the suitability of this software for any purpose. It
15 * is provided "as is" without express or implied warranty.
16 *
17 * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 */
25 #include <stdio.h>
26 #include <stdlib.h> /* abort() */
27 #include <math.h>
28 #include <time.h>
29 #include "utils.h"
30
31 typedef struct image_t image_t;
32
33 static const color_t colors[] =
34 {
35 { 1.0, 1.0, 1.0, 1.0 },
36 { 1.0, 1.0, 1.0, 0.0 },
37 { 0.0, 0.0, 0.0, 1.0 },
38 { 0.0, 0.0, 0.0, 0.0 },
39 { 1.0, 0.0, 0.0, 1.0 },
40 { 0.0, 1.0, 0.0, 1.0 },
41 { 0.0, 0.0, 1.0, 1.0 },
42 { 0.5, 0.0, 0.0, 0.5 },
43 };
44
45 static uint16_t
_color_double_to_short(double d)46 _color_double_to_short (double d)
47 {
48 uint32_t i;
49
50 i = (uint32_t) (d * 65536);
51 i -= (i >> 16);
52
53 return i;
54 }
55
56 static void
compute_pixman_color(const color_t * color,pixman_color_t * out)57 compute_pixman_color (const color_t *color,
58 pixman_color_t *out)
59 {
60 out->red = _color_double_to_short (color->r);
61 out->green = _color_double_to_short (color->g);
62 out->blue = _color_double_to_short (color->b);
63 out->alpha = _color_double_to_short (color->a);
64 }
65
66 #define REPEAT 0x01000000
67 #define FLAGS 0xff000000
68
69 static const int sizes[] =
70 {
71 0,
72 1,
73 1 | REPEAT,
74 10
75 };
76
77 static const pixman_format_code_t formats[] =
78 {
79 /* 32 bpp formats */
80 PIXMAN_a8r8g8b8,
81 PIXMAN_x8r8g8b8,
82 PIXMAN_a8b8g8r8,
83 PIXMAN_x8b8g8r8,
84 PIXMAN_b8g8r8a8,
85 PIXMAN_b8g8r8x8,
86 PIXMAN_r8g8b8a8,
87 PIXMAN_r8g8b8x8,
88 PIXMAN_x2r10g10b10,
89 PIXMAN_x2b10g10r10,
90 PIXMAN_a2r10g10b10,
91 PIXMAN_a2b10g10r10,
92
93 /* sRGB formats */
94 PIXMAN_a8r8g8b8_sRGB,
95
96 /* 24 bpp formats */
97 PIXMAN_r8g8b8,
98 PIXMAN_b8g8r8,
99 PIXMAN_r5g6b5,
100 PIXMAN_b5g6r5,
101
102 /* 16 bpp formats */
103 PIXMAN_x1r5g5b5,
104 PIXMAN_x1b5g5r5,
105 PIXMAN_a1r5g5b5,
106 PIXMAN_a1b5g5r5,
107 PIXMAN_a4b4g4r4,
108 PIXMAN_x4b4g4r4,
109 PIXMAN_a4r4g4b4,
110 PIXMAN_x4r4g4b4,
111
112 /* 8 bpp formats */
113 PIXMAN_a8,
114 PIXMAN_r3g3b2,
115 PIXMAN_b2g3r3,
116 PIXMAN_a2r2g2b2,
117 PIXMAN_a2b2g2r2,
118 PIXMAN_x4a4,
119
120 /* 4 bpp formats */
121 PIXMAN_a4,
122 PIXMAN_r1g2b1,
123 PIXMAN_b1g2r1,
124 PIXMAN_a1r1g1b1,
125 PIXMAN_a1b1g1r1,
126
127 /* 1 bpp formats */
128 PIXMAN_a1,
129 };
130
131 struct image_t
132 {
133 pixman_image_t *image;
134 pixman_format_code_t format;
135 const color_t *color;
136 pixman_repeat_t repeat;
137 int size;
138 };
139
140 static const pixman_op_t operators[] =
141 {
142 PIXMAN_OP_CLEAR,
143 PIXMAN_OP_SRC,
144 PIXMAN_OP_DST,
145 PIXMAN_OP_OVER,
146 PIXMAN_OP_OVER_REVERSE,
147 PIXMAN_OP_IN,
148 PIXMAN_OP_IN_REVERSE,
149 PIXMAN_OP_OUT,
150 PIXMAN_OP_OUT_REVERSE,
151 PIXMAN_OP_ATOP,
152 PIXMAN_OP_ATOP_REVERSE,
153 PIXMAN_OP_XOR,
154 PIXMAN_OP_ADD,
155 PIXMAN_OP_SATURATE,
156
157 PIXMAN_OP_DISJOINT_CLEAR,
158 PIXMAN_OP_DISJOINT_SRC,
159 PIXMAN_OP_DISJOINT_DST,
160 PIXMAN_OP_DISJOINT_OVER,
161 PIXMAN_OP_DISJOINT_OVER_REVERSE,
162 PIXMAN_OP_DISJOINT_IN,
163 PIXMAN_OP_DISJOINT_IN_REVERSE,
164 PIXMAN_OP_DISJOINT_OUT,
165 PIXMAN_OP_DISJOINT_OUT_REVERSE,
166 PIXMAN_OP_DISJOINT_ATOP,
167 PIXMAN_OP_DISJOINT_ATOP_REVERSE,
168 PIXMAN_OP_DISJOINT_XOR,
169
170 PIXMAN_OP_CONJOINT_CLEAR,
171 PIXMAN_OP_CONJOINT_SRC,
172 PIXMAN_OP_CONJOINT_DST,
173 PIXMAN_OP_CONJOINT_OVER,
174 PIXMAN_OP_CONJOINT_OVER_REVERSE,
175 PIXMAN_OP_CONJOINT_IN,
176 PIXMAN_OP_CONJOINT_IN_REVERSE,
177 PIXMAN_OP_CONJOINT_OUT,
178 PIXMAN_OP_CONJOINT_OUT_REVERSE,
179 PIXMAN_OP_CONJOINT_ATOP,
180 PIXMAN_OP_CONJOINT_ATOP_REVERSE,
181 PIXMAN_OP_CONJOINT_XOR,
182 };
183
184 static uint32_t
get_value(pixman_image_t * image)185 get_value (pixman_image_t *image)
186 {
187 uint32_t value = *(uint32_t *)pixman_image_get_data (image);
188
189 #ifdef WORDS_BIGENDIAN
190 {
191 pixman_format_code_t format = pixman_image_get_format (image);
192 value >>= 8 * sizeof(value) - PIXMAN_FORMAT_BPP (format);
193 }
194 #endif
195
196 return value;
197 }
198
199 static char *
describe_image(image_t * info,char * buf)200 describe_image (image_t *info, char *buf)
201 {
202 if (info->size)
203 {
204 sprintf (buf, "%s, %dx%d%s",
205 format_name (info->format),
206 info->size, info->size,
207 info->repeat ? " R" :"");
208 }
209 else
210 {
211 sprintf (buf, "solid");
212 }
213
214 return buf;
215 }
216
217 static char *
describe_color(const color_t * color,char * buf)218 describe_color (const color_t *color, char *buf)
219 {
220 sprintf (buf, "%.3f %.3f %.3f %.3f",
221 color->r, color->g, color->b, color->a);
222
223 return buf;
224 }
225
226 static pixman_bool_t
composite_test(image_t * dst,pixman_op_t op,image_t * src,image_t * mask,pixman_bool_t component_alpha,int testno)227 composite_test (image_t *dst,
228 pixman_op_t op,
229 image_t *src,
230 image_t *mask,
231 pixman_bool_t component_alpha,
232 int testno)
233 {
234 color_t expected, tdst, tsrc, tmsk;
235 pixel_checker_t checker;
236
237 if (mask)
238 {
239 pixman_image_set_component_alpha (mask->image, component_alpha);
240
241 pixman_image_composite (op, src->image, mask->image, dst->image,
242 0, 0, 0, 0, 0, 0, dst->size, dst->size);
243 }
244 else
245 {
246 pixman_image_composite (op, src->image, NULL, dst->image,
247 0, 0,
248 0, 0,
249 0, 0,
250 dst->size, dst->size);
251 }
252
253 tdst = *dst->color;
254 tsrc = *src->color;
255
256 if (mask)
257 {
258 tmsk = *mask->color;
259 }
260
261 /* It turns out that by construction all source, mask etc. colors are
262 * linear because they are made from fills, and fills are always in linear
263 * color space. However, if they have been converted to bitmaps, we need
264 * to simulate the sRGB approximation to pass the test cases.
265 */
266 if (src->size)
267 {
268 if (PIXMAN_FORMAT_TYPE (src->format) == PIXMAN_TYPE_ARGB_SRGB)
269 {
270 tsrc.r = convert_linear_to_srgb (tsrc.r);
271 tsrc.g = convert_linear_to_srgb (tsrc.g);
272 tsrc.b = convert_linear_to_srgb (tsrc.b);
273 round_color (src->format, &tsrc);
274 tsrc.r = convert_srgb_to_linear (tsrc.r);
275 tsrc.g = convert_srgb_to_linear (tsrc.g);
276 tsrc.b = convert_srgb_to_linear (tsrc.b);
277 }
278 else
279 {
280 round_color (src->format, &tsrc);
281 }
282 }
283
284 if (mask && mask->size)
285 {
286 if (PIXMAN_FORMAT_TYPE (mask->format) == PIXMAN_TYPE_ARGB_SRGB)
287 {
288 tmsk.r = convert_linear_to_srgb (tmsk.r);
289 tmsk.g = convert_linear_to_srgb (tmsk.g);
290 tmsk.b = convert_linear_to_srgb (tmsk.b);
291 round_color (mask->format, &tmsk);
292 tmsk.r = convert_srgb_to_linear (tmsk.r);
293 tmsk.g = convert_srgb_to_linear (tmsk.g);
294 tmsk.b = convert_srgb_to_linear (tmsk.b);
295 }
296 else
297 {
298 round_color (mask->format, &tmsk);
299 }
300 }
301
302 if (PIXMAN_FORMAT_TYPE (dst->format) == PIXMAN_TYPE_ARGB_SRGB)
303 {
304 tdst.r = convert_linear_to_srgb (tdst.r);
305 tdst.g = convert_linear_to_srgb (tdst.g);
306 tdst.b = convert_linear_to_srgb (tdst.b);
307 round_color (dst->format, &tdst);
308 tdst.r = convert_srgb_to_linear (tdst.r);
309 tdst.g = convert_srgb_to_linear (tdst.g);
310 tdst.b = convert_srgb_to_linear (tdst.b);
311 }
312 else
313 {
314 round_color (dst->format, &tdst);
315 }
316
317 do_composite (op,
318 &tsrc,
319 mask? &tmsk : NULL,
320 &tdst,
321 &expected,
322 component_alpha);
323
324 pixel_checker_init (&checker, dst->format);
325
326 if (!pixel_checker_check (&checker, get_value (dst->image), &expected))
327 {
328 char buf[40], buf2[40];
329 int a, r, g, b;
330 uint32_t pixel;
331
332 printf ("---- Test %d failed ----\n", testno);
333 printf ("Operator: %s %s\n",
334 operator_name (op), component_alpha ? "CA" : "");
335
336 printf ("Source: %s\n", describe_image (src, buf));
337 if (mask != NULL)
338 printf ("Mask: %s\n", describe_image (mask, buf));
339
340 printf ("Destination: %s\n\n", describe_image (dst, buf));
341 printf (" R G B A Rounded\n");
342 printf ("Source color: %s %s\n",
343 describe_color (src->color, buf),
344 describe_color (&tsrc, buf2));
345 if (mask)
346 {
347 printf ("Mask color: %s %s\n",
348 describe_color (mask->color, buf),
349 describe_color (&tmsk, buf2));
350 }
351 printf ("Dest. color: %s %s\n",
352 describe_color (dst->color, buf),
353 describe_color (&tdst, buf2));
354
355 pixel = get_value (dst->image);
356
357 printf ("Expected: %s\n", describe_color (&expected, buf));
358
359 pixel_checker_split_pixel (&checker, pixel, &a, &r, &g, &b);
360
361 printf ("Got: %5d %5d %5d %5d [pixel: 0x%08x]\n", r, g, b, a, pixel);
362 pixel_checker_get_min (&checker, &expected, &a, &r, &g, &b);
363 printf ("Min accepted: %5d %5d %5d %5d\n", r, g, b, a);
364 pixel_checker_get_max (&checker, &expected, &a, &r, &g, &b);
365 printf ("Max accepted: %5d %5d %5d %5d\n", r, g, b, a);
366
367 return FALSE;
368 }
369 return TRUE;
370 }
371
372 static void
image_init(image_t * info,int color,int format,int size)373 image_init (image_t *info,
374 int color,
375 int format,
376 int size)
377 {
378 pixman_color_t fill;
379
380 info->color = &colors[color];
381 compute_pixman_color (info->color, &fill);
382
383 info->format = formats[format];
384 info->size = sizes[size] & ~FLAGS;
385 info->repeat = PIXMAN_REPEAT_NONE;
386
387 if (info->size)
388 {
389 pixman_image_t *solid;
390
391 info->image = pixman_image_create_bits (info->format,
392 info->size, info->size,
393 NULL, 0);
394
395 solid = pixman_image_create_solid_fill (&fill);
396 pixman_image_composite32 (PIXMAN_OP_SRC, solid, NULL, info->image,
397 0, 0, 0, 0, 0, 0, info->size, info->size);
398 pixman_image_unref (solid);
399
400 if (sizes[size] & REPEAT)
401 {
402 pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL);
403 info->repeat = PIXMAN_REPEAT_NORMAL;
404 }
405 }
406 else
407 {
408 info->image = pixman_image_create_solid_fill (&fill);
409 }
410 }
411
412 static void
image_fini(image_t * info)413 image_fini (image_t *info)
414 {
415 pixman_image_unref (info->image);
416 }
417
418 static int
random_size(void)419 random_size (void)
420 {
421 return prng_rand_n (ARRAY_LENGTH (sizes));
422 }
423
424 static int
random_color(void)425 random_color (void)
426 {
427 return prng_rand_n (ARRAY_LENGTH (colors));
428 }
429
430 static int
random_format(void)431 random_format (void)
432 {
433 return prng_rand_n (ARRAY_LENGTH (formats));
434 }
435
436 static pixman_bool_t
run_test(uint32_t seed)437 run_test (uint32_t seed)
438 {
439 image_t src, mask, dst;
440 pixman_op_t op;
441 int ca;
442 int ok;
443
444 prng_srand (seed);
445
446 image_init (&dst, random_color(), random_format(), 1);
447 image_init (&src, random_color(), random_format(), random_size());
448 image_init (&mask, random_color(), random_format(), random_size());
449
450 op = operators [prng_rand_n (ARRAY_LENGTH (operators))];
451
452 ca = prng_rand_n (3);
453
454 switch (ca)
455 {
456 case 0:
457 ok = composite_test (&dst, op, &src, NULL, FALSE, seed);
458 break;
459 case 1:
460 ok = composite_test (&dst, op, &src, &mask, FALSE, seed);
461 break;
462 case 2:
463 ok = composite_test (&dst, op, &src, &mask,
464 mask.size? TRUE : FALSE, seed);
465 break;
466 default:
467 ok = FALSE;
468 break;
469 }
470
471 image_fini (&src);
472 image_fini (&mask);
473 image_fini (&dst);
474
475 return ok;
476 }
477
478 int
main(int argc,char ** argv)479 main (int argc, char **argv)
480 {
481 #define N_TESTS (8 * 1024 * 1024)
482 int result = 0;
483 uint32_t seed;
484 int32_t i;
485
486 if (argc > 1)
487 {
488 char *end;
489
490 i = strtol (argv[1], &end, 0);
491
492 if (end != argv[1])
493 {
494 if (!run_test (i))
495 return 1;
496 else
497 return 0;
498 }
499 else
500 {
501 printf ("Usage:\n\n %s <number>\n\n", argv[0]);
502 return -1;
503 }
504 }
505
506 if (getenv ("PIXMAN_RANDOMIZE_TESTS"))
507 seed = get_random_seed();
508 else
509 seed = 1;
510
511 #ifdef USE_OPENMP
512 # pragma omp parallel for default(none) shared(result, argv, seed)
513 #endif
514 for (i = 0; i <= N_TESTS; ++i)
515 {
516 if (!result && !run_test (i + seed))
517 {
518 printf ("Test 0x%08X failed.\n", seed + i);
519
520 result = seed + i;
521 }
522 }
523
524 return result;
525 }
526