1952204abSmrg#include <stdio.h>
2952204abSmrg#include <stdlib.h>
3952204abSmrg#include "utils.h"
4952204abSmrg
59ad247e8Sjmcneill#define WIDTH 48
69ad247e8Sjmcneill#define HEIGHT 48
7952204abSmrg
81b18d63aSmrgstatic const pixman_format_code_t formats[] =
91b18d63aSmrg{
101b18d63aSmrg    PIXMAN_a8r8g8b8,
111b18d63aSmrg    PIXMAN_a2r10g10b10,
121b18d63aSmrg    PIXMAN_a4r4g4b4,
134f2886e8Smrg    PIXMAN_a8,
144f2886e8Smrg    PIXMAN_rgba_float,
151b18d63aSmrg};
161b18d63aSmrg
171b18d63aSmrgstatic const pixman_format_code_t alpha_formats[] =
181b18d63aSmrg{
191b18d63aSmrg    PIXMAN_null,
201b18d63aSmrg    PIXMAN_a8,
211b18d63aSmrg    PIXMAN_a2r10g10b10,
224f2886e8Smrg    PIXMAN_a4r4g4b4,
234f2886e8Smrg    PIXMAN_rgba_float,
241b18d63aSmrg};
251b18d63aSmrg
261b18d63aSmrgstatic const int origins[] =
271b18d63aSmrg{
281b18d63aSmrg    0, 10, -100
291b18d63aSmrg};
301b18d63aSmrg
311b18d63aSmrgstatic void
321b18d63aSmrgon_destroy (pixman_image_t *image, void *data)
331b18d63aSmrg{
341b18d63aSmrg    uint32_t *bits = pixman_image_get_data (image);
351b18d63aSmrg
361b18d63aSmrg    fence_free (bits);
371b18d63aSmrg}
381b18d63aSmrg
391b18d63aSmrgstatic pixman_image_t *
401b18d63aSmrgmake_image (pixman_format_code_t format)
411b18d63aSmrg{
421b18d63aSmrg    uint32_t *bits;
431b18d63aSmrg    uint8_t bpp = PIXMAN_FORMAT_BPP (format) / 8;
441b18d63aSmrg    pixman_image_t *image;
451b18d63aSmrg
464f2886e8Smrg    if (format != PIXMAN_rgba_float)
474f2886e8Smrg	bits = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * bpp);
484f2886e8Smrg    else
494f2886e8Smrg	bits = (uint32_t *)make_random_floats (WIDTH * HEIGHT * bpp);
501b18d63aSmrg
511b18d63aSmrg    image = pixman_image_create_bits (format, WIDTH, HEIGHT, bits, WIDTH * bpp);
521b18d63aSmrg
531b18d63aSmrg    if (image && bits)
541b18d63aSmrg	pixman_image_set_destroy_function (image, on_destroy, NULL);
551b18d63aSmrg
561b18d63aSmrg    return image;
571b18d63aSmrg}
581b18d63aSmrg
594f2886e8Smrgstatic float
601b18d63aSmrgget_alpha (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
61952204abSmrg{
621b18d63aSmrg    uint8_t *bits;
634f2886e8Smrg    uint32_t r;
641b18d63aSmrg
651b18d63aSmrg    if (image->common.alpha_map)
661b18d63aSmrg    {
671b18d63aSmrg	if (x - orig_x >= 0 && x - orig_x < WIDTH &&
681b18d63aSmrg	    y - orig_y >= 0 && y - orig_y < HEIGHT)
691b18d63aSmrg	{
701b18d63aSmrg	    image = (pixman_image_t *)image->common.alpha_map;
711b18d63aSmrg
721b18d63aSmrg	    x -= orig_x;
731b18d63aSmrg	    y -= orig_y;
741b18d63aSmrg	}
751b18d63aSmrg	else
761b18d63aSmrg	{
774f2886e8Smrg	    return 0.f;
781b18d63aSmrg	}
791b18d63aSmrg    }
80952204abSmrg
811b18d63aSmrg    bits = (uint8_t *)image->bits.bits;
82952204abSmrg
831b18d63aSmrg    if (image->bits.format == PIXMAN_a8)
841b18d63aSmrg    {
851b18d63aSmrg	r = bits[y * WIDTH + x];
864f2886e8Smrg	return r / 255.f;
871b18d63aSmrg    }
881b18d63aSmrg    else if (image->bits.format == PIXMAN_a2r10g10b10)
891b18d63aSmrg    {
901b18d63aSmrg	r = ((uint32_t *)bits)[y * WIDTH + x] >> 30;
914f2886e8Smrg	return r / 3.f;
921b18d63aSmrg    }
931b18d63aSmrg    else if (image->bits.format == PIXMAN_a8r8g8b8)
941b18d63aSmrg    {
951b18d63aSmrg	r = ((uint32_t *)bits)[y * WIDTH + x] >> 24;
964f2886e8Smrg	return r / 255.f;
971b18d63aSmrg    }
981b18d63aSmrg    else if (image->bits.format == PIXMAN_a4r4g4b4)
99952204abSmrg    {
1001b18d63aSmrg	r = ((uint16_t *)bits)[y * WIDTH + x] >> 12;
1014f2886e8Smrg	return r / 15.f;
1024f2886e8Smrg    }
1034f2886e8Smrg    else if (image->bits.format == PIXMAN_rgba_float)
1044f2886e8Smrg    {
1054f2886e8Smrg	return ((float *)bits)[y * WIDTH * 4 + x * 4 + 3];
1061b18d63aSmrg    }
1071b18d63aSmrg    else
1081b18d63aSmrg    {
1091b18d63aSmrg	assert (0);
1104f2886e8Smrg	return 0.f;
1111b18d63aSmrg    }
1121b18d63aSmrg}
113952204abSmrg
1149ad247e8Sjmcneillstatic uint16_t
1159ad247e8Sjmcneillget_red (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
1169ad247e8Sjmcneill{
1179ad247e8Sjmcneill    uint8_t *bits;
1189ad247e8Sjmcneill    uint16_t r;
1199ad247e8Sjmcneill
1209ad247e8Sjmcneill    bits = (uint8_t *)image->bits.bits;
1219ad247e8Sjmcneill
1229ad247e8Sjmcneill    if (image->bits.format == PIXMAN_a8)
1239ad247e8Sjmcneill    {
1249ad247e8Sjmcneill	r = 0x00;
1259ad247e8Sjmcneill    }
1269ad247e8Sjmcneill    else if (image->bits.format == PIXMAN_a2r10g10b10)
1279ad247e8Sjmcneill    {
1289ad247e8Sjmcneill	r = ((uint32_t *)bits)[y * WIDTH + x] >> 14;
1299ad247e8Sjmcneill	r &= 0xffc0;
1309ad247e8Sjmcneill	r |= (r >> 10);
1319ad247e8Sjmcneill    }
1329ad247e8Sjmcneill    else if (image->bits.format == PIXMAN_a8r8g8b8)
1339ad247e8Sjmcneill    {
1349ad247e8Sjmcneill	r = ((uint32_t *)bits)[y * WIDTH + x] >> 16;
1359ad247e8Sjmcneill	r &= 0xff;
1369ad247e8Sjmcneill	r |= r << 8;
1379ad247e8Sjmcneill    }
1389ad247e8Sjmcneill    else if (image->bits.format == PIXMAN_a4r4g4b4)
1399ad247e8Sjmcneill    {
1409ad247e8Sjmcneill	r = ((uint16_t *)bits)[y * WIDTH + x] >> 8;
1419ad247e8Sjmcneill	r &= 0xf;
1429ad247e8Sjmcneill	r |= r << 4;
1439ad247e8Sjmcneill	r |= r << 8;
1449ad247e8Sjmcneill    }
1454f2886e8Smrg    else if (image->bits.format == PIXMAN_rgba_float)
1464f2886e8Smrg    {
1474f2886e8Smrg	double tmp = ((float *)bits)[y * WIDTH * 4 + x * 4];
1484f2886e8Smrg	return tmp * 65535.;
1494f2886e8Smrg    }
1509ad247e8Sjmcneill    else
1519ad247e8Sjmcneill    {
1529ad247e8Sjmcneill	assert (0);
1539ad247e8Sjmcneill    }
1549ad247e8Sjmcneill
1559ad247e8Sjmcneill    return r;
1569ad247e8Sjmcneill}
157952204abSmrg
1584f2886e8Smrgstatic float get_alpha_err(pixman_format_code_t sf, pixman_format_code_t saf,
1594f2886e8Smrg			   pixman_format_code_t df, pixman_format_code_t daf)
1604f2886e8Smrg{
1614f2886e8Smrg	pixman_format_code_t s = saf != PIXMAN_null ? saf : sf;
1624f2886e8Smrg	pixman_format_code_t d = daf != PIXMAN_null ? daf : df;
1634f2886e8Smrg
1644f2886e8Smrg	/* There are cases where we go through the 8 bit compositing
1654f2886e8Smrg	 * path even with 10bpc and higher formats.
1664f2886e8Smrg	 */
1674f2886e8Smrg	if (PIXMAN_FORMAT_A(s) == PIXMAN_FORMAT_A(d))
1684f2886e8Smrg		return 1.f / 255.f;
1694f2886e8Smrg	else if (PIXMAN_FORMAT_A(s) > PIXMAN_FORMAT_A(d))
1704f2886e8Smrg		return 1.f / ((1 << PIXMAN_FORMAT_A(d)) - 1);
1714f2886e8Smrg	else
1724f2886e8Smrg		return 1.f / ((1 << PIXMAN_FORMAT_A(s)) - 1);
1734f2886e8Smrg}
1744f2886e8Smrg
1751b18d63aSmrgstatic int
1761b18d63aSmrgrun_test (int s, int d, int sa, int da, int soff, int doff)
1771b18d63aSmrg{
1781b18d63aSmrg    pixman_format_code_t sf = formats[s];
1791b18d63aSmrg    pixman_format_code_t df = formats[d];
1801b18d63aSmrg    pixman_format_code_t saf = alpha_formats[sa];
1811b18d63aSmrg    pixman_format_code_t daf = alpha_formats[da];
1829ad247e8Sjmcneill    pixman_image_t *src, *dst, *orig_dst, *alpha, *orig_alpha;
1831b18d63aSmrg    pixman_transform_t t1;
1841b18d63aSmrg    int j, k;
1854f2886e8Smrg    int n_red_bits;
1861b18d63aSmrg
1871b18d63aSmrg    soff = origins[soff];
1881b18d63aSmrg    doff = origins[doff];
1891b18d63aSmrg
1909ad247e8Sjmcneill    n_red_bits = PIXMAN_FORMAT_R (df);
1919ad247e8Sjmcneill
1929ad247e8Sjmcneill    /* Source */
1939ad247e8Sjmcneill    src = make_image (sf);
1949ad247e8Sjmcneill    if (saf != PIXMAN_null)
1959ad247e8Sjmcneill    {
1969ad247e8Sjmcneill	alpha = make_image (saf);
1979ad247e8Sjmcneill	pixman_image_set_alpha_map (src, alpha, soff, soff);
1989ad247e8Sjmcneill	pixman_image_unref (alpha);
1999ad247e8Sjmcneill    }
2009ad247e8Sjmcneill
2019ad247e8Sjmcneill    /* Destination */
2029ad247e8Sjmcneill    orig_dst = make_image (df);
2039ad247e8Sjmcneill    dst = make_image (df);
2049ad247e8Sjmcneill    pixman_image_composite (PIXMAN_OP_SRC, orig_dst, NULL, dst,
2059ad247e8Sjmcneill			    0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
2069ad247e8Sjmcneill
2079ad247e8Sjmcneill    if (daf != PIXMAN_null)
2089ad247e8Sjmcneill    {
2099ad247e8Sjmcneill	orig_alpha = make_image (daf);
2109ad247e8Sjmcneill	alpha = make_image (daf);
2119ad247e8Sjmcneill
2129ad247e8Sjmcneill	pixman_image_composite (PIXMAN_OP_SRC, orig_alpha, NULL, alpha,
2139ad247e8Sjmcneill				0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
2141b18d63aSmrg
2159ad247e8Sjmcneill	pixman_image_set_alpha_map (orig_dst, orig_alpha, doff, doff);
2169ad247e8Sjmcneill	pixman_image_set_alpha_map (dst, alpha, doff, doff);
2179ad247e8Sjmcneill
2189ad247e8Sjmcneill	pixman_image_unref (orig_alpha);
2199ad247e8Sjmcneill	pixman_image_unref (alpha);
2209ad247e8Sjmcneill    }
221952204abSmrg
222953d7d37Smrg    /* Transformations, repeats and filters on destinations should be ignored,
223953d7d37Smrg     * so just set some random ones.
2241b18d63aSmrg     */
2251b18d63aSmrg    pixman_transform_init_identity (&t1);
2261b18d63aSmrg    pixman_transform_scale (&t1, NULL, pixman_int_to_fixed (100), pixman_int_to_fixed (11));
2271b18d63aSmrg    pixman_transform_rotate (&t1, NULL, pixman_double_to_fixed (0.5), pixman_double_to_fixed (0.11));
2281b18d63aSmrg    pixman_transform_translate (&t1, NULL, pixman_int_to_fixed (11), pixman_int_to_fixed (17));
2291b18d63aSmrg
2301b18d63aSmrg    pixman_image_set_transform (dst, &t1);
231953d7d37Smrg    pixman_image_set_filter (dst, PIXMAN_FILTER_BILINEAR, NULL, 0);
232953d7d37Smrg    pixman_image_set_repeat (dst, PIXMAN_REPEAT_REFLECT);
2331b18d63aSmrg
2341b18d63aSmrg    pixman_image_composite (PIXMAN_OP_ADD, src, NULL, dst,
2351b18d63aSmrg			    0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
2361b18d63aSmrg
2371b18d63aSmrg    for (j = MAX (doff, 0); j < MIN (HEIGHT, HEIGHT + doff); ++j)
2381b18d63aSmrg    {
2391b18d63aSmrg	for (k = MAX (doff, 0); k < MIN (WIDTH, WIDTH + doff); ++k)
240952204abSmrg	{
2414f2886e8Smrg	    float sa, da, oda, refa;
2429ad247e8Sjmcneill	    uint16_t sr, dr, odr, refr;
2434f2886e8Smrg	    float err;
2444f2886e8Smrg
2454f2886e8Smrg	    err = get_alpha_err(sf, saf, df, daf);
2461b18d63aSmrg
2471b18d63aSmrg	    sa = get_alpha (src, k, j, soff, soff);
2481b18d63aSmrg	    da = get_alpha (dst, k, j, doff, doff);
2491b18d63aSmrg	    oda = get_alpha (orig_dst, k, j, doff, doff);
2501b18d63aSmrg
2514f2886e8Smrg	    if (sa + oda > 1.f)
2524f2886e8Smrg		refa = 1.f;
2531b18d63aSmrg	    else
2549ad247e8Sjmcneill		refa = sa + oda;
2551b18d63aSmrg
2564f2886e8Smrg	    if (da - err > refa ||
2574f2886e8Smrg	        da + err < refa)
258952204abSmrg	    {
2594f2886e8Smrg		printf ("\nWrong alpha value at (%d, %d). Should be %g; got %g. Source was %g, original dest was %g\n",
2609ad247e8Sjmcneill			k, j, refa, da, sa, oda);
2611b18d63aSmrg
2621b18d63aSmrg		printf ("src: %s, alpha: %s, origin %d %d\ndst: %s, alpha: %s, origin: %d %d\n\n",
2631b18d63aSmrg			format_name (sf),
2641b18d63aSmrg			format_name (saf),
2651b18d63aSmrg			soff, soff,
2661b18d63aSmrg			format_name (df),
2671b18d63aSmrg			format_name (daf),
2681b18d63aSmrg			doff, doff);
2691b18d63aSmrg		return 1;
2701b18d63aSmrg	    }
2719ad247e8Sjmcneill
2729ad247e8Sjmcneill	    /* There are cases where we go through the 8 bit compositing
2739ad247e8Sjmcneill	     * path even with 10bpc formats. This results in incorrect
2749ad247e8Sjmcneill	     * results here, so only do the red check for narrow formats
2759ad247e8Sjmcneill	     */
2769ad247e8Sjmcneill	    if (n_red_bits <= 8)
2779ad247e8Sjmcneill	    {
2789ad247e8Sjmcneill		sr = get_red (src, k, j, soff, soff);
2799ad247e8Sjmcneill		dr = get_red (dst, k, j, doff, doff);
2809ad247e8Sjmcneill		odr = get_red (orig_dst, k, j, doff, doff);
2819ad247e8Sjmcneill
2829ad247e8Sjmcneill		if (sr + odr > 0xffff)
2839ad247e8Sjmcneill		    refr = 0xffff;
2849ad247e8Sjmcneill		else
2859ad247e8Sjmcneill		    refr = sr + odr;
2869ad247e8Sjmcneill
2879ad247e8Sjmcneill		if (abs ((dr >> (16 - n_red_bits)) - (refr >> (16 - n_red_bits))) > 1)
2889ad247e8Sjmcneill		{
2899ad247e8Sjmcneill		    printf ("%d red bits\n", n_red_bits);
2909ad247e8Sjmcneill		    printf ("\nWrong red value at (%d, %d). Should be 0x%x; got 0x%x. Source was 0x%x, original dest was 0x%x\n",
2919ad247e8Sjmcneill			    k, j, refr, dr, sr, odr);
2929ad247e8Sjmcneill
2939ad247e8Sjmcneill		    printf ("src: %s, alpha: %s, origin %d %d\ndst: %s, alpha: %s, origin: %d %d\n\n",
2949ad247e8Sjmcneill			    format_name (sf),
2959ad247e8Sjmcneill			    format_name (saf),
2969ad247e8Sjmcneill			    soff, soff,
2979ad247e8Sjmcneill			    format_name (df),
2989ad247e8Sjmcneill			    format_name (daf),
2999ad247e8Sjmcneill			    doff, doff);
3009ad247e8Sjmcneill		    return 1;
3019ad247e8Sjmcneill		}
3029ad247e8Sjmcneill	    }
3031b18d63aSmrg	}
3041b18d63aSmrg    }
3051b18d63aSmrg
3061b18d63aSmrg    pixman_image_set_alpha_map (src, NULL, 0, 0);
3071b18d63aSmrg    pixman_image_set_alpha_map (dst, NULL, 0, 0);
3081b18d63aSmrg    pixman_image_set_alpha_map (orig_dst, NULL, 0, 0);
3091b18d63aSmrg
3101b18d63aSmrg    pixman_image_unref (src);
3111b18d63aSmrg    pixman_image_unref (dst);
3121b18d63aSmrg    pixman_image_unref (orig_dst);
3131b18d63aSmrg
3141b18d63aSmrg    return 0;
3151b18d63aSmrg}
3161b18d63aSmrg
3171b18d63aSmrgint
3181b18d63aSmrgmain (int argc, char **argv)
3191b18d63aSmrg{
3201b18d63aSmrg    int i, j, a, b, x, y;
321952204abSmrg
322f4f78bb6Smrg    prng_srand (0);
323f4f78bb6Smrg
3241b18d63aSmrg    for (i = 0; i < ARRAY_LENGTH (formats); ++i)
3251b18d63aSmrg    {
3261b18d63aSmrg	for (j = 0; j < ARRAY_LENGTH (formats); ++j)
3271b18d63aSmrg	{
3281b18d63aSmrg	    for (a = 0; a < ARRAY_LENGTH (alpha_formats); ++a)
3291b18d63aSmrg	    {
3301b18d63aSmrg		for (b = 0; b < ARRAY_LENGTH (alpha_formats); ++b)
331952204abSmrg		{
3321b18d63aSmrg		    for (x = 0; x < ARRAY_LENGTH (origins); ++x)
3331b18d63aSmrg		    {
3341b18d63aSmrg			for (y = 0; y < ARRAY_LENGTH (origins); ++y)
3351b18d63aSmrg			{
3361b18d63aSmrg			    if (run_test (i, j, a, b, x, y) != 0)
3371b18d63aSmrg				return 1;
3381b18d63aSmrg			}
3391b18d63aSmrg		    }
340952204abSmrg		}
341952204abSmrg	    }
342952204abSmrg	}
343952204abSmrg    }
344952204abSmrg
345952204abSmrg    return 0;
346952204abSmrg}
347