composite.c revision 1176bdada62cabc6ec4b0308a930e83b679d5d36
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
31typedef struct image_t image_t;
32
33static 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
45static uint16_t
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
56static void
57compute_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
69static const int sizes[] =
70{
71    0,
72    1,
73    1 | REPEAT,
74    10
75};
76
77static 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
131struct 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
140static 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
184static uint32_t
185get_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
199static char *
200describe_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
217static char *
218describe_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
226static pixman_bool_t
227composite_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 (mask)
303    {
304	if (component_alpha && PIXMAN_FORMAT_R (mask->format) == 0)
305	{
306	    /* Ax component-alpha masks expand alpha into
307	     * all color channels.
308	     */
309	    tmsk.r = tmsk.g = tmsk.b = tmsk.a;
310	}
311    }
312
313    if (PIXMAN_FORMAT_TYPE (dst->format) == PIXMAN_TYPE_ARGB_SRGB)
314    {
315	tdst.r = convert_linear_to_srgb (tdst.r);
316	tdst.g = convert_linear_to_srgb (tdst.g);
317	tdst.b = convert_linear_to_srgb (tdst.b);
318    	round_color (dst->format, &tdst);
319	tdst.r = convert_srgb_to_linear (tdst.r);
320	tdst.g = convert_srgb_to_linear (tdst.g);
321	tdst.b = convert_srgb_to_linear (tdst.b);
322    }
323    else
324    {
325    	round_color (dst->format, &tdst);
326    }
327
328    do_composite (op,
329		  &tsrc,
330		  mask? &tmsk : NULL,
331		  &tdst,
332		  &expected,
333		  component_alpha);
334
335    pixel_checker_init (&checker, dst->format);
336
337    if (!pixel_checker_check (&checker, get_value (dst->image), &expected))
338    {
339	char buf[40], buf2[40];
340	int a, r, g, b;
341	uint32_t pixel;
342
343	printf ("---- Test %d failed ----\n", testno);
344	printf ("Operator:      %s %s\n",
345                operator_name (op), component_alpha ? "CA" : "");
346
347	printf ("Source:        %s\n", describe_image (src, buf));
348	if (mask != NULL)
349	    printf ("Mask:          %s\n", describe_image (mask, buf));
350
351	printf ("Destination:   %s\n\n", describe_image (dst, buf));
352	printf ("               R     G     B     A         Rounded\n");
353	printf ("Source color:  %s     %s\n",
354		describe_color (src->color, buf),
355		describe_color (&tsrc, buf2));
356	if (mask)
357	{
358	    printf ("Mask color:    %s     %s\n",
359		    describe_color (mask->color, buf),
360		    describe_color (&tmsk, buf2));
361	}
362	printf ("Dest. color:   %s     %s\n",
363		describe_color (dst->color, buf),
364		describe_color (&tdst, buf2));
365
366	pixel = get_value (dst->image);
367
368	printf ("Expected:      %s\n", describe_color (&expected, buf));
369
370	pixel_checker_split_pixel (&checker, pixel, &a, &r, &g, &b);
371
372	printf ("Got:           %5d %5d %5d %5d  [pixel: 0x%08x]\n", r, g, b, a, pixel);
373	pixel_checker_get_min (&checker, &expected, &a, &r, &g, &b);
374	printf ("Min accepted:  %5d %5d %5d %5d\n", r, g, b, a);
375	pixel_checker_get_max (&checker, &expected, &a, &r, &g, &b);
376	printf ("Max accepted:  %5d %5d %5d %5d\n", r, g, b, a);
377
378	return FALSE;
379    }
380    return TRUE;
381}
382
383static void
384image_init (image_t *info,
385	    int color,
386	    int format,
387	    int size)
388{
389    pixman_color_t fill;
390
391    info->color = &colors[color];
392    compute_pixman_color (info->color, &fill);
393
394    info->format = formats[format];
395    info->size = sizes[size] & ~FLAGS;
396    info->repeat = PIXMAN_REPEAT_NONE;
397
398    if (info->size)
399    {
400	pixman_image_t *solid;
401
402	info->image = pixman_image_create_bits (info->format,
403						info->size, info->size,
404						NULL, 0);
405
406	solid = pixman_image_create_solid_fill (&fill);
407	pixman_image_composite32 (PIXMAN_OP_SRC, solid, NULL, info->image,
408				  0, 0, 0, 0, 0, 0, info->size, info->size);
409	pixman_image_unref (solid);
410
411	if (sizes[size] & REPEAT)
412	{
413	    pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL);
414	    info->repeat = PIXMAN_REPEAT_NORMAL;
415	}
416    }
417    else
418    {
419	info->image = pixman_image_create_solid_fill (&fill);
420    }
421}
422
423static void
424image_fini (image_t *info)
425{
426    pixman_image_unref (info->image);
427}
428
429static int
430random_size (void)
431{
432    return prng_rand_n (ARRAY_LENGTH (sizes));
433}
434
435static int
436random_color (void)
437{
438    return prng_rand_n (ARRAY_LENGTH (colors));
439}
440
441static int
442random_format (void)
443{
444    return prng_rand_n (ARRAY_LENGTH (formats));
445}
446
447static pixman_bool_t
448run_test (uint32_t seed)
449{
450    image_t src, mask, dst;
451    pixman_op_t op;
452    int ca;
453    int ok;
454
455    prng_srand (seed);
456
457    image_init (&dst, random_color(), random_format(), 1);
458    image_init (&src, random_color(), random_format(), random_size());
459    image_init (&mask, random_color(), random_format(), random_size());
460
461    op = operators [prng_rand_n (ARRAY_LENGTH (operators))];
462
463    ca = prng_rand_n (3);
464
465    switch (ca)
466    {
467    case 0:
468	ok = composite_test (&dst, op, &src, NULL, FALSE, seed);
469	break;
470    case 1:
471	ok = composite_test (&dst, op, &src, &mask, FALSE, seed);
472	break;
473    case 2:
474	ok = composite_test (&dst, op, &src, &mask,
475			     mask.size? TRUE : FALSE, seed);
476	break;
477    default:
478	ok = FALSE;
479	break;
480    }
481
482    image_fini (&src);
483    image_fini (&mask);
484    image_fini (&dst);
485
486    return ok;
487}
488
489int
490main (int argc, char **argv)
491{
492#define N_TESTS (8 * 1024 * 1024)
493    int result = 0;
494    uint32_t seed;
495    int32_t i;
496
497    if (argc > 1)
498    {
499	char *end;
500
501	i = strtol (argv[1], &end, 0);
502
503	if (end != argv[1])
504	{
505	    if (!run_test (i))
506		return 1;
507	    else
508		return 0;
509	}
510	else
511	{
512	    printf ("Usage:\n\n   %s <number>\n\n", argv[0]);
513	    return -1;
514	}
515    }
516
517    if (getenv ("PIXMAN_RANDOMIZE_TESTS"))
518	seed = get_random_seed();
519    else
520	seed = 1;
521
522#ifdef USE_OPENMP
523#   pragma omp parallel for default(none) shared(result, argv, seed)
524#endif
525    for (i = 0; i <= N_TESTS; ++i)
526    {
527	if (!result && !run_test (i + seed))
528	{
529	    printf ("Test 0x%08X failed.\n", seed + i);
530
531	    result = seed + i;
532	}
533    }
534
535    return result;
536}
537