diff options
Diffstat (limited to 'pixman')
-rw-r--r-- | pixman/pixman/pixman-access.c | 10 | ||||
-rw-r--r-- | pixman/pixman/pixman-arm-neon-asm.S | 36 | ||||
-rw-r--r-- | pixman/pixman/pixman-arm-neon.c | 4 | ||||
-rw-r--r-- | pixman/pixman/pixman.c | 17 | ||||
-rw-r--r-- | pixman/test/composite.c | 1803 |
5 files changed, 951 insertions, 919 deletions
diff --git a/pixman/pixman/pixman-access.c b/pixman/pixman/pixman-access.c index 7ca856f3e..8dc770081 100644 --- a/pixman/pixman/pixman-access.c +++ b/pixman/pixman/pixman-access.c @@ -2425,11 +2425,11 @@ store_scanline_a2b2g2r2 (bits_image_t * image, {
SPLIT_A (values[i]);
- *(pixel++) =
- ((a ) & 0xc0) |
- ((b >> 2) & 0x30) |
- ((g >> 4) & 0x0c) |
- ((r >> 6) );
+ WRITE (image, pixel++,
+ ((a ) & 0xc0) |
+ ((b >> 2) & 0x30) |
+ ((g >> 4) & 0x0c) |
+ ((r >> 6) ));
}
}
diff --git a/pixman/pixman/pixman-arm-neon-asm.S b/pixman/pixman/pixman-arm-neon-asm.S index 18dca54ef..c2a8bd6ea 100644 --- a/pixman/pixman/pixman-arm-neon-asm.S +++ b/pixman/pixman/pixman-arm-neon-asm.S @@ -881,6 +881,42 @@ generate_composite_function \ /******************************************************************************/
+/* TODO: expand macros and do better instructions scheduling */
+.macro pixman_composite_over_8888_8_0565_process_pixblock_tail_head
+ vld1.16 {d4, d5}, [DST_R, :128]!
+ pixman_composite_over_n_8_0565_process_pixblock_tail
+ vld4.8 {d8, d9, d10, d11}, [SRC]!
+ cache_preload 8, 8
+ vld1.8 {d24}, [MASK]!
+ pixman_composite_over_n_8_0565_process_pixblock_head
+ vst1.16 {d28, d29}, [DST_W, :128]!
+.endm
+
+.macro pixman_composite_over_8888_8_0565_init
+ vpush {d8-d15}
+.endm
+
+.macro pixman_composite_over_8888_8_0565_cleanup
+ vpop {d8-d15}
+.endm
+
+generate_composite_function \
+ pixman_composite_over_8888_8_0565_asm_neon, 32, 8, 16, \
+ FLAG_DST_READWRITE | FLAG_DEINTERLEAVE_32BPP, \
+ 8, /* number of pixels, processed in a single block */ \
+ 5, /* prefetch distance */ \
+ pixman_composite_over_8888_8_0565_init, \
+ pixman_composite_over_8888_8_0565_cleanup, \
+ pixman_composite_over_n_8_0565_process_pixblock_head, \
+ pixman_composite_over_n_8_0565_process_pixblock_tail, \
+ pixman_composite_over_8888_8_0565_process_pixblock_tail_head, \
+ 28, /* dst_w_basereg */ \
+ 4, /* dst_r_basereg */ \
+ 8, /* src_basereg */ \
+ 24 /* mask_basereg */
+
+/******************************************************************************/
+
.macro pixman_composite_src_0565_0565_process_pixblock_head
.endm
diff --git a/pixman/pixman/pixman-arm-neon.c b/pixman/pixman/pixman-arm-neon.c index ce049b280..a6da794f1 100644 --- a/pixman/pixman/pixman-arm-neon.c +++ b/pixman/pixman/pixman-arm-neon.c @@ -88,6 +88,8 @@ PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, over_8888_8_8888, uint32_t, 1, uint8_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, over_8888_8888_8888,
uint32_t, 1, uint32_t, 1, uint32_t, 1)
+PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, over_8888_8_0565,
+ uint32_t, 1, uint8_t, 1, uint16_t, 1)
void
pixman_composite_src_n_8_asm_neon (int32_t w,
@@ -237,6 +239,8 @@ static const pixman_fast_path_t arm_neon_fast_paths[] = PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, x8r8g8b8, neon_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, a8b8g8r8, neon_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, x8b8g8r8, neon_composite_over_8888_8_8888),
+ PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, r5g6b5, neon_composite_over_8888_8_0565),
+ PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, b5g6r5, neon_composite_over_8888_8_0565),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, a8r8g8b8, neon_composite_over_8888_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, r5g6b5, neon_composite_over_8888_0565),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, b5g6r5, neon_composite_over_8888_0565),
diff --git a/pixman/pixman/pixman.c b/pixman/pixman/pixman.c index 4171cb889..4dd45f471 100644 --- a/pixman/pixman/pixman.c +++ b/pixman/pixman/pixman.c @@ -302,17 +302,13 @@ pixman_compute_composite_region32 (pixman_region32_t * region, if (region->extents.x1 >= region->extents.x2 ||
region->extents.y1 >= region->extents.y2)
{
- pixman_region32_init (region);
return FALSE;
}
if (dst_image->common.have_clip_region)
{
if (!clip_general_image (region, &dst_image->common.clip_region, 0, 0))
- {
- pixman_region32_fini (region);
return FALSE;
- }
}
if (dst_image->common.alpha_map && dst_image->common.alpha_map->common.have_clip_region)
@@ -321,7 +317,6 @@ pixman_compute_composite_region32 (pixman_region32_t * region, -dst_image->common.alpha_origin_x,
-dst_image->common.alpha_origin_y))
{
- pixman_region32_fini (region);
return FALSE;
}
}
@@ -330,10 +325,7 @@ pixman_compute_composite_region32 (pixman_region32_t * region, if (src_image->common.have_clip_region)
{
if (!clip_source_image (region, src_image, dest_x - src_x, dest_y - src_y))
- {
- pixman_region32_fini (region);
return FALSE;
- }
}
if (src_image->common.alpha_map && src_image->common.alpha_map->common.have_clip_region)
{
@@ -341,7 +333,6 @@ pixman_compute_composite_region32 (pixman_region32_t * region, dest_x - (src_x - src_image->common.alpha_origin_x),
dest_y - (src_y - src_image->common.alpha_origin_y)))
{
- pixman_region32_fini (region);
return FALSE;
}
}
@@ -349,17 +340,14 @@ pixman_compute_composite_region32 (pixman_region32_t * region, if (mask_image && mask_image->common.have_clip_region)
{
if (!clip_source_image (region, mask_image, dest_x - mask_x, dest_y - mask_y))
- {
- pixman_region32_fini (region);
return FALSE;
- }
+
if (mask_image->common.alpha_map && mask_image->common.alpha_map->common.have_clip_region)
{
if (!clip_source_image (region, (pixman_image_t *)mask_image->common.alpha_map,
dest_x - (mask_x - mask_image->common.alpha_origin_x),
dest_y - (mask_y - mask_image->common.alpha_origin_y)))
{
- pixman_region32_fini (region);
return FALSE;
}
}
@@ -625,6 +613,9 @@ compute_sample_extents (pixman_transform_t *transform, {
int i;
+ /* Silence GCC */
+ tx1 = ty1 = tx2 = ty2 = 0;
+
for (i = 0; i < 4; ++i)
{
pixman_fixed_48_16_t tx, ty;
diff --git a/pixman/test/composite.c b/pixman/test/composite.c index 0624cd37d..426a887e3 100644 --- a/pixman/test/composite.c +++ b/pixman/test/composite.c @@ -1,901 +1,902 @@ -/* - * Copyright © 2005 Eric Anholt - * Copyright © 2009 Chris Wilson - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Eric Anholt not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Eric Anholt makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include <pixman.h> -#include <stdio.h> -#include <stdlib.h> /* abort() */ -#include <math.h> -#include <config.h> - -#define FALSE 0 -#define TRUE !FALSE - -#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 color_t colors[] = -{ - /* these are premultiplied in main() */ - { 1.0, 1.0, 1.0, 1.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.0, 0.0, 0.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); -} - -static const format_t formats[] = -{ -#define P(x) { PIXMAN_##x, #x } - P(a8), - - /* 32bpp formats */ - P(a8r8g8b8), - P(x8r8g8b8), - P(a8b8g8r8), - P(x8b8g8r8), - P(b8g8r8a8), - P(b8g8r8x8), - - /* XXX: and here the errors begin! */ -#if 0 - P(x2r10g10b10), - P(a2r10g10b10), - P(x2b10g10r10), - P(a2b10g10r10), - - /* 24bpp formats */ - P(r8g8b8), - P(b8g8r8), - - /* 16bpp formats */ - P(r5g6b5), - P(b5g6r5), - - P(a1r5g5b5), - P(x1r5g5b5), - P(a1b5g5r5), - P(x1b5g5r5), - P(a4r4g4b4), - P(x4r4g4b4), - P(a4b4g4r4), - P(x4b4g4r4), - - /* 8bpp formats */ - P(a8), - P(r3g3b2), - P(b2g3r3), - P(a2r2g2b2), - P(a2b2g2r2), - - P(x4a4), - - /* 4bpp formats */ - P(a4), - P(r1g2b1), - P(b1g2r1), - P(a1r1g1b1), - P(a1b1g1r1), - - /* 1bpp formats */ - P(a1) -#endif -#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 round_pix(pix, mask) \ - ((int)((pix) * (mask) + .5) / (double) (mask)) - - 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 -} - -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) -{ - double rscale, gscale, bscale, ascale; - double rdiff, gdiff, bdiff, adiff; - - /* XXX: Need to be provided mask shifts so we can produce useful error - * values. - */ - rscale = 1.0 * (1 << 5); - gscale = 1.0 * (1 << 6); - bscale = 1.0 * (1 << 5); - ascale = 1.0 * 32; - - 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); - 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; -} - -#define REPEAT 0x01000000 -#define FLAGS 0xff000000 - -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 = 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); -} - -int -main (void) -{ - pixman_bool_t ok, group_ok = TRUE, ca; - int i, d, m, s; - int tests_passed = 0, tests_total = 0; - int sizes[] = { 1, 1 | REPEAT, 10 }; - int num_tests; - - for (i = 0; i < ARRAY_LENGTH (colors); i++) - { - colors[i].r *= colors[i].a; - colors[i].g *= colors[i].a; - colors[i].b *= colors[i].a; - } - - num_tests = ARRAY_LENGTH (colors) * ARRAY_LENGTH (formats); - - for (d = 0; d < num_tests; d++) - { - image_t dst; - - image_init ( - &dst, d / ARRAY_LENGTH (formats), d % ARRAY_LENGTH (formats), 1); - - - for (s = -ARRAY_LENGTH (colors); - s < ARRAY_LENGTH (sizes) * num_tests; - s++) - { - image_t src; - - if (s < 0) - { - image_init (&src, -s - 1, 0, 0); - } - else - { - image_init (&src, - s / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats), - s / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats), - sizes[s % ARRAY_LENGTH (sizes)]); - } - - for (m = -ARRAY_LENGTH (colors); - m < ARRAY_LENGTH (sizes) * num_tests; - m++) - { - image_t mask; - - if (m < 0) - { - image_init (&mask, -m - 1, 0, 0); - } - else - { - image_init ( - &mask, - m / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats), - m / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats), - sizes[m % ARRAY_LENGTH (sizes)]); - } - - for (ca = -1; ca <= 1; ca++) - { - for (i = 0; i < ARRAY_LENGTH (operators); i++) - { - const operator_t *op = &operators[i]; - - switch (ca) - { - case -1: - ok = composite_test (&dst, op, &src, NULL, FALSE); - break; - case 0: - ok = composite_test (&dst, op, &src, &mask, FALSE); - break; - case 1: - ok = composite_test (&dst, op, &src, &mask, - mask.size? TRUE : FALSE); - break; - default: - break; - } - group_ok = group_ok && ok; - tests_passed += ok; - tests_total++; - } - } - - image_fini (&mask); - } - image_fini (&src); - } - image_fini (&dst); - } - - return group_ok == FALSE; -} +/*
+ * Copyright © 2005 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Eric Anholt not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Eric Anholt makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <pixman.h>
+#include <stdio.h>
+#include <stdlib.h> /* abort() */
+#include <math.h>
+#include <config.h>
+
+#define FALSE 0
+#define TRUE !FALSE
+
+#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 color_t colors[] =
+{
+ /* these are premultiplied in main() */
+ { 1.0, 1.0, 1.0, 1.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.0, 0.0, 0.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);
+}
+
+static const format_t formats[] =
+{
+#define P(x) { PIXMAN_##x, #x }
+ P(a8),
+
+ /* 32bpp formats */
+ P(a8r8g8b8),
+ P(x8r8g8b8),
+ P(a8b8g8r8),
+ P(x8b8g8r8),
+ P(b8g8r8a8),
+ P(b8g8r8x8),
+
+ /* XXX: and here the errors begin! */
+#if 0
+ P(x2r10g10b10),
+ P(a2r10g10b10),
+ P(x2b10g10r10),
+ P(a2b10g10r10),
+
+ /* 24bpp formats */
+ P(r8g8b8),
+ P(b8g8r8),
+
+ /* 16bpp formats */
+ P(r5g6b5),
+ P(b5g6r5),
+
+ P(a1r5g5b5),
+ P(x1r5g5b5),
+ P(a1b5g5r5),
+ P(x1b5g5r5),
+ P(a4r4g4b4),
+ P(x4r4g4b4),
+ P(a4b4g4r4),
+ P(x4b4g4r4),
+
+ /* 8bpp formats */
+ P(a8),
+ P(r3g3b2),
+ P(b2g3r3),
+ P(a2r2g2b2),
+ P(a2b2g2r2),
+
+ P(x4a4),
+
+ /* 4bpp formats */
+ P(a4),
+ P(r1g2b1),
+ P(b1g2r1),
+ P(a1r1g1b1),
+ P(a1b1g1r1),
+
+ /* 1bpp formats */
+ P(a1)
+#endif
+#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 round_pix(pix, mask) \
+ ((int)((pix) * (mask) + .5) / (double) (mask))
+
+ 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
+}
+
+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)
+{
+ double rscale, gscale, bscale, ascale;
+ double rdiff, gdiff, bdiff, adiff;
+
+ /* XXX: Need to be provided mask shifts so we can produce useful error
+ * values.
+ */
+ rscale = 1.0 * (1 << 5);
+ gscale = 1.0 * (1 << 6);
+ bscale = 1.0 * (1 << 5);
+ ascale = 1.0 * 32;
+
+ 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);
+ 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;
+}
+
+#define REPEAT 0x01000000
+#define FLAGS 0xff000000
+
+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 = 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);
+}
+
+int
+main (void)
+{
+ pixman_bool_t ok, group_ok = TRUE, ca;
+ int i, d, m, s;
+ int tests_passed = 0, tests_total = 0;
+ int sizes[] = { 1, 1 | REPEAT, 10 };
+ int num_tests;
+
+ for (i = 0; i < ARRAY_LENGTH (colors); i++)
+ {
+ colors[i].r *= colors[i].a;
+ colors[i].g *= colors[i].a;
+ colors[i].b *= colors[i].a;
+ }
+
+ num_tests = ARRAY_LENGTH (colors) * ARRAY_LENGTH (formats);
+
+ for (d = 0; d < num_tests; d++)
+ {
+ image_t dst;
+
+ image_init (
+ &dst, d / ARRAY_LENGTH (formats), d % ARRAY_LENGTH (formats), 1);
+
+
+ for (s = -ARRAY_LENGTH (colors);
+ s < ARRAY_LENGTH (sizes) * num_tests;
+ s++)
+ {
+ image_t src;
+
+ if (s < 0)
+ {
+ image_init (&src, -s - 1, 0, 0);
+ }
+ else
+ {
+ image_init (&src,
+ s / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats),
+ s / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats),
+ sizes[s % ARRAY_LENGTH (sizes)]);
+ }
+
+ for (m = -ARRAY_LENGTH (colors);
+ m < ARRAY_LENGTH (sizes) * num_tests;
+ m++)
+ {
+ image_t mask;
+
+ if (m < 0)
+ {
+ image_init (&mask, -m - 1, 0, 0);
+ }
+ else
+ {
+ image_init (
+ &mask,
+ m / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats),
+ m / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats),
+ sizes[m % ARRAY_LENGTH (sizes)]);
+ }
+
+ for (ca = -1; ca <= 1; ca++)
+ {
+ for (i = 0; i < ARRAY_LENGTH (operators); i++)
+ {
+ const operator_t *op = &operators[i];
+
+ switch (ca)
+ {
+ case -1:
+ ok = composite_test (&dst, op, &src, NULL, FALSE);
+ break;
+ case 0:
+ ok = composite_test (&dst, op, &src, &mask, FALSE);
+ break;
+ case 1:
+ ok = composite_test (&dst, op, &src, &mask,
+ mask.size? TRUE : FALSE);
+ break;
+ default:
+ ok = FALSE; /* Silence GCC */
+ break;
+ }
+ group_ok = group_ok && ok;
+ tests_passed += ok;
+ tests_total++;
+ }
+ }
+
+ image_fini (&mask);
+ }
+ image_fini (&src);
+ }
+ image_fini (&dst);
+ }
+
+ return group_ok == FALSE;
+}
|