diff options
Diffstat (limited to 'qemu/pixman/test/composite.c')
-rw-r--r-- | qemu/pixman/test/composite.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/qemu/pixman/test/composite.c b/qemu/pixman/test/composite.c new file mode 100644 index 000000000..9e51a8f65 --- /dev/null +++ b/qemu/pixman/test/composite.c @@ -0,0 +1,536 @@ +/* + * Copyright © 2005 Eric Anholt + * Copyright © 2009 Chris Wilson + * Copyright © 2010 Soeren Sandmann + * Copyright © 2010 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Eric Anholt not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Eric Anholt makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include <stdio.h> +#include <stdlib.h> /* abort() */ +#include <math.h> +#include <time.h> +#include "utils.h" + +typedef struct image_t image_t; + +static const color_t colors[] = +{ + { 1.0, 1.0, 1.0, 1.0 }, + { 1.0, 1.0, 1.0, 0.0 }, + { 0.0, 0.0, 0.0, 1.0 }, + { 0.0, 0.0, 0.0, 0.0 }, + { 1.0, 0.0, 0.0, 1.0 }, + { 0.0, 1.0, 0.0, 1.0 }, + { 0.0, 0.0, 1.0, 1.0 }, + { 0.5, 0.0, 0.0, 0.5 }, +}; + +static uint16_t +_color_double_to_short (double d) +{ + uint32_t i; + + i = (uint32_t) (d * 65536); + i -= (i >> 16); + + return i; +} + +static void +compute_pixman_color (const color_t *color, + pixman_color_t *out) +{ + out->red = _color_double_to_short (color->r); + out->green = _color_double_to_short (color->g); + out->blue = _color_double_to_short (color->b); + out->alpha = _color_double_to_short (color->a); +} + +#define REPEAT 0x01000000 +#define FLAGS 0xff000000 + +static const int sizes[] = +{ + 0, + 1, + 1 | REPEAT, + 10 +}; + +static const pixman_format_code_t formats[] = +{ + /* 32 bpp formats */ + PIXMAN_a8r8g8b8, + PIXMAN_x8r8g8b8, + PIXMAN_a8b8g8r8, + PIXMAN_x8b8g8r8, + PIXMAN_b8g8r8a8, + PIXMAN_b8g8r8x8, + PIXMAN_r8g8b8a8, + PIXMAN_r8g8b8x8, + PIXMAN_x2r10g10b10, + PIXMAN_x2b10g10r10, + PIXMAN_a2r10g10b10, + PIXMAN_a2b10g10r10, + + /* sRGB formats */ + PIXMAN_a8r8g8b8_sRGB, + + /* 24 bpp formats */ + PIXMAN_r8g8b8, + PIXMAN_b8g8r8, + PIXMAN_r5g6b5, + PIXMAN_b5g6r5, + + /* 16 bpp formats */ + PIXMAN_x1r5g5b5, + PIXMAN_x1b5g5r5, + PIXMAN_a1r5g5b5, + PIXMAN_a1b5g5r5, + PIXMAN_a4b4g4r4, + PIXMAN_x4b4g4r4, + PIXMAN_a4r4g4b4, + PIXMAN_x4r4g4b4, + + /* 8 bpp formats */ + PIXMAN_a8, + PIXMAN_r3g3b2, + PIXMAN_b2g3r3, + PIXMAN_a2r2g2b2, + PIXMAN_a2b2g2r2, + PIXMAN_x4a4, + + /* 4 bpp formats */ + PIXMAN_a4, + PIXMAN_r1g2b1, + PIXMAN_b1g2r1, + PIXMAN_a1r1g1b1, + PIXMAN_a1b1g1r1, + + /* 1 bpp formats */ + PIXMAN_a1, +}; + +struct image_t +{ + pixman_image_t *image; + pixman_format_code_t format; + const color_t *color; + pixman_repeat_t repeat; + int size; +}; + +static const pixman_op_t operators[] = +{ + PIXMAN_OP_CLEAR, + PIXMAN_OP_SRC, + PIXMAN_OP_DST, + PIXMAN_OP_OVER, + PIXMAN_OP_OVER_REVERSE, + PIXMAN_OP_IN, + PIXMAN_OP_IN_REVERSE, + PIXMAN_OP_OUT, + PIXMAN_OP_OUT_REVERSE, + PIXMAN_OP_ATOP, + PIXMAN_OP_ATOP_REVERSE, + PIXMAN_OP_XOR, + PIXMAN_OP_ADD, + PIXMAN_OP_SATURATE, + + PIXMAN_OP_DISJOINT_CLEAR, + PIXMAN_OP_DISJOINT_SRC, + PIXMAN_OP_DISJOINT_DST, + PIXMAN_OP_DISJOINT_OVER, + PIXMAN_OP_DISJOINT_OVER_REVERSE, + PIXMAN_OP_DISJOINT_IN, + PIXMAN_OP_DISJOINT_IN_REVERSE, + PIXMAN_OP_DISJOINT_OUT, + PIXMAN_OP_DISJOINT_OUT_REVERSE, + PIXMAN_OP_DISJOINT_ATOP, + PIXMAN_OP_DISJOINT_ATOP_REVERSE, + PIXMAN_OP_DISJOINT_XOR, + + PIXMAN_OP_CONJOINT_CLEAR, + PIXMAN_OP_CONJOINT_SRC, + PIXMAN_OP_CONJOINT_DST, + PIXMAN_OP_CONJOINT_OVER, + PIXMAN_OP_CONJOINT_OVER_REVERSE, + PIXMAN_OP_CONJOINT_IN, + PIXMAN_OP_CONJOINT_IN_REVERSE, + PIXMAN_OP_CONJOINT_OUT, + PIXMAN_OP_CONJOINT_OUT_REVERSE, + PIXMAN_OP_CONJOINT_ATOP, + PIXMAN_OP_CONJOINT_ATOP_REVERSE, + PIXMAN_OP_CONJOINT_XOR, +}; + +static uint32_t +get_value (pixman_image_t *image) +{ + uint32_t value = *(uint32_t *)pixman_image_get_data (image); + +#ifdef WORDS_BIGENDIAN + { + pixman_format_code_t format = pixman_image_get_format (image); + value >>= 8 * sizeof(value) - PIXMAN_FORMAT_BPP (format); + } +#endif + + return value; +} + +static char * +describe_image (image_t *info, char *buf) +{ + if (info->size) + { + sprintf (buf, "%s, %dx%d%s", + format_name (info->format), + info->size, info->size, + info->repeat ? " R" :""); + } + else + { + sprintf (buf, "solid"); + } + + return buf; +} + +static char * +describe_color (const color_t *color, char *buf) +{ + sprintf (buf, "%.3f %.3f %.3f %.3f", + color->r, color->g, color->b, color->a); + + return buf; +} + +static pixman_bool_t +composite_test (image_t *dst, + pixman_op_t op, + image_t *src, + image_t *mask, + pixman_bool_t component_alpha, + int testno) +{ + color_t expected, tdst, tsrc, tmsk; + pixel_checker_t checker; + + if (mask) + { + pixman_image_set_component_alpha (mask->image, component_alpha); + + pixman_image_composite (op, src->image, mask->image, dst->image, + 0, 0, 0, 0, 0, 0, dst->size, dst->size); + } + else + { + pixman_image_composite (op, src->image, NULL, dst->image, + 0, 0, + 0, 0, + 0, 0, + dst->size, dst->size); + } + + tdst = *dst->color; + tsrc = *src->color; + + if (mask) + { + tmsk = *mask->color; + } + + /* It turns out that by construction all source, mask etc. colors are + * linear because they are made from fills, and fills are always in linear + * color space. However, if they have been converted to bitmaps, we need + * to simulate the sRGB approximation to pass the test cases. + */ + if (src->size) + { + if (PIXMAN_FORMAT_TYPE (src->format) == PIXMAN_TYPE_ARGB_SRGB) + { + tsrc.r = convert_linear_to_srgb (tsrc.r); + tsrc.g = convert_linear_to_srgb (tsrc.g); + tsrc.b = convert_linear_to_srgb (tsrc.b); + round_color (src->format, &tsrc); + tsrc.r = convert_srgb_to_linear (tsrc.r); + tsrc.g = convert_srgb_to_linear (tsrc.g); + tsrc.b = convert_srgb_to_linear (tsrc.b); + } + else + { + round_color (src->format, &tsrc); + } + } + + if (mask && mask->size) + { + if (PIXMAN_FORMAT_TYPE (mask->format) == PIXMAN_TYPE_ARGB_SRGB) + { + tmsk.r = convert_linear_to_srgb (tmsk.r); + tmsk.g = convert_linear_to_srgb (tmsk.g); + tmsk.b = convert_linear_to_srgb (tmsk.b); + round_color (mask->format, &tmsk); + tmsk.r = convert_srgb_to_linear (tmsk.r); + tmsk.g = convert_srgb_to_linear (tmsk.g); + tmsk.b = convert_srgb_to_linear (tmsk.b); + } + else + { + round_color (mask->format, &tmsk); + } + } + + if (mask) + { + if (component_alpha && PIXMAN_FORMAT_R (mask->format) == 0) + { + /* Ax component-alpha masks expand alpha into + * all color channels. + */ + tmsk.r = tmsk.g = tmsk.b = tmsk.a; + } + } + + if (PIXMAN_FORMAT_TYPE (dst->format) == PIXMAN_TYPE_ARGB_SRGB) + { + tdst.r = convert_linear_to_srgb (tdst.r); + tdst.g = convert_linear_to_srgb (tdst.g); + tdst.b = convert_linear_to_srgb (tdst.b); + round_color (dst->format, &tdst); + tdst.r = convert_srgb_to_linear (tdst.r); + tdst.g = convert_srgb_to_linear (tdst.g); + tdst.b = convert_srgb_to_linear (tdst.b); + } + else + { + round_color (dst->format, &tdst); + } + + do_composite (op, + &tsrc, + mask? &tmsk : NULL, + &tdst, + &expected, + component_alpha); + + pixel_checker_init (&checker, dst->format); + + if (!pixel_checker_check (&checker, get_value (dst->image), &expected)) + { + char buf[40], buf2[40]; + int a, r, g, b; + uint32_t pixel; + + printf ("---- Test %d failed ----\n", testno); + printf ("Operator: %s %s\n", + operator_name (op), component_alpha ? "CA" : ""); + + printf ("Source: %s\n", describe_image (src, buf)); + if (mask != NULL) + printf ("Mask: %s\n", describe_image (mask, buf)); + + printf ("Destination: %s\n\n", describe_image (dst, buf)); + printf (" R G B A Rounded\n"); + printf ("Source color: %s %s\n", + describe_color (src->color, buf), + describe_color (&tsrc, buf2)); + if (mask) + { + printf ("Mask color: %s %s\n", + describe_color (mask->color, buf), + describe_color (&tmsk, buf2)); + } + printf ("Dest. color: %s %s\n", + describe_color (dst->color, buf), + describe_color (&tdst, buf2)); + + pixel = get_value (dst->image); + + printf ("Expected: %s\n", describe_color (&expected, buf)); + + pixel_checker_split_pixel (&checker, pixel, &a, &r, &g, &b); + + printf ("Got: %5d %5d %5d %5d [pixel: 0x%08x]\n", r, g, b, a, pixel); + pixel_checker_get_min (&checker, &expected, &a, &r, &g, &b); + printf ("Min accepted: %5d %5d %5d %5d\n", r, g, b, a); + pixel_checker_get_max (&checker, &expected, &a, &r, &g, &b); + printf ("Max accepted: %5d %5d %5d %5d\n", r, g, b, a); + + return FALSE; + } + return TRUE; +} + +static void +image_init (image_t *info, + int color, + int format, + int size) +{ + pixman_color_t fill; + + info->color = &colors[color]; + compute_pixman_color (info->color, &fill); + + info->format = formats[format]; + info->size = sizes[size] & ~FLAGS; + info->repeat = PIXMAN_REPEAT_NONE; + + if (info->size) + { + pixman_image_t *solid; + + info->image = pixman_image_create_bits (info->format, + info->size, info->size, + NULL, 0); + + solid = pixman_image_create_solid_fill (&fill); + pixman_image_composite32 (PIXMAN_OP_SRC, solid, NULL, info->image, + 0, 0, 0, 0, 0, 0, info->size, info->size); + pixman_image_unref (solid); + + if (sizes[size] & REPEAT) + { + pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL); + info->repeat = PIXMAN_REPEAT_NORMAL; + } + } + else + { + info->image = pixman_image_create_solid_fill (&fill); + } +} + +static void +image_fini (image_t *info) +{ + pixman_image_unref (info->image); +} + +static int +random_size (void) +{ + return prng_rand_n (ARRAY_LENGTH (sizes)); +} + +static int +random_color (void) +{ + return prng_rand_n (ARRAY_LENGTH (colors)); +} + +static int +random_format (void) +{ + return prng_rand_n (ARRAY_LENGTH (formats)); +} + +static pixman_bool_t +run_test (uint32_t seed) +{ + image_t src, mask, dst; + pixman_op_t op; + int ca; + int ok; + + prng_srand (seed); + + image_init (&dst, random_color(), random_format(), 1); + image_init (&src, random_color(), random_format(), random_size()); + image_init (&mask, random_color(), random_format(), random_size()); + + op = operators [prng_rand_n (ARRAY_LENGTH (operators))]; + + ca = prng_rand_n (3); + + switch (ca) + { + case 0: + ok = composite_test (&dst, op, &src, NULL, FALSE, seed); + break; + case 1: + ok = composite_test (&dst, op, &src, &mask, FALSE, seed); + break; + case 2: + ok = composite_test (&dst, op, &src, &mask, + mask.size? TRUE : FALSE, seed); + break; + default: + ok = FALSE; + break; + } + + image_fini (&src); + image_fini (&mask); + image_fini (&dst); + + return ok; +} + +int +main (int argc, char **argv) +{ +#define N_TESTS (8 * 1024 * 1024) + int result = 0; + uint32_t seed; + int32_t i; + + if (argc > 1) + { + char *end; + + i = strtol (argv[1], &end, 0); + + if (end != argv[1]) + { + if (!run_test (i)) + return 1; + else + return 0; + } + else + { + printf ("Usage:\n\n %s <number>\n\n", argv[0]); + return -1; + } + } + + if (getenv ("PIXMAN_RANDOMIZE_TESTS")) + seed = get_random_seed(); + else + seed = 1; + +#ifdef USE_OPENMP +# pragma omp parallel for default(none) shared(result, argv, seed) +#endif + for (i = 0; i <= N_TESTS; ++i) + { + if (!result && !run_test (i + seed)) + { + printf ("Test 0x%08X failed.\n", seed + i); + + result = seed + i; + } + } + + return result; +} |