diff options
Diffstat (limited to 'pixman/test/composite.c')
-rw-r--r-- | pixman/test/composite.c | 1842 |
1 files changed, 921 insertions, 921 deletions
diff --git a/pixman/test/composite.c b/pixman/test/composite.c index edea9a96b..fccf18b53 100644 --- a/pixman/test/composite.c +++ b/pixman/test/composite.c @@ -1,921 +1,921 @@ -/* - * 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. - */ -#define PIXMAN_USE_INTERNAL_API -#include <pixman.h> -#include <stdio.h> -#include <stdlib.h> /* abort() */ -#include <math.h> -#include <config.h> -#include <time.h> -#include "utils.h" - -typedef struct color_t color_t; -typedef struct format_t format_t; -typedef struct image_t image_t; -typedef struct operator_t operator_t; - -struct color_t -{ - double r, g, b, a; -}; - -struct format_t -{ - pixman_format_code_t format; - const char *name; -}; - -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 format_t formats[] = -{ -#define P(x) { PIXMAN_##x, #x } - - /* 32 bpp formats */ - P(a8r8g8b8), - P(x8r8g8b8), - P(a8b8g8r8), - P(x8b8g8r8), - P(b8g8r8a8), - P(b8g8r8x8), - P(r8g8b8a8), - P(r8g8b8x8), - P(x2r10g10b10), - P(x2b10g10r10), - P(a2r10g10b10), - P(a2b10g10r10), - - /* 24 bpp formats */ - P(r8g8b8), - P(b8g8r8), - P(r5g6b5), - P(b5g6r5), - - /* 16 bpp formats */ - P(x1r5g5b5), - P(x1b5g5r5), - P(a1r5g5b5), - P(a1b5g5r5), - P(a4b4g4r4), - P(x4b4g4r4), - P(a4r4g4b4), - P(x4r4g4b4), - - /* 8 bpp formats */ - P(a8), - P(r3g3b2), - P(b2g3r3), - P(a2r2g2b2), - P(a2b2g2r2), - P(x4a4), - - /* 4 bpp formats */ - P(a4), - P(r1g2b1), - P(b1g2r1), - P(a1r1g1b1), - P(a1b1g1r1), - - /* 1 bpp formats */ - P(a1) -#undef P -}; - -struct image_t -{ - pixman_image_t *image; - const format_t *format; - const color_t *color; - pixman_repeat_t repeat; - int size; -}; - -struct operator_t -{ - pixman_op_t op; - const char *name; -}; - -static const operator_t operators[] = -{ -#define P(x) { PIXMAN_OP_##x, #x } - P(CLEAR), - P(SRC), - P(DST), - P(OVER), - P(OVER_REVERSE), - P(IN), - P(IN_REVERSE), - P(OUT), - P(OUT_REVERSE), - P(ATOP), - P(ATOP_REVERSE), - P(XOR), - P(ADD), - P(SATURATE), - - P(DISJOINT_CLEAR), - P(DISJOINT_SRC), - P(DISJOINT_DST), - P(DISJOINT_OVER), - P(DISJOINT_OVER_REVERSE), - P(DISJOINT_IN), - P(DISJOINT_IN_REVERSE), - P(DISJOINT_OUT), - P(DISJOINT_OUT_REVERSE), - P(DISJOINT_ATOP), - P(DISJOINT_ATOP_REVERSE), - P(DISJOINT_XOR), - - P(CONJOINT_CLEAR), - P(CONJOINT_SRC), - P(CONJOINT_DST), - P(CONJOINT_OVER), - P(CONJOINT_OVER_REVERSE), - P(CONJOINT_IN), - P(CONJOINT_IN_REVERSE), - P(CONJOINT_OUT), - P(CONJOINT_OUT_REVERSE), - P(CONJOINT_ATOP), - P(CONJOINT_ATOP_REVERSE), - P(CONJOINT_XOR), -#undef P -}; - -static double -calc_op (pixman_op_t op, double src, double dst, double srca, double dsta) -{ -#define mult_chan(src, dst, Fa, Fb) MIN ((src) * (Fa) + (dst) * (Fb), 1.0) - - double Fa, Fb; - - switch (op) - { - case PIXMAN_OP_CLEAR: - case PIXMAN_OP_DISJOINT_CLEAR: - case PIXMAN_OP_CONJOINT_CLEAR: - return mult_chan (src, dst, 0.0, 0.0); - - case PIXMAN_OP_SRC: - case PIXMAN_OP_DISJOINT_SRC: - case PIXMAN_OP_CONJOINT_SRC: - return mult_chan (src, dst, 1.0, 0.0); - - case PIXMAN_OP_DST: - case PIXMAN_OP_DISJOINT_DST: - case PIXMAN_OP_CONJOINT_DST: - return mult_chan (src, dst, 0.0, 1.0); - - case PIXMAN_OP_OVER: - return mult_chan (src, dst, 1.0, 1.0 - srca); - - case PIXMAN_OP_OVER_REVERSE: - return mult_chan (src, dst, 1.0 - dsta, 1.0); - - case PIXMAN_OP_IN: - return mult_chan (src, dst, dsta, 0.0); - - case PIXMAN_OP_IN_REVERSE: - return mult_chan (src, dst, 0.0, srca); - - case PIXMAN_OP_OUT: - return mult_chan (src, dst, 1.0 - dsta, 0.0); - - case PIXMAN_OP_OUT_REVERSE: - return mult_chan (src, dst, 0.0, 1.0 - srca); - - case PIXMAN_OP_ATOP: - return mult_chan (src, dst, dsta, 1.0 - srca); - - case PIXMAN_OP_ATOP_REVERSE: - return mult_chan (src, dst, 1.0 - dsta, srca); - - case PIXMAN_OP_XOR: - return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca); - - case PIXMAN_OP_ADD: - return mult_chan (src, dst, 1.0, 1.0); - - case PIXMAN_OP_SATURATE: - case PIXMAN_OP_DISJOINT_OVER_REVERSE: - if (srca == 0.0) - Fa = 1.0; - else - Fa = MIN (1.0, (1.0 - dsta) / srca); - return mult_chan (src, dst, Fa, 1.0); - - case PIXMAN_OP_DISJOINT_OVER: - if (dsta == 0.0) - Fb = 1.0; - else - Fb = MIN (1.0, (1.0 - srca) / dsta); - return mult_chan (src, dst, 1.0, Fb); - - case PIXMAN_OP_DISJOINT_IN: - if (srca == 0.0) - Fa = 0.0; - else - Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca); - return mult_chan (src, dst, Fa, 0.0); - - case PIXMAN_OP_DISJOINT_IN_REVERSE: - if (dsta == 0.0) - Fb = 0.0; - else - Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta); - return mult_chan (src, dst, 0.0, Fb); - - case PIXMAN_OP_DISJOINT_OUT: - if (srca == 0.0) - Fa = 1.0; - else - Fa = MIN (1.0, (1.0 - dsta) / srca); - return mult_chan (src, dst, Fa, 0.0); - - case PIXMAN_OP_DISJOINT_OUT_REVERSE: - if (dsta == 0.0) - Fb = 1.0; - else - Fb = MIN (1.0, (1.0 - srca) / dsta); - return mult_chan (src, dst, 0.0, Fb); - - case PIXMAN_OP_DISJOINT_ATOP: - if (srca == 0.0) - Fa = 0.0; - else - Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca); - if (dsta == 0.0) - Fb = 1.0; - else - Fb = MIN (1.0, (1.0 - srca) / dsta); - return mult_chan (src, dst, Fa, Fb); - - case PIXMAN_OP_DISJOINT_ATOP_REVERSE: - if (srca == 0.0) - Fa = 1.0; - else - Fa = MIN (1.0, (1.0 - dsta) / srca); - if (dsta == 0.0) - Fb = 0.0; - else - Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta); - return mult_chan (src, dst, Fa, Fb); - - case PIXMAN_OP_DISJOINT_XOR: - if (srca == 0.0) - Fa = 1.0; - else - Fa = MIN (1.0, (1.0 - dsta) / srca); - if (dsta == 0.0) - Fb = 1.0; - else - Fb = MIN (1.0, (1.0 - srca) / dsta); - return mult_chan (src, dst, Fa, Fb); - - case PIXMAN_OP_CONJOINT_OVER: - if (dsta == 0.0) - Fb = 0.0; - else - Fb = MAX (0.0, 1.0 - srca / dsta); - return mult_chan (src, dst, 1.0, Fb); - - case PIXMAN_OP_CONJOINT_OVER_REVERSE: - if (srca == 0.0) - Fa = 0.0; - else - Fa = MAX (0.0, 1.0 - dsta / srca); - return mult_chan (src, dst, Fa, 1.0); - - case PIXMAN_OP_CONJOINT_IN: - if (srca == 0.0) - Fa = 1.0; - else - Fa = MIN (1.0, dsta / srca); - return mult_chan (src, dst, Fa, 0.0); - - case PIXMAN_OP_CONJOINT_IN_REVERSE: - if (dsta == 0.0) - Fb = 1.0; - else - Fb = MIN (1.0, srca / dsta); - return mult_chan (src, dst, 0.0, Fb); - - case PIXMAN_OP_CONJOINT_OUT: - if (srca == 0.0) - Fa = 0.0; - else - Fa = MAX (0.0, 1.0 - dsta / srca); - return mult_chan (src, dst, Fa, 0.0); - - case PIXMAN_OP_CONJOINT_OUT_REVERSE: - if (dsta == 0.0) - Fb = 0.0; - else - Fb = MAX (0.0, 1.0 - srca / dsta); - return mult_chan (src, dst, 0.0, Fb); - - case PIXMAN_OP_CONJOINT_ATOP: - if (srca == 0.0) - Fa = 1.0; - else - Fa = MIN (1.0, dsta / srca); - if (dsta == 0.0) - Fb = 0.0; - else - Fb = MAX (0.0, 1.0 - srca / dsta); - return mult_chan (src, dst, Fa, Fb); - - case PIXMAN_OP_CONJOINT_ATOP_REVERSE: - if (srca == 0.0) - Fa = 0.0; - else - Fa = MAX (0.0, 1.0 - dsta / srca); - if (dsta == 0.0) - Fb = 1.0; - else - Fb = MIN (1.0, srca / dsta); - return mult_chan (src, dst, Fa, Fb); - - case PIXMAN_OP_CONJOINT_XOR: - if (srca == 0.0) - Fa = 0.0; - else - Fa = MAX (0.0, 1.0 - dsta / srca); - if (dsta == 0.0) - Fb = 0.0; - else - Fb = MAX (0.0, 1.0 - srca / dsta); - return mult_chan (src, dst, Fa, Fb); - - case PIXMAN_OP_MULTIPLY: - case PIXMAN_OP_SCREEN: - case PIXMAN_OP_OVERLAY: - case PIXMAN_OP_DARKEN: - case PIXMAN_OP_LIGHTEN: - case PIXMAN_OP_COLOR_DODGE: - case PIXMAN_OP_COLOR_BURN: - case PIXMAN_OP_HARD_LIGHT: - case PIXMAN_OP_SOFT_LIGHT: - case PIXMAN_OP_DIFFERENCE: - case PIXMAN_OP_EXCLUSION: - case PIXMAN_OP_HSL_HUE: - case PIXMAN_OP_HSL_SATURATION: - case PIXMAN_OP_HSL_COLOR: - case PIXMAN_OP_HSL_LUMINOSITY: - default: - abort(); - return 0; /* silence MSVC */ - } -#undef mult_chan -} - -static void -do_composite (pixman_op_t op, - const color_t *src, - const color_t *mask, - const color_t *dst, - color_t *result, - pixman_bool_t component_alpha) -{ - color_t srcval, srcalpha; - - if (mask == NULL) - { - srcval = *src; - - srcalpha.r = src->a; - srcalpha.g = src->a; - srcalpha.b = src->a; - srcalpha.a = src->a; - } - else if (component_alpha) - { - srcval.r = src->r * mask->r; - srcval.g = src->g * mask->g; - srcval.b = src->b * mask->b; - srcval.a = src->a * mask->a; - - srcalpha.r = src->a * mask->r; - srcalpha.g = src->a * mask->g; - srcalpha.b = src->a * mask->b; - srcalpha.a = src->a * mask->a; - } - else - { - srcval.r = src->r * mask->a; - srcval.g = src->g * mask->a; - srcval.b = src->b * mask->a; - srcval.a = src->a * mask->a; - - srcalpha.r = src->a * mask->a; - srcalpha.g = src->a * mask->a; - srcalpha.b = src->a * mask->a; - srcalpha.a = src->a * mask->a; - } - - result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a); - result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a); - result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a); - result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a); -} - -static void -color_correct (pixman_format_code_t format, - color_t *color) -{ -#define MASK(x) ((1 << (x)) - 1) -#define round_pix(pix, m) \ - ((int)((pix) * (MASK(m)) + .5) / (double) (MASK(m))) - - if (PIXMAN_FORMAT_R (format) == 0) - { - color->r = 0.0; - color->g = 0.0; - color->b = 0.0; - } - else - { - color->r = round_pix (color->r, PIXMAN_FORMAT_R (format)); - color->g = round_pix (color->g, PIXMAN_FORMAT_G (format)); - color->b = round_pix (color->b, PIXMAN_FORMAT_B (format)); - } - - if (PIXMAN_FORMAT_A (format) == 0) - color->a = 1.0; - else - color->a = round_pix (color->a, PIXMAN_FORMAT_A (format)); - -#undef round_pix -#undef MASK -} - -static void -get_pixel (pixman_image_t *image, - pixman_format_code_t format, - color_t *color) -{ -#define MASK(N) ((1UL << (N))-1) - - unsigned long rs, gs, bs, as; - int a, r, g, b; - unsigned long val; - - val = *(unsigned long *) pixman_image_get_data (image); -#ifdef WORDS_BIGENDIAN - val >>= 8 * sizeof(val) - PIXMAN_FORMAT_BPP (format); -#endif - - /* Number of bits in each channel */ - a = PIXMAN_FORMAT_A (format); - r = PIXMAN_FORMAT_R (format); - g = PIXMAN_FORMAT_G (format); - b = PIXMAN_FORMAT_B (format); - - switch (PIXMAN_FORMAT_TYPE (format)) - { - case PIXMAN_TYPE_ARGB: - bs = 0; - gs = b + bs; - rs = g + gs; - as = r + rs; - break; - - case PIXMAN_TYPE_ABGR: - rs = 0; - gs = r + rs; - bs = g + gs; - as = b + bs; - break; - - case PIXMAN_TYPE_BGRA: - as = 0; - rs = PIXMAN_FORMAT_BPP (format) - (b + g + r); - gs = r + rs; - bs = g + gs; - break; - - case PIXMAN_TYPE_RGBA: - as = 0; - bs = PIXMAN_FORMAT_BPP (format) - (b + g + r); - gs = b + bs; - rs = g + gs; - break; - - case PIXMAN_TYPE_A: - as = 0; - rs = 0; - gs = 0; - bs = 0; - break; - - case PIXMAN_TYPE_OTHER: - case PIXMAN_TYPE_COLOR: - case PIXMAN_TYPE_GRAY: - case PIXMAN_TYPE_YUY2: - case PIXMAN_TYPE_YV12: - default: - abort (); - as = 0; - rs = 0; - gs = 0; - bs = 0; - break; - } - - if (MASK (a) != 0) - color->a = ((val >> as) & MASK (a)) / (double) MASK (a); - else - color->a = 1.0; - - if (MASK (r) != 0) - { - color->r = ((val >> rs) & MASK (r)) / (double) MASK (r); - color->g = ((val >> gs) & MASK (g)) / (double) MASK (g); - color->b = ((val >> bs) & MASK (b)) / (double) MASK (b); - } - else - { - color->r = 0.0; - color->g = 0.0; - color->b = 0.0; - } - -#undef MASK -} - -static double -eval_diff (color_t *expected, color_t *test, pixman_format_code_t format) -{ - double rscale, gscale, bscale, ascale; - double rdiff, gdiff, bdiff, adiff; - - rscale = 1.0 * ((1 << PIXMAN_FORMAT_R (format)) - 1); - gscale = 1.0 * ((1 << PIXMAN_FORMAT_G (format)) - 1); - bscale = 1.0 * ((1 << PIXMAN_FORMAT_B (format)) - 1); - ascale = 1.0 * ((1 << PIXMAN_FORMAT_A (format)) - 1); - - rdiff = fabs (test->r - expected->r) * rscale; - bdiff = fabs (test->g - expected->g) * gscale; - gdiff = fabs (test->b - expected->b) * bscale; - adiff = fabs (test->a - expected->a) * ascale; - - return MAX (MAX (MAX (rdiff, gdiff), bdiff), adiff); -} - -static char * -describe_image (image_t *info, char *buf) -{ - if (info->size) - { - sprintf (buf, "%s %dx%d%s", - info->format->name, - info->size, info->size, - info->repeat ? "R" :""); - } - else - { - sprintf (buf, "solid"); - } - - return buf; -} - -/* Test a composite of a given operation, source, mask, and destination - * picture. - * Fills the window, and samples from the 0,0 pixel corner. - */ -static pixman_bool_t -composite_test (image_t *dst, - const operator_t *op, - image_t *src, - image_t *mask, - pixman_bool_t component_alpha) -{ - pixman_color_t fill; - pixman_rectangle16_t rect; - color_t expected, result, tdst, tsrc, tmsk; - double diff; - pixman_bool_t success = TRUE; - - compute_pixman_color (dst->color, &fill); - rect.x = rect.y = 0; - rect.width = rect.height = dst->size; - pixman_image_fill_rectangles (PIXMAN_OP_SRC, dst->image, - &fill, 1, &rect); - - if (mask != NULL) - { - pixman_image_set_component_alpha (mask->image, component_alpha); - pixman_image_composite (op->op, src->image, mask->image, dst->image, - 0, 0, - 0, 0, - 0, 0, - dst->size, dst->size); - - tmsk = *mask->color; - if (mask->size) - { - color_correct (mask->format->format, &tmsk); - - if (component_alpha && - PIXMAN_FORMAT_R (mask->format->format) == 0) - { - /* Ax component-alpha masks expand alpha into - * all color channels. - */ - tmsk.r = tmsk.g = tmsk.b = tmsk.a; - } - } - } - else - { - pixman_image_composite (op->op, src->image, NULL, dst->image, - 0, 0, - 0, 0, - 0, 0, - dst->size, dst->size); - } - get_pixel (dst->image, dst->format->format, &result); - - tdst = *dst->color; - color_correct (dst->format->format, &tdst); - tsrc = *src->color; - if (src->size) - color_correct (src->format->format, &tsrc); - do_composite (op->op, &tsrc, mask ? &tmsk : NULL, &tdst, - &expected, component_alpha); - color_correct (dst->format->format, &expected); - - diff = eval_diff (&expected, &result, dst->format->format); - - /* FIXME: We should find out what deviation is acceptable. 3.0 - * is clearly absurd for 2 bit formats for example. On the other - * hand currently 1.0 does not work. - */ - if (diff > 3.0) - { - char buf[40]; - - sprintf (buf, "%s %scomposite", - op->name, - component_alpha ? "CA " : ""); - - printf ("%s test error of %.4f --\n" - " R G B A\n" - "got: %.2f %.2f %.2f %.2f [%08lx]\n" - "expected: %.2f %.2f %.2f %.2f\n", - buf, diff, - result.r, result.g, result.b, result.a, - *(unsigned long *) pixman_image_get_data (dst->image), - expected.r, expected.g, expected.b, expected.a); - - if (mask != NULL) - { - printf ("src color: %.2f %.2f %.2f %.2f\n" - "msk color: %.2f %.2f %.2f %.2f\n" - "dst color: %.2f %.2f %.2f %.2f\n", - src->color->r, src->color->g, - src->color->b, src->color->a, - mask->color->r, mask->color->g, - mask->color->b, mask->color->a, - dst->color->r, dst->color->g, - dst->color->b, dst->color->a); - printf ("src: %s, ", describe_image (src, buf)); - printf ("mask: %s, ", describe_image (mask, buf)); - printf ("dst: %s\n\n", describe_image (dst, buf)); - } - else - { - printf ("src color: %.2f %.2f %.2f %.2f\n" - "dst color: %.2f %.2f %.2f %.2f\n", - src->color->r, src->color->g, - src->color->b, src->color->a, - dst->color->r, dst->color->g, - dst->color->b, dst->color->a); - printf ("src: %s, ", describe_image (src, buf)); - printf ("dst: %s\n\n", describe_image (dst, buf)); - } - - success = FALSE; - } - - return success; -} - -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_rectangle16_t rect; - - info->image = pixman_image_create_bits (info->format->format, - info->size, info->size, - NULL, 0); - - rect.x = rect.y = 0; - rect.width = rect.height = info->size; - pixman_image_fill_rectangles (PIXMAN_OP_SRC, info->image, &fill, - 1, &rect); - - if (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 lcg_rand_n (ARRAY_LENGTH (sizes)); -} - -static int -random_color (void) -{ - return lcg_rand_n (ARRAY_LENGTH (colors)); -} - -static int -random_format (void) -{ - return lcg_rand_n (ARRAY_LENGTH (formats)); -} - -static pixman_bool_t -run_test (uint32_t seed) -{ - image_t src, mask, dst; - const operator_t *op; - int ca; - int ok; - - lcg_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 [lcg_rand_n (ARRAY_LENGTH (operators))]); - - ca = lcg_rand_n (3); - - switch (ca) - { - case 0: - ok = composite_test (&dst, op, &src, NULL, FALSE); - break; - case 1: - ok = composite_test (&dst, op, &src, &mask, FALSE); - break; - case 2: - ok = composite_test (&dst, op, &src, &mask, - mask.size? TRUE : FALSE); - 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 i, seed; - - 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; -} +/*
+ * 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.
+ */
+#define PIXMAN_USE_INTERNAL_API
+#include <pixman.h>
+#include <stdio.h>
+#include <stdlib.h> /* abort() */
+#include <math.h>
+#include <config.h>
+#include <time.h>
+#include "utils.h"
+
+typedef struct color_t color_t;
+typedef struct format_t format_t;
+typedef struct image_t image_t;
+typedef struct operator_t operator_t;
+
+struct color_t
+{
+ double r, g, b, a;
+};
+
+struct format_t
+{
+ pixman_format_code_t format;
+ const char *name;
+};
+
+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 format_t formats[] =
+{
+#define P(x) { PIXMAN_##x, #x }
+
+ /* 32 bpp formats */
+ P(a8r8g8b8),
+ P(x8r8g8b8),
+ P(a8b8g8r8),
+ P(x8b8g8r8),
+ P(b8g8r8a8),
+ P(b8g8r8x8),
+ P(r8g8b8a8),
+ P(r8g8b8x8),
+ P(x2r10g10b10),
+ P(x2b10g10r10),
+ P(a2r10g10b10),
+ P(a2b10g10r10),
+
+ /* 24 bpp formats */
+ P(r8g8b8),
+ P(b8g8r8),
+ P(r5g6b5),
+ P(b5g6r5),
+
+ /* 16 bpp formats */
+ P(x1r5g5b5),
+ P(x1b5g5r5),
+ P(a1r5g5b5),
+ P(a1b5g5r5),
+ P(a4b4g4r4),
+ P(x4b4g4r4),
+ P(a4r4g4b4),
+ P(x4r4g4b4),
+
+ /* 8 bpp formats */
+ P(a8),
+ P(r3g3b2),
+ P(b2g3r3),
+ P(a2r2g2b2),
+ P(a2b2g2r2),
+ P(x4a4),
+
+ /* 4 bpp formats */
+ P(a4),
+ P(r1g2b1),
+ P(b1g2r1),
+ P(a1r1g1b1),
+ P(a1b1g1r1),
+
+ /* 1 bpp formats */
+ P(a1)
+#undef P
+};
+
+struct image_t
+{
+ pixman_image_t *image;
+ const format_t *format;
+ const color_t *color;
+ pixman_repeat_t repeat;
+ int size;
+};
+
+struct operator_t
+{
+ pixman_op_t op;
+ const char *name;
+};
+
+static const operator_t operators[] =
+{
+#define P(x) { PIXMAN_OP_##x, #x }
+ P(CLEAR),
+ P(SRC),
+ P(DST),
+ P(OVER),
+ P(OVER_REVERSE),
+ P(IN),
+ P(IN_REVERSE),
+ P(OUT),
+ P(OUT_REVERSE),
+ P(ATOP),
+ P(ATOP_REVERSE),
+ P(XOR),
+ P(ADD),
+ P(SATURATE),
+
+ P(DISJOINT_CLEAR),
+ P(DISJOINT_SRC),
+ P(DISJOINT_DST),
+ P(DISJOINT_OVER),
+ P(DISJOINT_OVER_REVERSE),
+ P(DISJOINT_IN),
+ P(DISJOINT_IN_REVERSE),
+ P(DISJOINT_OUT),
+ P(DISJOINT_OUT_REVERSE),
+ P(DISJOINT_ATOP),
+ P(DISJOINT_ATOP_REVERSE),
+ P(DISJOINT_XOR),
+
+ P(CONJOINT_CLEAR),
+ P(CONJOINT_SRC),
+ P(CONJOINT_DST),
+ P(CONJOINT_OVER),
+ P(CONJOINT_OVER_REVERSE),
+ P(CONJOINT_IN),
+ P(CONJOINT_IN_REVERSE),
+ P(CONJOINT_OUT),
+ P(CONJOINT_OUT_REVERSE),
+ P(CONJOINT_ATOP),
+ P(CONJOINT_ATOP_REVERSE),
+ P(CONJOINT_XOR),
+#undef P
+};
+
+static double
+calc_op (pixman_op_t op, double src, double dst, double srca, double dsta)
+{
+#define mult_chan(src, dst, Fa, Fb) MIN ((src) * (Fa) + (dst) * (Fb), 1.0)
+
+ double Fa, Fb;
+
+ switch (op)
+ {
+ case PIXMAN_OP_CLEAR:
+ case PIXMAN_OP_DISJOINT_CLEAR:
+ case PIXMAN_OP_CONJOINT_CLEAR:
+ return mult_chan (src, dst, 0.0, 0.0);
+
+ case PIXMAN_OP_SRC:
+ case PIXMAN_OP_DISJOINT_SRC:
+ case PIXMAN_OP_CONJOINT_SRC:
+ return mult_chan (src, dst, 1.0, 0.0);
+
+ case PIXMAN_OP_DST:
+ case PIXMAN_OP_DISJOINT_DST:
+ case PIXMAN_OP_CONJOINT_DST:
+ return mult_chan (src, dst, 0.0, 1.0);
+
+ case PIXMAN_OP_OVER:
+ return mult_chan (src, dst, 1.0, 1.0 - srca);
+
+ case PIXMAN_OP_OVER_REVERSE:
+ return mult_chan (src, dst, 1.0 - dsta, 1.0);
+
+ case PIXMAN_OP_IN:
+ return mult_chan (src, dst, dsta, 0.0);
+
+ case PIXMAN_OP_IN_REVERSE:
+ return mult_chan (src, dst, 0.0, srca);
+
+ case PIXMAN_OP_OUT:
+ return mult_chan (src, dst, 1.0 - dsta, 0.0);
+
+ case PIXMAN_OP_OUT_REVERSE:
+ return mult_chan (src, dst, 0.0, 1.0 - srca);
+
+ case PIXMAN_OP_ATOP:
+ return mult_chan (src, dst, dsta, 1.0 - srca);
+
+ case PIXMAN_OP_ATOP_REVERSE:
+ return mult_chan (src, dst, 1.0 - dsta, srca);
+
+ case PIXMAN_OP_XOR:
+ return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca);
+
+ case PIXMAN_OP_ADD:
+ return mult_chan (src, dst, 1.0, 1.0);
+
+ case PIXMAN_OP_SATURATE:
+ case PIXMAN_OP_DISJOINT_OVER_REVERSE:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = MIN (1.0, (1.0 - dsta) / srca);
+ return mult_chan (src, dst, Fa, 1.0);
+
+ case PIXMAN_OP_DISJOINT_OVER:
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = MIN (1.0, (1.0 - srca) / dsta);
+ return mult_chan (src, dst, 1.0, Fb);
+
+ case PIXMAN_OP_DISJOINT_IN:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca);
+ return mult_chan (src, dst, Fa, 0.0);
+
+ case PIXMAN_OP_DISJOINT_IN_REVERSE:
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta);
+ return mult_chan (src, dst, 0.0, Fb);
+
+ case PIXMAN_OP_DISJOINT_OUT:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = MIN (1.0, (1.0 - dsta) / srca);
+ return mult_chan (src, dst, Fa, 0.0);
+
+ case PIXMAN_OP_DISJOINT_OUT_REVERSE:
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = MIN (1.0, (1.0 - srca) / dsta);
+ return mult_chan (src, dst, 0.0, Fb);
+
+ case PIXMAN_OP_DISJOINT_ATOP:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca);
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = MIN (1.0, (1.0 - srca) / dsta);
+ return mult_chan (src, dst, Fa, Fb);
+
+ case PIXMAN_OP_DISJOINT_ATOP_REVERSE:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = MIN (1.0, (1.0 - dsta) / srca);
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta);
+ return mult_chan (src, dst, Fa, Fb);
+
+ case PIXMAN_OP_DISJOINT_XOR:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = MIN (1.0, (1.0 - dsta) / srca);
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = MIN (1.0, (1.0 - srca) / dsta);
+ return mult_chan (src, dst, Fa, Fb);
+
+ case PIXMAN_OP_CONJOINT_OVER:
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = MAX (0.0, 1.0 - srca / dsta);
+ return mult_chan (src, dst, 1.0, Fb);
+
+ case PIXMAN_OP_CONJOINT_OVER_REVERSE:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = MAX (0.0, 1.0 - dsta / srca);
+ return mult_chan (src, dst, Fa, 1.0);
+
+ case PIXMAN_OP_CONJOINT_IN:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = MIN (1.0, dsta / srca);
+ return mult_chan (src, dst, Fa, 0.0);
+
+ case PIXMAN_OP_CONJOINT_IN_REVERSE:
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = MIN (1.0, srca / dsta);
+ return mult_chan (src, dst, 0.0, Fb);
+
+ case PIXMAN_OP_CONJOINT_OUT:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = MAX (0.0, 1.0 - dsta / srca);
+ return mult_chan (src, dst, Fa, 0.0);
+
+ case PIXMAN_OP_CONJOINT_OUT_REVERSE:
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = MAX (0.0, 1.0 - srca / dsta);
+ return mult_chan (src, dst, 0.0, Fb);
+
+ case PIXMAN_OP_CONJOINT_ATOP:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = MIN (1.0, dsta / srca);
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = MAX (0.0, 1.0 - srca / dsta);
+ return mult_chan (src, dst, Fa, Fb);
+
+ case PIXMAN_OP_CONJOINT_ATOP_REVERSE:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = MAX (0.0, 1.0 - dsta / srca);
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = MIN (1.0, srca / dsta);
+ return mult_chan (src, dst, Fa, Fb);
+
+ case PIXMAN_OP_CONJOINT_XOR:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = MAX (0.0, 1.0 - dsta / srca);
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = MAX (0.0, 1.0 - srca / dsta);
+ return mult_chan (src, dst, Fa, Fb);
+
+ case PIXMAN_OP_MULTIPLY:
+ case PIXMAN_OP_SCREEN:
+ case PIXMAN_OP_OVERLAY:
+ case PIXMAN_OP_DARKEN:
+ case PIXMAN_OP_LIGHTEN:
+ case PIXMAN_OP_COLOR_DODGE:
+ case PIXMAN_OP_COLOR_BURN:
+ case PIXMAN_OP_HARD_LIGHT:
+ case PIXMAN_OP_SOFT_LIGHT:
+ case PIXMAN_OP_DIFFERENCE:
+ case PIXMAN_OP_EXCLUSION:
+ case PIXMAN_OP_HSL_HUE:
+ case PIXMAN_OP_HSL_SATURATION:
+ case PIXMAN_OP_HSL_COLOR:
+ case PIXMAN_OP_HSL_LUMINOSITY:
+ default:
+ abort();
+ return 0; /* silence MSVC */
+ }
+#undef mult_chan
+}
+
+static void
+do_composite (pixman_op_t op,
+ const color_t *src,
+ const color_t *mask,
+ const color_t *dst,
+ color_t *result,
+ pixman_bool_t component_alpha)
+{
+ color_t srcval, srcalpha;
+
+ if (mask == NULL)
+ {
+ srcval = *src;
+
+ srcalpha.r = src->a;
+ srcalpha.g = src->a;
+ srcalpha.b = src->a;
+ srcalpha.a = src->a;
+ }
+ else if (component_alpha)
+ {
+ srcval.r = src->r * mask->r;
+ srcval.g = src->g * mask->g;
+ srcval.b = src->b * mask->b;
+ srcval.a = src->a * mask->a;
+
+ srcalpha.r = src->a * mask->r;
+ srcalpha.g = src->a * mask->g;
+ srcalpha.b = src->a * mask->b;
+ srcalpha.a = src->a * mask->a;
+ }
+ else
+ {
+ srcval.r = src->r * mask->a;
+ srcval.g = src->g * mask->a;
+ srcval.b = src->b * mask->a;
+ srcval.a = src->a * mask->a;
+
+ srcalpha.r = src->a * mask->a;
+ srcalpha.g = src->a * mask->a;
+ srcalpha.b = src->a * mask->a;
+ srcalpha.a = src->a * mask->a;
+ }
+
+ result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a);
+ result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a);
+ result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a);
+ result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a);
+}
+
+static void
+color_correct (pixman_format_code_t format,
+ color_t *color)
+{
+#define MASK(x) ((1 << (x)) - 1)
+#define round_pix(pix, m) \
+ ((int)((pix) * (MASK(m)) + .5) / (double) (MASK(m)))
+
+ if (PIXMAN_FORMAT_R (format) == 0)
+ {
+ color->r = 0.0;
+ color->g = 0.0;
+ color->b = 0.0;
+ }
+ else
+ {
+ color->r = round_pix (color->r, PIXMAN_FORMAT_R (format));
+ color->g = round_pix (color->g, PIXMAN_FORMAT_G (format));
+ color->b = round_pix (color->b, PIXMAN_FORMAT_B (format));
+ }
+
+ if (PIXMAN_FORMAT_A (format) == 0)
+ color->a = 1.0;
+ else
+ color->a = round_pix (color->a, PIXMAN_FORMAT_A (format));
+
+#undef round_pix
+#undef MASK
+}
+
+static void
+get_pixel (pixman_image_t *image,
+ pixman_format_code_t format,
+ color_t *color)
+{
+#define MASK(N) ((1UL << (N))-1)
+
+ unsigned long rs, gs, bs, as;
+ int a, r, g, b;
+ unsigned long val;
+
+ val = *(unsigned long *) pixman_image_get_data (image);
+#ifdef WORDS_BIGENDIAN
+ val >>= 8 * sizeof(val) - PIXMAN_FORMAT_BPP (format);
+#endif
+
+ /* Number of bits in each channel */
+ a = PIXMAN_FORMAT_A (format);
+ r = PIXMAN_FORMAT_R (format);
+ g = PIXMAN_FORMAT_G (format);
+ b = PIXMAN_FORMAT_B (format);
+
+ switch (PIXMAN_FORMAT_TYPE (format))
+ {
+ case PIXMAN_TYPE_ARGB:
+ bs = 0;
+ gs = b + bs;
+ rs = g + gs;
+ as = r + rs;
+ break;
+
+ case PIXMAN_TYPE_ABGR:
+ rs = 0;
+ gs = r + rs;
+ bs = g + gs;
+ as = b + bs;
+ break;
+
+ case PIXMAN_TYPE_BGRA:
+ as = 0;
+ rs = PIXMAN_FORMAT_BPP (format) - (b + g + r);
+ gs = r + rs;
+ bs = g + gs;
+ break;
+
+ case PIXMAN_TYPE_RGBA:
+ as = 0;
+ bs = PIXMAN_FORMAT_BPP (format) - (b + g + r);
+ gs = b + bs;
+ rs = g + gs;
+ break;
+
+ case PIXMAN_TYPE_A:
+ as = 0;
+ rs = 0;
+ gs = 0;
+ bs = 0;
+ break;
+
+ case PIXMAN_TYPE_OTHER:
+ case PIXMAN_TYPE_COLOR:
+ case PIXMAN_TYPE_GRAY:
+ case PIXMAN_TYPE_YUY2:
+ case PIXMAN_TYPE_YV12:
+ default:
+ abort ();
+ as = 0;
+ rs = 0;
+ gs = 0;
+ bs = 0;
+ break;
+ }
+
+ if (MASK (a) != 0)
+ color->a = ((val >> as) & MASK (a)) / (double) MASK (a);
+ else
+ color->a = 1.0;
+
+ if (MASK (r) != 0)
+ {
+ color->r = ((val >> rs) & MASK (r)) / (double) MASK (r);
+ color->g = ((val >> gs) & MASK (g)) / (double) MASK (g);
+ color->b = ((val >> bs) & MASK (b)) / (double) MASK (b);
+ }
+ else
+ {
+ color->r = 0.0;
+ color->g = 0.0;
+ color->b = 0.0;
+ }
+
+#undef MASK
+}
+
+static double
+eval_diff (color_t *expected, color_t *test, pixman_format_code_t format)
+{
+ double rscale, gscale, bscale, ascale;
+ double rdiff, gdiff, bdiff, adiff;
+
+ rscale = 1.0 * ((1 << PIXMAN_FORMAT_R (format)) - 1);
+ gscale = 1.0 * ((1 << PIXMAN_FORMAT_G (format)) - 1);
+ bscale = 1.0 * ((1 << PIXMAN_FORMAT_B (format)) - 1);
+ ascale = 1.0 * ((1 << PIXMAN_FORMAT_A (format)) - 1);
+
+ rdiff = fabs (test->r - expected->r) * rscale;
+ bdiff = fabs (test->g - expected->g) * gscale;
+ gdiff = fabs (test->b - expected->b) * bscale;
+ adiff = fabs (test->a - expected->a) * ascale;
+
+ return MAX (MAX (MAX (rdiff, gdiff), bdiff), adiff);
+}
+
+static char *
+describe_image (image_t *info, char *buf)
+{
+ if (info->size)
+ {
+ sprintf (buf, "%s %dx%d%s",
+ info->format->name,
+ info->size, info->size,
+ info->repeat ? "R" :"");
+ }
+ else
+ {
+ sprintf (buf, "solid");
+ }
+
+ return buf;
+}
+
+/* Test a composite of a given operation, source, mask, and destination
+ * picture.
+ * Fills the window, and samples from the 0,0 pixel corner.
+ */
+static pixman_bool_t
+composite_test (image_t *dst,
+ const operator_t *op,
+ image_t *src,
+ image_t *mask,
+ pixman_bool_t component_alpha)
+{
+ pixman_color_t fill;
+ pixman_rectangle16_t rect;
+ color_t expected, result, tdst, tsrc, tmsk;
+ double diff;
+ pixman_bool_t success = TRUE;
+
+ compute_pixman_color (dst->color, &fill);
+ rect.x = rect.y = 0;
+ rect.width = rect.height = dst->size;
+ pixman_image_fill_rectangles (PIXMAN_OP_SRC, dst->image,
+ &fill, 1, &rect);
+
+ if (mask != NULL)
+ {
+ pixman_image_set_component_alpha (mask->image, component_alpha);
+ pixman_image_composite (op->op, src->image, mask->image, dst->image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ dst->size, dst->size);
+
+ tmsk = *mask->color;
+ if (mask->size)
+ {
+ color_correct (mask->format->format, &tmsk);
+
+ if (component_alpha &&
+ PIXMAN_FORMAT_R (mask->format->format) == 0)
+ {
+ /* Ax component-alpha masks expand alpha into
+ * all color channels.
+ */
+ tmsk.r = tmsk.g = tmsk.b = tmsk.a;
+ }
+ }
+ }
+ else
+ {
+ pixman_image_composite (op->op, src->image, NULL, dst->image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ dst->size, dst->size);
+ }
+ get_pixel (dst->image, dst->format->format, &result);
+
+ tdst = *dst->color;
+ color_correct (dst->format->format, &tdst);
+ tsrc = *src->color;
+ if (src->size)
+ color_correct (src->format->format, &tsrc);
+ do_composite (op->op, &tsrc, mask ? &tmsk : NULL, &tdst,
+ &expected, component_alpha);
+ color_correct (dst->format->format, &expected);
+
+ diff = eval_diff (&expected, &result, dst->format->format);
+
+ /* FIXME: We should find out what deviation is acceptable. 3.0
+ * is clearly absurd for 2 bit formats for example. On the other
+ * hand currently 1.0 does not work.
+ */
+ if (diff > 3.0)
+ {
+ char buf[40];
+
+ sprintf (buf, "%s %scomposite",
+ op->name,
+ component_alpha ? "CA " : "");
+
+ printf ("%s test error of %.4f --\n"
+ " R G B A\n"
+ "got: %.2f %.2f %.2f %.2f [%08lx]\n"
+ "expected: %.2f %.2f %.2f %.2f\n",
+ buf, diff,
+ result.r, result.g, result.b, result.a,
+ *(unsigned long *) pixman_image_get_data (dst->image),
+ expected.r, expected.g, expected.b, expected.a);
+
+ if (mask != NULL)
+ {
+ printf ("src color: %.2f %.2f %.2f %.2f\n"
+ "msk color: %.2f %.2f %.2f %.2f\n"
+ "dst color: %.2f %.2f %.2f %.2f\n",
+ src->color->r, src->color->g,
+ src->color->b, src->color->a,
+ mask->color->r, mask->color->g,
+ mask->color->b, mask->color->a,
+ dst->color->r, dst->color->g,
+ dst->color->b, dst->color->a);
+ printf ("src: %s, ", describe_image (src, buf));
+ printf ("mask: %s, ", describe_image (mask, buf));
+ printf ("dst: %s\n\n", describe_image (dst, buf));
+ }
+ else
+ {
+ printf ("src color: %.2f %.2f %.2f %.2f\n"
+ "dst color: %.2f %.2f %.2f %.2f\n",
+ src->color->r, src->color->g,
+ src->color->b, src->color->a,
+ dst->color->r, dst->color->g,
+ dst->color->b, dst->color->a);
+ printf ("src: %s, ", describe_image (src, buf));
+ printf ("dst: %s\n\n", describe_image (dst, buf));
+ }
+
+ success = FALSE;
+ }
+
+ return success;
+}
+
+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_rectangle16_t rect;
+
+ info->image = pixman_image_create_bits (info->format->format,
+ info->size, info->size,
+ NULL, 0);
+
+ rect.x = rect.y = 0;
+ rect.width = rect.height = info->size;
+ pixman_image_fill_rectangles (PIXMAN_OP_SRC, info->image, &fill,
+ 1, &rect);
+
+ if (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 lcg_rand_n (ARRAY_LENGTH (sizes));
+}
+
+static int
+random_color (void)
+{
+ return lcg_rand_n (ARRAY_LENGTH (colors));
+}
+
+static int
+random_format (void)
+{
+ return lcg_rand_n (ARRAY_LENGTH (formats));
+}
+
+static pixman_bool_t
+run_test (uint32_t seed)
+{
+ image_t src, mask, dst;
+ const operator_t *op;
+ int ca;
+ int ok;
+
+ lcg_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 [lcg_rand_n (ARRAY_LENGTH (operators))]);
+
+ ca = lcg_rand_n (3);
+
+ switch (ca)
+ {
+ case 0:
+ ok = composite_test (&dst, op, &src, NULL, FALSE);
+ break;
+ case 1:
+ ok = composite_test (&dst, op, &src, &mask, FALSE);
+ break;
+ case 2:
+ ok = composite_test (&dst, op, &src, &mask,
+ mask.size? TRUE : FALSE);
+ 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 i, seed;
+
+ 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;
+}
|