16ca29ff0Smrg#include <assert.h>
26ca29ff0Smrg#include <stdlib.h>
36ca29ff0Smrg#include <stdio.h>
46ca29ff0Smrg#include <float.h>
56ca29ff0Smrg#include <math.h>
66ca29ff0Smrg#include "utils.h"
76ca29ff0Smrg
86ca29ff0Smrg#define MAX_WIDTH  16
96ca29ff0Smrg#define MAX_HEIGHT 16
106ca29ff0Smrg#define MAX_STRIDE 4
116ca29ff0Smrg
126ca29ff0Smrgstatic const pixman_format_code_t formats[] =
136ca29ff0Smrg{
146ca29ff0Smrg    PIXMAN_a2r10g10b10,
156ca29ff0Smrg    PIXMAN_x2r10g10b10,
166ca29ff0Smrg    PIXMAN_a8r8g8b8,
176ca29ff0Smrg    PIXMAN_a4r4g4b4,
186ca29ff0Smrg    PIXMAN_a2r2g2b2,
196ca29ff0Smrg    PIXMAN_r5g6b5,
206ca29ff0Smrg    PIXMAN_r3g3b2,
216ca29ff0Smrg};
226ca29ff0Smrg
236ca29ff0Smrgstatic const pixman_op_t operators[] =
246ca29ff0Smrg{
256ca29ff0Smrg    PIXMAN_OP_CLEAR,
266ca29ff0Smrg    PIXMAN_OP_SRC,
276ca29ff0Smrg    PIXMAN_OP_DST,
286ca29ff0Smrg    PIXMAN_OP_OVER,
296ca29ff0Smrg    PIXMAN_OP_OVER_REVERSE,
306ca29ff0Smrg    PIXMAN_OP_IN,
316ca29ff0Smrg    PIXMAN_OP_IN_REVERSE,
326ca29ff0Smrg    PIXMAN_OP_OUT,
336ca29ff0Smrg    PIXMAN_OP_OUT_REVERSE,
346ca29ff0Smrg    PIXMAN_OP_ATOP,
356ca29ff0Smrg    PIXMAN_OP_ATOP_REVERSE,
366ca29ff0Smrg    PIXMAN_OP_XOR,
376ca29ff0Smrg    PIXMAN_OP_ADD,
386ca29ff0Smrg    PIXMAN_OP_SATURATE,
396ca29ff0Smrg
406ca29ff0Smrg    PIXMAN_OP_DISJOINT_CLEAR,
416ca29ff0Smrg    PIXMAN_OP_DISJOINT_SRC,
426ca29ff0Smrg    PIXMAN_OP_DISJOINT_DST,
436ca29ff0Smrg    PIXMAN_OP_DISJOINT_OVER,
446ca29ff0Smrg    PIXMAN_OP_DISJOINT_OVER_REVERSE,
456ca29ff0Smrg    PIXMAN_OP_DISJOINT_IN,
466ca29ff0Smrg    PIXMAN_OP_DISJOINT_IN_REVERSE,
476ca29ff0Smrg    PIXMAN_OP_DISJOINT_OUT,
486ca29ff0Smrg    PIXMAN_OP_DISJOINT_OUT_REVERSE,
496ca29ff0Smrg    PIXMAN_OP_DISJOINT_ATOP,
506ca29ff0Smrg    PIXMAN_OP_DISJOINT_ATOP_REVERSE,
516ca29ff0Smrg    PIXMAN_OP_DISJOINT_XOR,
526ca29ff0Smrg
536ca29ff0Smrg    PIXMAN_OP_CONJOINT_CLEAR,
546ca29ff0Smrg    PIXMAN_OP_CONJOINT_SRC,
556ca29ff0Smrg    PIXMAN_OP_CONJOINT_DST,
566ca29ff0Smrg    PIXMAN_OP_CONJOINT_OVER,
576ca29ff0Smrg    PIXMAN_OP_CONJOINT_OVER_REVERSE,
586ca29ff0Smrg    PIXMAN_OP_CONJOINT_IN,
596ca29ff0Smrg    PIXMAN_OP_CONJOINT_IN_REVERSE,
606ca29ff0Smrg    PIXMAN_OP_CONJOINT_OUT,
616ca29ff0Smrg    PIXMAN_OP_CONJOINT_OUT_REVERSE,
626ca29ff0Smrg    PIXMAN_OP_CONJOINT_ATOP,
636ca29ff0Smrg    PIXMAN_OP_CONJOINT_ATOP_REVERSE,
646ca29ff0Smrg    PIXMAN_OP_CONJOINT_XOR,
656ca29ff0Smrg
666ca29ff0Smrg    PIXMAN_OP_MULTIPLY,
676ca29ff0Smrg    PIXMAN_OP_SCREEN,
686ca29ff0Smrg    PIXMAN_OP_OVERLAY,
696ca29ff0Smrg    PIXMAN_OP_DARKEN,
706ca29ff0Smrg    PIXMAN_OP_LIGHTEN,
716ca29ff0Smrg    PIXMAN_OP_COLOR_DODGE,
726ca29ff0Smrg    PIXMAN_OP_COLOR_BURN,
736ca29ff0Smrg    PIXMAN_OP_HARD_LIGHT,
746ca29ff0Smrg    PIXMAN_OP_SOFT_LIGHT,
756ca29ff0Smrg    PIXMAN_OP_DIFFERENCE,
766ca29ff0Smrg    PIXMAN_OP_EXCLUSION,
776ca29ff0Smrg};
786ca29ff0Smrg
7914b11b2bSmrgstatic const pixman_dither_t dithers[] =
8014b11b2bSmrg{
8114b11b2bSmrg    PIXMAN_DITHER_ORDERED_BAYER_8,
8214b11b2bSmrg    PIXMAN_DITHER_ORDERED_BLUE_NOISE_64,
8314b11b2bSmrg};
8414b11b2bSmrg
856ca29ff0Smrg#define RANDOM_ELT(array)                                               \
866ca29ff0Smrg    (array[prng_rand_n (ARRAY_LENGTH (array))])
876ca29ff0Smrg
886ca29ff0Smrgstatic void
896ca29ff0Smrgfree_bits (pixman_image_t *image, void *data)
906ca29ff0Smrg{
916ca29ff0Smrg    free (image->bits.bits);
926ca29ff0Smrg}
936ca29ff0Smrg
946ca29ff0Smrgstatic pixman_image_t *
956ca29ff0Smrgcreate_image (pixman_image_t **clone)
966ca29ff0Smrg{
976ca29ff0Smrg    pixman_format_code_t format = RANDOM_ELT (formats);
986ca29ff0Smrg    pixman_image_t *image;
996ca29ff0Smrg    int width = prng_rand_n (MAX_WIDTH);
1006ca29ff0Smrg    int height = prng_rand_n (MAX_HEIGHT);
1016ca29ff0Smrg    int stride = ((width * (PIXMAN_FORMAT_BPP (format) / 8)) + 3) & ~3;
1026ca29ff0Smrg    uint32_t *bytes = malloc (stride * height);
1036ca29ff0Smrg
1046ca29ff0Smrg    prng_randmemset (bytes, stride * height, RANDMEMSET_MORE_00_AND_FF);
1056ca29ff0Smrg
1066ca29ff0Smrg    image = pixman_image_create_bits (
1076ca29ff0Smrg        format, width, height, bytes, stride);
1086ca29ff0Smrg
1096ca29ff0Smrg    pixman_image_set_destroy_function (image, free_bits, NULL);
1106ca29ff0Smrg
1116ca29ff0Smrg    assert (image);
1126ca29ff0Smrg
1136ca29ff0Smrg    if (clone)
1146ca29ff0Smrg    {
1156ca29ff0Smrg        uint32_t *bytes_dup = malloc (stride * height);
1166ca29ff0Smrg
1176ca29ff0Smrg        memcpy (bytes_dup, bytes, stride * height);
1186ca29ff0Smrg
1196ca29ff0Smrg        *clone = pixman_image_create_bits (
1206ca29ff0Smrg            format, width, height, bytes_dup, stride);
1216ca29ff0Smrg
1226ca29ff0Smrg        pixman_image_set_destroy_function (*clone, free_bits, NULL);
1236ca29ff0Smrg    }
1246ca29ff0Smrg
1256ca29ff0Smrg    return image;
1266ca29ff0Smrg}
1276ca29ff0Smrg
1286ca29ff0Smrgstatic pixman_bool_t
1296ca29ff0Smrgaccess (pixman_image_t *image, int x, int y, uint32_t *pixel)
1306ca29ff0Smrg{
1316ca29ff0Smrg    int bytes_per_pixel;
1326ca29ff0Smrg    int stride;
1336ca29ff0Smrg    uint8_t *location;
1346ca29ff0Smrg
1356ca29ff0Smrg    if (x < 0 || x >= image->bits.width || y < 0 || y >= image->bits.height)
1366ca29ff0Smrg        return FALSE;
1376ca29ff0Smrg
1386ca29ff0Smrg    bytes_per_pixel = PIXMAN_FORMAT_BPP (image->bits.format) / 8;
1396ca29ff0Smrg    stride = image->bits.rowstride * 4;
1406ca29ff0Smrg
1416ca29ff0Smrg    location = (uint8_t *)image->bits.bits + y * stride + x * bytes_per_pixel;
1426ca29ff0Smrg
1436ca29ff0Smrg    if (bytes_per_pixel == 4)
1446ca29ff0Smrg        *pixel = *(uint32_t *)location;
1456ca29ff0Smrg    else if (bytes_per_pixel == 2)
1466ca29ff0Smrg        *pixel = *(uint16_t *)location;
1476ca29ff0Smrg    else if (bytes_per_pixel == 1)
1486ca29ff0Smrg        *pixel = *(uint8_t *)location;
1496ca29ff0Smrg    else
1506ca29ff0Smrg	assert (0);
1516ca29ff0Smrg
1526ca29ff0Smrg    return TRUE;
1536ca29ff0Smrg}
1546ca29ff0Smrg
1556ca29ff0Smrgstatic void
1566ca29ff0Smrgget_color (pixel_checker_t *checker,
1576ca29ff0Smrg	   pixman_image_t *image,
1586ca29ff0Smrg	   int x, int y,
1596ca29ff0Smrg	   color_t *color,
1606ca29ff0Smrg	   uint32_t *pixel)
1616ca29ff0Smrg{
1626ca29ff0Smrg    if (!access (image, x, y, pixel))
1636ca29ff0Smrg    {
1646ca29ff0Smrg	color->a = 0.0;
1656ca29ff0Smrg	color->r = 0.0;
1666ca29ff0Smrg	color->g = 0.0;
1676ca29ff0Smrg	color->b = 0.0;
1686ca29ff0Smrg    }
1696ca29ff0Smrg    else
1706ca29ff0Smrg    {
1716ca29ff0Smrg	pixel_checker_convert_pixel_to_color (
1726ca29ff0Smrg	    checker, *pixel, color);
1736ca29ff0Smrg    }
1746ca29ff0Smrg}
1756ca29ff0Smrg
1766ca29ff0Smrgstatic pixman_bool_t
1776ca29ff0Smrgverify (int test_no,
1786ca29ff0Smrg        pixman_op_t op,
1796ca29ff0Smrg        pixman_image_t *source,
1806ca29ff0Smrg	pixman_image_t *mask,
1816ca29ff0Smrg        pixman_image_t *dest,
1826ca29ff0Smrg        pixman_image_t *orig_dest,
1836ca29ff0Smrg        int x, int y,
1846ca29ff0Smrg        int width, int height,
18514b11b2bSmrg	pixman_bool_t component_alpha,
18614b11b2bSmrg	pixman_dither_t dither)
1876ca29ff0Smrg{
1886ca29ff0Smrg    pixel_checker_t dest_checker, src_checker, mask_checker;
1896ca29ff0Smrg    int i, j;
1906ca29ff0Smrg
1916ca29ff0Smrg    pixel_checker_init (&src_checker, source->bits.format);
1926ca29ff0Smrg    pixel_checker_init (&dest_checker, dest->bits.format);
1936ca29ff0Smrg    pixel_checker_init (&mask_checker, mask->bits.format);
1946ca29ff0Smrg
19514b11b2bSmrg    if (dest->bits.dither != PIXMAN_DITHER_NONE)
19614b11b2bSmrg	pixel_checker_allow_dither (&dest_checker);
19714b11b2bSmrg
1986ca29ff0Smrg    assert (dest->bits.format == orig_dest->bits.format);
1996ca29ff0Smrg
2006ca29ff0Smrg    for (j = y; j < y + height; ++j)
2016ca29ff0Smrg    {
2026ca29ff0Smrg        for (i = x; i < x + width; ++i)
2036ca29ff0Smrg        {
2046ca29ff0Smrg            color_t src_color, mask_color, orig_dest_color, result;
2056ca29ff0Smrg            uint32_t dest_pixel, orig_dest_pixel, src_pixel, mask_pixel;
2066ca29ff0Smrg
2076ca29ff0Smrg            access (dest, i, j, &dest_pixel);
2086ca29ff0Smrg
2096ca29ff0Smrg	    get_color (&src_checker,
2106ca29ff0Smrg		       source, i - x, j - y,
2116ca29ff0Smrg		       &src_color, &src_pixel);
2126ca29ff0Smrg
2136ca29ff0Smrg	    get_color (&mask_checker,
2146ca29ff0Smrg		       mask, i - x, j - y,
2156ca29ff0Smrg		       &mask_color, &mask_pixel);
2166ca29ff0Smrg
2176ca29ff0Smrg	    get_color (&dest_checker,
2186ca29ff0Smrg		       orig_dest, i, j,
2196ca29ff0Smrg		       &orig_dest_color, &orig_dest_pixel);
2206ca29ff0Smrg
2216ca29ff0Smrg	    do_composite (op,
2226ca29ff0Smrg			  &src_color, &mask_color, &orig_dest_color,
2236ca29ff0Smrg			  &result, component_alpha);
2246ca29ff0Smrg
2256ca29ff0Smrg            if (!pixel_checker_check (&dest_checker, dest_pixel, &result))
2266ca29ff0Smrg            {
2276ca29ff0Smrg                int a, r, g, b;
2286ca29ff0Smrg
2296ca29ff0Smrg                printf ("--------- Test 0x%x failed ---------\n", test_no);
2306ca29ff0Smrg
2316ca29ff0Smrg                printf ("   operator:         %s (%s alpha)\n", operator_name (op),
2326ca29ff0Smrg			component_alpha? "component" : "unified");
23314b11b2bSmrg		printf ("   dither:           %s\n", dither_name (dither));
2346ca29ff0Smrg                printf ("   dest_x, dest_y:   %d %d\n", x, y);
2356ca29ff0Smrg                printf ("   width, height:    %d %d\n", width, height);
2366ca29ff0Smrg                printf ("   source:           format: %-14s  size: %2d x %2d\n",
2376ca29ff0Smrg                        format_name (source->bits.format),
2386ca29ff0Smrg			source->bits.width, source->bits.height);
2396ca29ff0Smrg                printf ("   mask:             format: %-14s  size: %2d x %2d\n",
2406ca29ff0Smrg                        format_name (mask->bits.format),
2416ca29ff0Smrg			mask->bits.width, mask->bits.height);
2426ca29ff0Smrg                printf ("   dest:             format: %-14s  size: %2d x %2d\n",
2436ca29ff0Smrg                        format_name (dest->bits.format),
2446ca29ff0Smrg			dest->bits.width, dest->bits.height);
2456ca29ff0Smrg                printf ("   -- Failed pixel: (%d, %d) --\n", i, j);
2466ca29ff0Smrg                printf ("   source ARGB:      %f  %f  %f  %f   (pixel: %x)\n",
2476ca29ff0Smrg                        src_color.a, src_color.r, src_color.g, src_color.b,
2486ca29ff0Smrg                        src_pixel);
2496ca29ff0Smrg                printf ("   mask ARGB:        %f  %f  %f  %f   (pixel: %x)\n",
2506ca29ff0Smrg                        mask_color.a, mask_color.r, mask_color.g, mask_color.b,
2516ca29ff0Smrg                        mask_pixel);
2526ca29ff0Smrg                printf ("   dest ARGB:        %f  %f  %f  %f   (pixel: %x)\n",
2536ca29ff0Smrg                        orig_dest_color.a, orig_dest_color.r, orig_dest_color.g, orig_dest_color.b,
2546ca29ff0Smrg                        orig_dest_pixel);
2556ca29ff0Smrg                printf ("   expected ARGB:    %f  %f  %f  %f\n",
2566ca29ff0Smrg                        result.a, result.r, result.g, result.b);
2576ca29ff0Smrg
2586ca29ff0Smrg                pixel_checker_get_min (&dest_checker, &result, &a, &r, &g, &b);
2596ca29ff0Smrg                printf ("   min acceptable:   %8d  %8d  %8d  %8d\n", a, r, g, b);
2606ca29ff0Smrg
2616ca29ff0Smrg                pixel_checker_split_pixel (&dest_checker, dest_pixel, &a, &r, &g, &b);
2626ca29ff0Smrg                printf ("   got:              %8d  %8d  %8d  %8d   (pixel: %x)\n", a, r, g, b, dest_pixel);
2636ca29ff0Smrg
2646ca29ff0Smrg                pixel_checker_get_max (&dest_checker, &result, &a, &r, &g, &b);
2656ca29ff0Smrg                printf ("   max acceptable:   %8d  %8d  %8d  %8d\n", a, r, g, b);
2666ca29ff0Smrg		printf ("\n");
2676ca29ff0Smrg		printf ("    { %s,\n", operator_name (op));
2686ca29ff0Smrg		printf ("      PIXMAN_%s,\t0x%x,\n", format_name (source->bits.format), src_pixel);
2696ca29ff0Smrg		printf ("      PIXMAN_%s,\t0x%x,\n", format_name (mask->bits.format), mask_pixel);
2706ca29ff0Smrg		printf ("      PIXMAN_%s,\t0x%x\n", format_name (dest->bits.format), orig_dest_pixel);
2716ca29ff0Smrg		printf ("    },\n");
2726ca29ff0Smrg                return FALSE;
2736ca29ff0Smrg            }
2746ca29ff0Smrg        }
2756ca29ff0Smrg    }
2766ca29ff0Smrg
2776ca29ff0Smrg    return TRUE;
2786ca29ff0Smrg}
2796ca29ff0Smrg
2806ca29ff0Smrgstatic pixman_bool_t
2816ca29ff0Smrgdo_check (int i)
2826ca29ff0Smrg{
2836ca29ff0Smrg    pixman_image_t *source, *dest, *mask;
2846ca29ff0Smrg    pixman_op_t op;
2856ca29ff0Smrg    int x, y, width, height;
2866ca29ff0Smrg    pixman_image_t *dest_copy;
2876ca29ff0Smrg    pixman_bool_t result = TRUE;
2886ca29ff0Smrg    pixman_bool_t component_alpha;
28914b11b2bSmrg    pixman_dither_t dither = PIXMAN_DITHER_NONE;
2906ca29ff0Smrg
2916ca29ff0Smrg    prng_srand (i);
2926ca29ff0Smrg    op = RANDOM_ELT (operators);
2936ca29ff0Smrg    x = prng_rand_n (MAX_WIDTH);
2946ca29ff0Smrg    y = prng_rand_n (MAX_HEIGHT);
2956ca29ff0Smrg    width = prng_rand_n (MAX_WIDTH) + 4;
2966ca29ff0Smrg    height = prng_rand_n (MAX_HEIGHT) + 4;
2976ca29ff0Smrg
2986ca29ff0Smrg    source = create_image (NULL);
2996ca29ff0Smrg    mask = create_image (NULL);
3006ca29ff0Smrg    dest = create_image (&dest_copy);
3016ca29ff0Smrg
3026ca29ff0Smrg    if (x >= dest->bits.width)
3036ca29ff0Smrg        x = dest->bits.width / 2;
3046ca29ff0Smrg    if (y >= dest->bits.height)
3056ca29ff0Smrg        y = dest->bits.height / 2;
3066ca29ff0Smrg    if (x + width > dest->bits.width)
3076ca29ff0Smrg        width = dest->bits.width - x;
3086ca29ff0Smrg    if (y + height > dest->bits.height)
3096ca29ff0Smrg        height = dest->bits.height - y;
3106ca29ff0Smrg
31114b11b2bSmrg    if (prng_rand_n (2))
31214b11b2bSmrg    {
31314b11b2bSmrg	dither = RANDOM_ELT (dithers);
31414b11b2bSmrg	pixman_image_set_dither (dest, dither);
31514b11b2bSmrg    }
31614b11b2bSmrg
3176ca29ff0Smrg    component_alpha = prng_rand_n (2);
3186ca29ff0Smrg
3196ca29ff0Smrg    pixman_image_set_component_alpha (mask, component_alpha);
3206ca29ff0Smrg
3216ca29ff0Smrg    pixman_image_composite32 (op, source, mask, dest,
3226ca29ff0Smrg                              0, 0, 0, 0,
3236ca29ff0Smrg                              x, y, width, height);
3246ca29ff0Smrg
3256ca29ff0Smrg    if (!verify (i, op, source, mask, dest, dest_copy,
32614b11b2bSmrg		 x, y, width, height, component_alpha,
32714b11b2bSmrg	         dither))
3286ca29ff0Smrg    {
3296ca29ff0Smrg	result = FALSE;
3306ca29ff0Smrg    }
3316ca29ff0Smrg
3326ca29ff0Smrg    pixman_image_unref (source);
3336ca29ff0Smrg    pixman_image_unref (mask);
3346ca29ff0Smrg    pixman_image_unref (dest);
3356ca29ff0Smrg    pixman_image_unref (dest_copy);
3366ca29ff0Smrg
3376ca29ff0Smrg    return result;
3386ca29ff0Smrg}
3396ca29ff0Smrg
3406ca29ff0Smrg#define N_TESTS    10000000
3416ca29ff0Smrg
3426ca29ff0Smrgint
3436ca29ff0Smrgmain (int argc, const char *argv[])
3446ca29ff0Smrg{
3456ca29ff0Smrg    int i;
3466ca29ff0Smrg    int result = 0;
3476ca29ff0Smrg
3486ca29ff0Smrg    if (argc == 2)
3496ca29ff0Smrg    {
3506ca29ff0Smrg	if (strcmp (argv[1], "--forever") == 0)
3516ca29ff0Smrg	{
3526ca29ff0Smrg	    uint32_t n;
3536ca29ff0Smrg
3546ca29ff0Smrg	    prng_srand (time (0));
3556ca29ff0Smrg
3566ca29ff0Smrg	    n = prng_rand();
3576ca29ff0Smrg
3586ca29ff0Smrg	    for (;;)
3596ca29ff0Smrg		do_check (n++);
3606ca29ff0Smrg	}
3616ca29ff0Smrg        else
3626ca29ff0Smrg	{
3636ca29ff0Smrg	    do_check (strtol (argv[1], NULL, 0));
3646ca29ff0Smrg	}
3656ca29ff0Smrg    }
3666ca29ff0Smrg    else
3676ca29ff0Smrg    {
3686ca29ff0Smrg#ifdef USE_OPENMP
3696ca29ff0Smrg#       pragma omp parallel for default(none) reduction(|:result)
3706ca29ff0Smrg#endif
3716ca29ff0Smrg        for (i = 0; i < N_TESTS; ++i)
3726ca29ff0Smrg	{
3736ca29ff0Smrg	    if (!do_check (i))
3746ca29ff0Smrg		result |= 1;
3756ca29ff0Smrg	}
3766ca29ff0Smrg    }
3776ca29ff0Smrg
3786ca29ff0Smrg    return result;
3796ca29ff0Smrg}
380