| /* |
| * 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" |
| |
| #define ARRAY_LENGTH(A) ((int) (sizeof (A) / sizeof ((A) [0]))) |
| #define min(a,b) ((a) <= (b) ? (a) : (b)) |
| #define max(a,b) ((a) >= (b) ? (a) : (b)) |
| |
| 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; |
| } |