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