1#include <stdio.h>
2#include <stdlib.h>
3#include "utils.h"
4
5#define WIDTH 48
6#define HEIGHT 48
7
8static const pixman_format_code_t formats[] =
9{
10    PIXMAN_a8r8g8b8,
11    PIXMAN_a2r10g10b10,
12    PIXMAN_a4r4g4b4,
13    PIXMAN_a8
14};
15
16static const pixman_format_code_t alpha_formats[] =
17{
18    PIXMAN_null,
19    PIXMAN_a8,
20    PIXMAN_a2r10g10b10,
21    PIXMAN_a4r4g4b4
22};
23
24static const int origins[] =
25{
26    0, 10, -100
27};
28
29static void
30on_destroy (pixman_image_t *image, void *data)
31{
32    uint32_t *bits = pixman_image_get_data (image);
33
34    fence_free (bits);
35}
36
37static pixman_image_t *
38make_image (pixman_format_code_t format)
39{
40    uint32_t *bits;
41    uint8_t bpp = PIXMAN_FORMAT_BPP (format) / 8;
42    pixman_image_t *image;
43
44    bits = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * bpp);
45
46    image = pixman_image_create_bits (format, WIDTH, HEIGHT, bits, WIDTH * bpp);
47
48    if (image && bits)
49	pixman_image_set_destroy_function (image, on_destroy, NULL);
50
51    return image;
52}
53
54static uint8_t
55get_alpha (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
56{
57    uint8_t *bits;
58    uint8_t r;
59
60    if (image->common.alpha_map)
61    {
62	if (x - orig_x >= 0 && x - orig_x < WIDTH &&
63	    y - orig_y >= 0 && y - orig_y < HEIGHT)
64	{
65	    image = (pixman_image_t *)image->common.alpha_map;
66
67	    x -= orig_x;
68	    y -= orig_y;
69	}
70	else
71	{
72	    return 0;
73	}
74    }
75
76    bits = (uint8_t *)image->bits.bits;
77
78    if (image->bits.format == PIXMAN_a8)
79    {
80	r = bits[y * WIDTH + x];
81    }
82    else if (image->bits.format == PIXMAN_a2r10g10b10)
83    {
84	r = ((uint32_t *)bits)[y * WIDTH + x] >> 30;
85	r |= r << 2;
86	r |= r << 4;
87    }
88    else if (image->bits.format == PIXMAN_a8r8g8b8)
89    {
90	r = ((uint32_t *)bits)[y * WIDTH + x] >> 24;
91    }
92    else if (image->bits.format == PIXMAN_a4r4g4b4)
93    {
94	r = ((uint16_t *)bits)[y * WIDTH + x] >> 12;
95	r |= r << 4;
96    }
97    else
98    {
99	assert (0);
100    }
101
102    return r;
103}
104
105static uint16_t
106get_red (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
107{
108    uint8_t *bits;
109    uint16_t r;
110
111    bits = (uint8_t *)image->bits.bits;
112
113    if (image->bits.format == PIXMAN_a8)
114    {
115	r = 0x00;
116    }
117    else if (image->bits.format == PIXMAN_a2r10g10b10)
118    {
119	r = ((uint32_t *)bits)[y * WIDTH + x] >> 14;
120	r &= 0xffc0;
121	r |= (r >> 10);
122    }
123    else if (image->bits.format == PIXMAN_a8r8g8b8)
124    {
125	r = ((uint32_t *)bits)[y * WIDTH + x] >> 16;
126	r &= 0xff;
127	r |= r << 8;
128    }
129    else if (image->bits.format == PIXMAN_a4r4g4b4)
130    {
131	r = ((uint16_t *)bits)[y * WIDTH + x] >> 8;
132	r &= 0xf;
133	r |= r << 4;
134	r |= r << 8;
135    }
136    else
137    {
138	assert (0);
139    }
140
141    return r;
142}
143
144static int
145run_test (int s, int d, int sa, int da, int soff, int doff)
146{
147    pixman_format_code_t sf = formats[s];
148    pixman_format_code_t df = formats[d];
149    pixman_format_code_t saf = alpha_formats[sa];
150    pixman_format_code_t daf = alpha_formats[da];
151    pixman_image_t *src, *dst, *orig_dst, *alpha, *orig_alpha;
152    pixman_transform_t t1;
153    int j, k;
154    int n_alpha_bits, n_red_bits;
155
156    soff = origins[soff];
157    doff = origins[doff];
158
159    n_alpha_bits = PIXMAN_FORMAT_A (df);
160    if (daf != PIXMAN_null)
161	n_alpha_bits = PIXMAN_FORMAT_A (daf);
162
163    n_red_bits = PIXMAN_FORMAT_R (df);
164
165    /* Source */
166    src = make_image (sf);
167    if (saf != PIXMAN_null)
168    {
169	alpha = make_image (saf);
170	pixman_image_set_alpha_map (src, alpha, soff, soff);
171	pixman_image_unref (alpha);
172    }
173
174    /* Destination */
175    orig_dst = make_image (df);
176    dst = make_image (df);
177    pixman_image_composite (PIXMAN_OP_SRC, orig_dst, NULL, dst,
178			    0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
179
180    if (daf != PIXMAN_null)
181    {
182	orig_alpha = make_image (daf);
183	alpha = make_image (daf);
184
185	pixman_image_composite (PIXMAN_OP_SRC, orig_alpha, NULL, alpha,
186				0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
187
188	pixman_image_set_alpha_map (orig_dst, orig_alpha, doff, doff);
189	pixman_image_set_alpha_map (dst, alpha, doff, doff);
190
191	pixman_image_unref (orig_alpha);
192	pixman_image_unref (alpha);
193    }
194
195    /* Transformations, repeats and filters on destinations should be ignored,
196     * so just set some random ones.
197     */
198    pixman_transform_init_identity (&t1);
199    pixman_transform_scale (&t1, NULL, pixman_int_to_fixed (100), pixman_int_to_fixed (11));
200    pixman_transform_rotate (&t1, NULL, pixman_double_to_fixed (0.5), pixman_double_to_fixed (0.11));
201    pixman_transform_translate (&t1, NULL, pixman_int_to_fixed (11), pixman_int_to_fixed (17));
202
203    pixman_image_set_transform (dst, &t1);
204    pixman_image_set_filter (dst, PIXMAN_FILTER_BILINEAR, NULL, 0);
205    pixman_image_set_repeat (dst, PIXMAN_REPEAT_REFLECT);
206
207    pixman_image_composite (PIXMAN_OP_ADD, src, NULL, dst,
208			    0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
209
210    for (j = MAX (doff, 0); j < MIN (HEIGHT, HEIGHT + doff); ++j)
211    {
212	for (k = MAX (doff, 0); k < MIN (WIDTH, WIDTH + doff); ++k)
213	{
214	    uint8_t sa, da, oda, refa;
215	    uint16_t sr, dr, odr, refr;
216
217	    sa = get_alpha (src, k, j, soff, soff);
218	    da = get_alpha (dst, k, j, doff, doff);
219	    oda = get_alpha (orig_dst, k, j, doff, doff);
220
221	    if (sa + oda > 255)
222		refa = 255;
223	    else
224		refa = sa + oda;
225
226	    if (da >> (8 - n_alpha_bits) != refa >> (8 - n_alpha_bits))
227	    {
228		printf ("\nWrong alpha value at (%d, %d). Should be 0x%x; got 0x%x. Source was 0x%x, original dest was 0x%x\n",
229			k, j, refa, da, sa, oda);
230
231		printf ("src: %s, alpha: %s, origin %d %d\ndst: %s, alpha: %s, origin: %d %d\n\n",
232			format_name (sf),
233			format_name (saf),
234			soff, soff,
235			format_name (df),
236			format_name (daf),
237			doff, doff);
238		return 1;
239	    }
240
241	    /* There are cases where we go through the 8 bit compositing
242	     * path even with 10bpc formats. This results in incorrect
243	     * results here, so only do the red check for narrow formats
244	     */
245	    if (n_red_bits <= 8)
246	    {
247		sr = get_red (src, k, j, soff, soff);
248		dr = get_red (dst, k, j, doff, doff);
249		odr = get_red (orig_dst, k, j, doff, doff);
250
251		if (sr + odr > 0xffff)
252		    refr = 0xffff;
253		else
254		    refr = sr + odr;
255
256		if (abs ((dr >> (16 - n_red_bits)) - (refr >> (16 - n_red_bits))) > 1)
257		{
258		    printf ("%d red bits\n", n_red_bits);
259		    printf ("\nWrong red value at (%d, %d). Should be 0x%x; got 0x%x. Source was 0x%x, original dest was 0x%x\n",
260			    k, j, refr, dr, sr, odr);
261
262		    printf ("src: %s, alpha: %s, origin %d %d\ndst: %s, alpha: %s, origin: %d %d\n\n",
263			    format_name (sf),
264			    format_name (saf),
265			    soff, soff,
266			    format_name (df),
267			    format_name (daf),
268			    doff, doff);
269		    return 1;
270		}
271	    }
272	}
273    }
274
275    pixman_image_set_alpha_map (src, NULL, 0, 0);
276    pixman_image_set_alpha_map (dst, NULL, 0, 0);
277    pixman_image_set_alpha_map (orig_dst, NULL, 0, 0);
278
279    pixman_image_unref (src);
280    pixman_image_unref (dst);
281    pixman_image_unref (orig_dst);
282
283    return 0;
284}
285
286int
287main (int argc, char **argv)
288{
289    int i, j, a, b, x, y;
290
291    prng_srand (0);
292
293    for (i = 0; i < ARRAY_LENGTH (formats); ++i)
294    {
295	for (j = 0; j < ARRAY_LENGTH (formats); ++j)
296	{
297	    for (a = 0; a < ARRAY_LENGTH (alpha_formats); ++a)
298	    {
299		for (b = 0; b < ARRAY_LENGTH (alpha_formats); ++b)
300		{
301		    for (x = 0; x < ARRAY_LENGTH (origins); ++x)
302		    {
303			for (y = 0; y < ARRAY_LENGTH (origins); ++y)
304			{
305			    if (run_test (i, j, a, b, x, y) != 0)
306				return 1;
307			}
308		    }
309		}
310	    }
311	}
312    }
313
314    return 0;
315}
316