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