diff options
Diffstat (limited to 'pixman/test/composite.c')
-rw-r--r-- | pixman/test/composite.c | 1814 |
1 files changed, 907 insertions, 907 deletions
diff --git a/pixman/test/composite.c b/pixman/test/composite.c index 8b8a8f540..a86e5ed68 100644 --- a/pixman/test/composite.c +++ b/pixman/test/composite.c @@ -1,907 +1,907 @@ -/*
- * 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(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();
- }
-#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_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, int buflen)
-{
- if (info->size)
- {
- snprintf (buf, buflen, "%s %dx%d%s",
- info->format->name,
- info->size, info->size,
- info->repeat ? "R" :"");
- }
- else
- {
- snprintf (buf, buflen, "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];
-
- snprintf (buf, sizeof (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, sizeof (buf)));
- printf ("mask: %s, ", describe_image (mask, buf, sizeof (buf)));
- printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (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, sizeof (buf)));
- printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (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;
- int 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;
- }
- }
-
-#ifdef USE_OPENMP
-# pragma omp parallel for default(none) shared(result) shared(argv)
-#endif
- for (i = 1; i <= N_TESTS; ++i)
- {
- if (!result && !run_test (i))
- {
- printf ("Test %d failed.\n", i);
-
- result = 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(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_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; + int 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; + } + } + +#ifdef USE_OPENMP +# pragma omp parallel for default(none) shared(result) shared(argv) +#endif + for (i = 1; i <= N_TESTS; ++i) + { + if (!result && !run_test (i)) + { + printf ("Test %d failed.\n", i); + + result = i; + } + } + + return result; +} |