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