composite.c revision 6ba797d6
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#define PIXMAN_USE_INTERNAL_API
26#include <pixman.h>
27#include <stdio.h>
28#include <stdlib.h> /* abort() */
29#include <math.h>
30#include <config.h>
31#include <time.h>
32#include "utils.h"
33
34typedef struct color_t color_t;
35typedef struct format_t format_t;
36typedef struct image_t image_t;
37typedef struct operator_t operator_t;
38
39struct color_t
40{
41    double r, g, b, a;
42};
43
44struct format_t
45{
46    pixman_format_code_t format;
47    const char *name;
48};
49
50static const color_t colors[] =
51{
52    { 1.0, 1.0, 1.0, 1.0 },
53    { 1.0, 1.0, 1.0, 0.0 },
54    { 0.0, 0.0, 0.0, 1.0 },
55    { 0.0, 0.0, 0.0, 0.0 },
56    { 1.0, 0.0, 0.0, 1.0 },
57    { 0.0, 1.0, 0.0, 1.0 },
58    { 0.0, 0.0, 1.0, 1.0 },
59    { 0.5, 0.0, 0.0, 0.5 },
60};
61
62static uint16_t
63_color_double_to_short (double d)
64{
65    uint32_t i;
66
67    i = (uint32_t) (d * 65536);
68    i -= (i >> 16);
69
70    return i;
71}
72
73static void
74compute_pixman_color (const color_t *color,
75		      pixman_color_t *out)
76{
77    out->red   = _color_double_to_short (color->r);
78    out->green = _color_double_to_short (color->g);
79    out->blue  = _color_double_to_short (color->b);
80    out->alpha = _color_double_to_short (color->a);
81}
82
83#define REPEAT 0x01000000
84#define FLAGS  0xff000000
85
86static const int sizes[] =
87{
88    0,
89    1,
90    1 | REPEAT,
91    10
92};
93
94static const format_t formats[] =
95{
96#define P(x) { PIXMAN_##x, #x }
97
98    /* 32 bpp formats */
99    P(a8r8g8b8),
100    P(x8r8g8b8),
101    P(a8b8g8r8),
102    P(x8b8g8r8),
103    P(b8g8r8a8),
104    P(b8g8r8x8),
105    P(r8g8b8a8),
106    P(r8g8b8x8),
107    P(x2r10g10b10),
108    P(x2b10g10r10),
109    P(a2r10g10b10),
110    P(a2b10g10r10),
111
112    /* 24 bpp formats */
113    P(r8g8b8),
114    P(b8g8r8),
115    P(r5g6b5),
116    P(b5g6r5),
117
118    /* 16 bpp formats */
119    P(x1r5g5b5),
120    P(x1b5g5r5),
121    P(a1r5g5b5),
122    P(a1b5g5r5),
123    P(a4b4g4r4),
124    P(x4b4g4r4),
125    P(a4r4g4b4),
126    P(x4r4g4b4),
127
128    /* 8 bpp formats */
129    P(a8),
130    P(r3g3b2),
131    P(b2g3r3),
132    P(a2r2g2b2),
133    P(a2b2g2r2),
134    P(x4a4),
135
136    /* 4 bpp formats */
137    P(a4),
138    P(r1g2b1),
139    P(b1g2r1),
140    P(a1r1g1b1),
141    P(a1b1g1r1),
142
143    /* 1 bpp formats */
144    P(a1)
145#undef P
146};
147
148struct image_t
149{
150    pixman_image_t *image;
151    const format_t *format;
152    const color_t *color;
153    pixman_repeat_t repeat;
154    int size;
155};
156
157struct operator_t
158{
159    pixman_op_t op;
160    const char *name;
161};
162
163static const operator_t operators[] =
164{
165#define P(x) { PIXMAN_OP_##x, #x }
166    P(CLEAR),
167    P(SRC),
168    P(DST),
169    P(OVER),
170    P(OVER_REVERSE),
171    P(IN),
172    P(IN_REVERSE),
173    P(OUT),
174    P(OUT_REVERSE),
175    P(ATOP),
176    P(ATOP_REVERSE),
177    P(XOR),
178    P(ADD),
179    P(SATURATE),
180
181    P(DISJOINT_CLEAR),
182    P(DISJOINT_SRC),
183    P(DISJOINT_DST),
184    P(DISJOINT_OVER),
185    P(DISJOINT_OVER_REVERSE),
186    P(DISJOINT_IN),
187    P(DISJOINT_IN_REVERSE),
188    P(DISJOINT_OUT),
189    P(DISJOINT_OUT_REVERSE),
190    P(DISJOINT_ATOP),
191    P(DISJOINT_ATOP_REVERSE),
192    P(DISJOINT_XOR),
193
194    P(CONJOINT_CLEAR),
195    P(CONJOINT_SRC),
196    P(CONJOINT_DST),
197    P(CONJOINT_OVER),
198    P(CONJOINT_OVER_REVERSE),
199    P(CONJOINT_IN),
200    P(CONJOINT_IN_REVERSE),
201    P(CONJOINT_OUT),
202    P(CONJOINT_OUT_REVERSE),
203    P(CONJOINT_ATOP),
204    P(CONJOINT_ATOP_REVERSE),
205    P(CONJOINT_XOR),
206#undef P
207};
208
209static double
210calc_op (pixman_op_t op, double src, double dst, double srca, double dsta)
211{
212#define mult_chan(src, dst, Fa, Fb) MIN ((src) * (Fa) + (dst) * (Fb), 1.0)
213
214    double Fa, Fb;
215
216    switch (op)
217    {
218    case PIXMAN_OP_CLEAR:
219    case PIXMAN_OP_DISJOINT_CLEAR:
220    case PIXMAN_OP_CONJOINT_CLEAR:
221	return mult_chan (src, dst, 0.0, 0.0);
222
223    case PIXMAN_OP_SRC:
224    case PIXMAN_OP_DISJOINT_SRC:
225    case PIXMAN_OP_CONJOINT_SRC:
226	return mult_chan (src, dst, 1.0, 0.0);
227
228    case PIXMAN_OP_DST:
229    case PIXMAN_OP_DISJOINT_DST:
230    case PIXMAN_OP_CONJOINT_DST:
231	return mult_chan (src, dst, 0.0, 1.0);
232
233    case PIXMAN_OP_OVER:
234	return mult_chan (src, dst, 1.0, 1.0 - srca);
235
236    case PIXMAN_OP_OVER_REVERSE:
237	return mult_chan (src, dst, 1.0 - dsta, 1.0);
238
239    case PIXMAN_OP_IN:
240	return mult_chan (src, dst, dsta, 0.0);
241
242    case PIXMAN_OP_IN_REVERSE:
243	return mult_chan (src, dst, 0.0, srca);
244
245    case PIXMAN_OP_OUT:
246	return mult_chan (src, dst, 1.0 - dsta, 0.0);
247
248    case PIXMAN_OP_OUT_REVERSE:
249	return mult_chan (src, dst, 0.0, 1.0 - srca);
250
251    case PIXMAN_OP_ATOP:
252	return mult_chan (src, dst, dsta, 1.0 - srca);
253
254    case PIXMAN_OP_ATOP_REVERSE:
255	return mult_chan (src, dst, 1.0 - dsta,  srca);
256
257    case PIXMAN_OP_XOR:
258	return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca);
259
260    case PIXMAN_OP_ADD:
261	return mult_chan (src, dst, 1.0, 1.0);
262
263    case PIXMAN_OP_SATURATE:
264    case PIXMAN_OP_DISJOINT_OVER_REVERSE:
265	if (srca == 0.0)
266	    Fa = 1.0;
267	else
268	    Fa = MIN (1.0, (1.0 - dsta) / srca);
269	return mult_chan (src, dst, Fa, 1.0);
270
271    case PIXMAN_OP_DISJOINT_OVER:
272	if (dsta == 0.0)
273	    Fb = 1.0;
274	else
275	    Fb = MIN (1.0, (1.0 - srca) / dsta);
276	return mult_chan (src, dst, 1.0, Fb);
277
278    case PIXMAN_OP_DISJOINT_IN:
279	if (srca == 0.0)
280	    Fa = 0.0;
281	else
282	    Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca);
283	return mult_chan (src, dst, Fa, 0.0);
284
285    case PIXMAN_OP_DISJOINT_IN_REVERSE:
286	if (dsta == 0.0)
287	    Fb = 0.0;
288	else
289	    Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta);
290	return mult_chan (src, dst, 0.0, Fb);
291
292    case PIXMAN_OP_DISJOINT_OUT:
293	if (srca == 0.0)
294	    Fa = 1.0;
295	else
296	    Fa = MIN (1.0, (1.0 - dsta) / srca);
297	return mult_chan (src, dst, Fa, 0.0);
298
299    case PIXMAN_OP_DISJOINT_OUT_REVERSE:
300	if (dsta == 0.0)
301	    Fb = 1.0;
302	else
303	    Fb = MIN (1.0, (1.0 - srca) / dsta);
304	return mult_chan (src, dst, 0.0, Fb);
305
306    case PIXMAN_OP_DISJOINT_ATOP:
307	if (srca == 0.0)
308	    Fa = 0.0;
309	else
310	    Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca);
311	if (dsta == 0.0)
312	    Fb = 1.0;
313	else
314	    Fb = MIN (1.0, (1.0 - srca) / dsta);
315	return mult_chan (src, dst, Fa, Fb);
316
317    case PIXMAN_OP_DISJOINT_ATOP_REVERSE:
318	if (srca == 0.0)
319	    Fa = 1.0;
320	else
321	    Fa = MIN (1.0, (1.0 - dsta) / srca);
322	if (dsta == 0.0)
323	    Fb = 0.0;
324	else
325	    Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta);
326	return mult_chan (src, dst, Fa, Fb);
327
328    case PIXMAN_OP_DISJOINT_XOR:
329	if (srca == 0.0)
330	    Fa = 1.0;
331	else
332	    Fa = MIN (1.0, (1.0 - dsta) / srca);
333	if (dsta == 0.0)
334	    Fb = 1.0;
335	else
336	    Fb = MIN (1.0, (1.0 - srca) / dsta);
337	return mult_chan (src, dst, Fa, Fb);
338
339    case PIXMAN_OP_CONJOINT_OVER:
340	if (dsta == 0.0)
341	    Fb = 0.0;
342	else
343	    Fb = MAX (0.0, 1.0 - srca / dsta);
344	return mult_chan (src, dst, 1.0, Fb);
345
346    case PIXMAN_OP_CONJOINT_OVER_REVERSE:
347	if (srca == 0.0)
348	    Fa = 0.0;
349	else
350	    Fa = MAX (0.0, 1.0 - dsta / srca);
351	return mult_chan (src, dst, Fa, 1.0);
352
353    case PIXMAN_OP_CONJOINT_IN:
354	if (srca == 0.0)
355	    Fa = 1.0;
356	else
357	    Fa = MIN (1.0, dsta / srca);
358	return mult_chan (src, dst, Fa, 0.0);
359
360    case PIXMAN_OP_CONJOINT_IN_REVERSE:
361	if (dsta == 0.0)
362	    Fb = 1.0;
363	else
364	    Fb = MIN (1.0, srca / dsta);
365	return mult_chan (src, dst, 0.0, Fb);
366
367    case PIXMAN_OP_CONJOINT_OUT:
368	if (srca == 0.0)
369	    Fa = 0.0;
370	else
371	    Fa = MAX (0.0, 1.0 - dsta / srca);
372	return mult_chan (src, dst, Fa, 0.0);
373
374    case PIXMAN_OP_CONJOINT_OUT_REVERSE:
375	if (dsta == 0.0)
376	    Fb = 0.0;
377	else
378	    Fb = MAX (0.0, 1.0 - srca / dsta);
379	return mult_chan (src, dst, 0.0, Fb);
380
381    case PIXMAN_OP_CONJOINT_ATOP:
382	if (srca == 0.0)
383	    Fa = 1.0;
384	else
385	    Fa = MIN (1.0, dsta / srca);
386	if (dsta == 0.0)
387	    Fb = 0.0;
388	else
389	    Fb = MAX (0.0, 1.0 - srca / dsta);
390	return mult_chan (src, dst, Fa, Fb);
391
392    case PIXMAN_OP_CONJOINT_ATOP_REVERSE:
393	if (srca == 0.0)
394	    Fa = 0.0;
395	else
396	    Fa = MAX (0.0, 1.0 - dsta / srca);
397	if (dsta == 0.0)
398	    Fb = 1.0;
399	else
400	    Fb = MIN (1.0, srca / dsta);
401	return mult_chan (src, dst, Fa, Fb);
402
403    case PIXMAN_OP_CONJOINT_XOR:
404	if (srca == 0.0)
405	    Fa = 0.0;
406	else
407	    Fa = MAX (0.0, 1.0 - dsta / srca);
408	if (dsta == 0.0)
409	    Fb = 0.0;
410	else
411	    Fb = MAX (0.0, 1.0 - srca / dsta);
412	return mult_chan (src, dst, Fa, Fb);
413
414    case PIXMAN_OP_MULTIPLY:
415    case PIXMAN_OP_SCREEN:
416    case PIXMAN_OP_OVERLAY:
417    case PIXMAN_OP_DARKEN:
418    case PIXMAN_OP_LIGHTEN:
419    case PIXMAN_OP_COLOR_DODGE:
420    case PIXMAN_OP_COLOR_BURN:
421    case PIXMAN_OP_HARD_LIGHT:
422    case PIXMAN_OP_SOFT_LIGHT:
423    case PIXMAN_OP_DIFFERENCE:
424    case PIXMAN_OP_EXCLUSION:
425    case PIXMAN_OP_HSL_HUE:
426    case PIXMAN_OP_HSL_SATURATION:
427    case PIXMAN_OP_HSL_COLOR:
428    case PIXMAN_OP_HSL_LUMINOSITY:
429    default:
430	abort();
431	return 0; /* silence MSVC */
432    }
433#undef mult_chan
434}
435
436static void
437do_composite (pixman_op_t op,
438	      const color_t *src,
439	      const color_t *mask,
440	      const color_t *dst,
441	      color_t *result,
442	      pixman_bool_t component_alpha)
443{
444    color_t srcval, srcalpha;
445
446    if (mask == NULL)
447    {
448	srcval = *src;
449
450	srcalpha.r = src->a;
451	srcalpha.g = src->a;
452	srcalpha.b = src->a;
453	srcalpha.a = src->a;
454    }
455    else if (component_alpha)
456    {
457	srcval.r = src->r * mask->r;
458	srcval.g = src->g * mask->g;
459	srcval.b = src->b * mask->b;
460	srcval.a = src->a * mask->a;
461
462	srcalpha.r = src->a * mask->r;
463	srcalpha.g = src->a * mask->g;
464	srcalpha.b = src->a * mask->b;
465	srcalpha.a = src->a * mask->a;
466    }
467    else
468    {
469	srcval.r = src->r * mask->a;
470	srcval.g = src->g * mask->a;
471	srcval.b = src->b * mask->a;
472	srcval.a = src->a * mask->a;
473
474	srcalpha.r = src->a * mask->a;
475	srcalpha.g = src->a * mask->a;
476	srcalpha.b = src->a * mask->a;
477	srcalpha.a = src->a * mask->a;
478    }
479
480    result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a);
481    result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a);
482    result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a);
483    result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a);
484}
485
486static void
487color_correct (pixman_format_code_t format,
488	       color_t *color)
489{
490#define MASK(x) ((1 << (x)) - 1)
491#define round_pix(pix, m)						\
492    ((int)((pix) * (MASK(m)) + .5) / (double) (MASK(m)))
493
494    if (PIXMAN_FORMAT_R (format) == 0)
495    {
496	color->r = 0.0;
497	color->g = 0.0;
498	color->b = 0.0;
499    }
500    else
501    {
502	color->r = round_pix (color->r, PIXMAN_FORMAT_R (format));
503	color->g = round_pix (color->g, PIXMAN_FORMAT_G (format));
504	color->b = round_pix (color->b, PIXMAN_FORMAT_B (format));
505    }
506
507    if (PIXMAN_FORMAT_A (format) == 0)
508	color->a = 1.0;
509    else
510	color->a = round_pix (color->a, PIXMAN_FORMAT_A (format));
511
512#undef round_pix
513#undef MASK
514}
515
516static void
517get_pixel (pixman_image_t *image,
518	   pixman_format_code_t format,
519	   color_t *color)
520{
521#define MASK(N) ((1UL << (N))-1)
522
523    unsigned long rs, gs, bs, as;
524    int a, r, g, b;
525    unsigned long val;
526
527    val = *(unsigned long *) pixman_image_get_data (image);
528#ifdef WORDS_BIGENDIAN
529    val >>= 8 * sizeof(val) - PIXMAN_FORMAT_BPP (format);
530#endif
531
532    /* Number of bits in each channel */
533    a = PIXMAN_FORMAT_A (format);
534    r = PIXMAN_FORMAT_R (format);
535    g = PIXMAN_FORMAT_G (format);
536    b = PIXMAN_FORMAT_B (format);
537
538    switch (PIXMAN_FORMAT_TYPE (format))
539    {
540    case PIXMAN_TYPE_ARGB:
541        bs = 0;
542        gs = b + bs;
543        rs = g + gs;
544        as = r + rs;
545	break;
546
547    case PIXMAN_TYPE_ABGR:
548        rs = 0;
549        gs = r + rs;
550        bs = g + gs;
551        as = b + bs;
552	break;
553
554    case PIXMAN_TYPE_BGRA:
555        as = 0;
556	rs = PIXMAN_FORMAT_BPP (format) - (b + g + r);
557        gs = r + rs;
558        bs = g + gs;
559	break;
560
561    case PIXMAN_TYPE_RGBA:
562	as = 0;
563	bs = PIXMAN_FORMAT_BPP (format) - (b + g + r);
564	gs = b + bs;
565	rs = g + gs;
566	break;
567
568    case PIXMAN_TYPE_A:
569        as = 0;
570        rs = 0;
571        gs = 0;
572        bs = 0;
573	break;
574
575    case PIXMAN_TYPE_OTHER:
576    case PIXMAN_TYPE_COLOR:
577    case PIXMAN_TYPE_GRAY:
578    case PIXMAN_TYPE_YUY2:
579    case PIXMAN_TYPE_YV12:
580    default:
581	abort ();
582        as = 0;
583        rs = 0;
584        gs = 0;
585        bs = 0;
586	break;
587    }
588
589    if (MASK (a) != 0)
590	color->a = ((val >> as) & MASK (a)) / (double) MASK (a);
591    else
592	color->a = 1.0;
593
594    if (MASK (r) != 0)
595    {
596	color->r = ((val >> rs) & MASK (r)) / (double) MASK (r);
597	color->g = ((val >> gs) & MASK (g)) / (double) MASK (g);
598	color->b = ((val >> bs) & MASK (b)) / (double) MASK (b);
599    }
600    else
601    {
602	color->r = 0.0;
603	color->g = 0.0;
604	color->b = 0.0;
605    }
606
607#undef MASK
608}
609
610static double
611eval_diff (color_t *expected, color_t *test, pixman_format_code_t format)
612{
613    double rscale, gscale, bscale, ascale;
614    double rdiff, gdiff, bdiff, adiff;
615
616    rscale = 1.0 * ((1 << PIXMAN_FORMAT_R (format)) - 1);
617    gscale = 1.0 * ((1 << PIXMAN_FORMAT_G (format)) - 1);
618    bscale = 1.0 * ((1 << PIXMAN_FORMAT_B (format)) - 1);
619    ascale = 1.0 * ((1 << PIXMAN_FORMAT_A (format)) - 1);
620
621    rdiff = fabs (test->r - expected->r) * rscale;
622    bdiff = fabs (test->g - expected->g) * gscale;
623    gdiff = fabs (test->b - expected->b) * bscale;
624    adiff = fabs (test->a - expected->a) * ascale;
625
626    return MAX (MAX (MAX (rdiff, gdiff), bdiff), adiff);
627}
628
629static char *
630describe_image (image_t *info, char *buf)
631{
632    if (info->size)
633    {
634	sprintf (buf, "%s %dx%d%s",
635		 info->format->name,
636		 info->size, info->size,
637		 info->repeat ? "R" :"");
638    }
639    else
640    {
641	sprintf (buf, "solid");
642    }
643
644    return buf;
645}
646
647/* Test a composite of a given operation, source, mask, and destination
648 * picture.
649 * Fills the window, and samples from the 0,0 pixel corner.
650 */
651static pixman_bool_t
652composite_test (image_t *dst,
653		const operator_t *op,
654		image_t *src,
655		image_t *mask,
656		pixman_bool_t component_alpha)
657{
658    pixman_color_t fill;
659    pixman_rectangle16_t rect;
660    color_t expected, result, tdst, tsrc, tmsk;
661    double diff;
662    pixman_bool_t success = TRUE;
663
664    compute_pixman_color (dst->color, &fill);
665    rect.x = rect.y = 0;
666    rect.width = rect.height = dst->size;
667    pixman_image_fill_rectangles (PIXMAN_OP_SRC, dst->image,
668				  &fill, 1, &rect);
669
670    if (mask != NULL)
671    {
672	pixman_image_set_component_alpha (mask->image, component_alpha);
673	pixman_image_composite (op->op, src->image, mask->image, dst->image,
674				0, 0,
675				0, 0,
676				0, 0,
677				dst->size, dst->size);
678
679	tmsk = *mask->color;
680	if (mask->size)
681	{
682	    color_correct (mask->format->format, &tmsk);
683
684	    if (component_alpha &&
685		PIXMAN_FORMAT_R (mask->format->format) == 0)
686	    {
687		/* Ax component-alpha masks expand alpha into
688		 * all color channels.
689		 */
690		tmsk.r = tmsk.g = tmsk.b = tmsk.a;
691	    }
692	}
693    }
694    else
695    {
696	pixman_image_composite (op->op, src->image, NULL, dst->image,
697				0, 0,
698				0, 0,
699				0, 0,
700				dst->size, dst->size);
701    }
702    get_pixel (dst->image, dst->format->format, &result);
703
704    tdst = *dst->color;
705    color_correct (dst->format->format, &tdst);
706    tsrc = *src->color;
707    if (src->size)
708	color_correct (src->format->format, &tsrc);
709    do_composite (op->op, &tsrc, mask ? &tmsk : NULL, &tdst,
710		  &expected, component_alpha);
711    color_correct (dst->format->format, &expected);
712
713    diff = eval_diff (&expected, &result, dst->format->format);
714
715    /* FIXME: We should find out what deviation is acceptable. 3.0
716     * is clearly absurd for 2 bit formats for example. On the other
717     * hand currently 1.0 does not work.
718     */
719    if (diff > 3.0)
720    {
721	char buf[40];
722
723	sprintf (buf, "%s %scomposite",
724		 op->name,
725		 component_alpha ? "CA " : "");
726
727	printf ("%s test error of %.4f --\n"
728		"           R    G    B    A\n"
729		"got:       %.2f %.2f %.2f %.2f [%08lx]\n"
730		"expected:  %.2f %.2f %.2f %.2f\n",
731		buf, diff,
732		result.r, result.g, result.b, result.a,
733		*(unsigned long *) pixman_image_get_data (dst->image),
734		expected.r, expected.g, expected.b, expected.a);
735
736	if (mask != NULL)
737	{
738	    printf ("src color: %.2f %.2f %.2f %.2f\n"
739		    "msk color: %.2f %.2f %.2f %.2f\n"
740		    "dst color: %.2f %.2f %.2f %.2f\n",
741		    src->color->r, src->color->g,
742		    src->color->b, src->color->a,
743		    mask->color->r, mask->color->g,
744		    mask->color->b, mask->color->a,
745		    dst->color->r, dst->color->g,
746		    dst->color->b, dst->color->a);
747	    printf ("src: %s, ", describe_image (src, buf));
748	    printf ("mask: %s, ", describe_image (mask, buf));
749	    printf ("dst: %s\n\n", describe_image (dst, buf));
750	}
751	else
752	{
753	    printf ("src color: %.2f %.2f %.2f %.2f\n"
754		    "dst color: %.2f %.2f %.2f %.2f\n",
755		    src->color->r, src->color->g,
756		    src->color->b, src->color->a,
757		    dst->color->r, dst->color->g,
758		    dst->color->b, dst->color->a);
759	    printf ("src: %s, ", describe_image (src, buf));
760	    printf ("dst: %s\n\n", describe_image (dst, buf));
761	}
762
763	success = FALSE;
764    }
765
766    return success;
767}
768
769static void
770image_init (image_t *info,
771	    int color,
772	    int format,
773	    int size)
774{
775    pixman_color_t fill;
776
777    info->color = &colors[color];
778    compute_pixman_color (info->color, &fill);
779
780    info->format = &formats[format];
781    info->size = sizes[size] & ~FLAGS;
782    info->repeat = PIXMAN_REPEAT_NONE;
783
784    if (info->size)
785    {
786	pixman_rectangle16_t rect;
787
788	info->image = pixman_image_create_bits (info->format->format,
789						info->size, info->size,
790						NULL, 0);
791
792	rect.x = rect.y = 0;
793	rect.width = rect.height = info->size;
794	pixman_image_fill_rectangles (PIXMAN_OP_SRC, info->image, &fill,
795				      1, &rect);
796
797	if (size & REPEAT)
798	{
799	    pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL);
800	    info->repeat = PIXMAN_REPEAT_NORMAL;
801	}
802    }
803    else
804    {
805	info->image = pixman_image_create_solid_fill (&fill);
806    }
807}
808
809static void
810image_fini (image_t *info)
811{
812    pixman_image_unref (info->image);
813}
814
815static int
816random_size (void)
817{
818    return lcg_rand_n (ARRAY_LENGTH (sizes));
819}
820
821static int
822random_color (void)
823{
824    return lcg_rand_n (ARRAY_LENGTH (colors));
825}
826
827static int
828random_format (void)
829{
830    return lcg_rand_n (ARRAY_LENGTH (formats));
831}
832
833static pixman_bool_t
834run_test (uint32_t seed)
835{
836    image_t src, mask, dst;
837    const operator_t *op;
838    int ca;
839    int ok;
840
841    lcg_srand (seed);
842
843    image_init (&dst, random_color(), random_format(), 1);
844    image_init (&src, random_color(), random_format(), random_size());
845    image_init (&mask, random_color(), random_format(), random_size());
846
847    op = &(operators [lcg_rand_n (ARRAY_LENGTH (operators))]);
848
849    ca = lcg_rand_n (3);
850
851    switch (ca)
852    {
853    case 0:
854	ok = composite_test (&dst, op, &src, NULL, FALSE);
855	break;
856    case 1:
857	ok = composite_test (&dst, op, &src, &mask, FALSE);
858	break;
859    case 2:
860	ok = composite_test (&dst, op, &src, &mask,
861			     mask.size? TRUE : FALSE);
862	break;
863    default:
864	ok = FALSE;
865	break;
866    }
867
868    image_fini (&src);
869    image_fini (&mask);
870    image_fini (&dst);
871
872    return ok;
873}
874
875int
876main (int argc, char **argv)
877{
878#define N_TESTS (8 * 1024 * 1024)
879    int result = 0;
880    uint32_t i, seed;
881
882    if (argc > 1)
883    {
884	char *end;
885
886	i = strtol (argv[1], &end, 0);
887
888	if (end != argv[1])
889	{
890	    if (!run_test (i))
891		return 1;
892	    else
893		return 0;
894	}
895	else
896	{
897	    printf ("Usage:\n\n   %s <number>\n\n", argv[0]);
898	    return -1;
899	}
900    }
901
902    if (getenv ("PIXMAN_RANDOMIZE_TESTS"))
903	seed = get_random_seed();
904    else
905	seed = 1;
906
907#ifdef USE_OPENMP
908#   pragma omp parallel for default(none) shared(result, argv, seed)
909#endif
910    for (i = 0; i <= N_TESTS; ++i)
911    {
912	if (!result && !run_test (i + seed))
913	{
914	    printf ("Test 0x%08X failed.\n", seed + i);
915
916	    result = seed + i;
917	}
918    }
919
920    return result;
921}
922