pixman: Branch 'master' - 12 commits

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Tue Feb 12 23:36:02 PST 2013


 pixman/pixman-compiler.h       |    6 
 pixman/pixman-implementation.c |    9 -
 pixman/pixman-private.h        |   36 ----
 pixman/pixman-sse2.c           |    4 
 pixman/pixman-utils.c          |    4 
 test/Makefile.am               |    2 
 test/Makefile.sources          |    4 
 test/a1-trap-test.c            |    8 
 test/check-formats.c           |  352 +++++++++++++++++++++++++++++++++++++++++
 test/composite.c               |  277 --------------------------------
 test/lowlevel-blt-bench.c      |   14 -
 test/pixel-test.c              |  267 +++++++++++++++++++++++++++++++
 test/utils.c                   |  332 ++++++++++++++++++++++++++++++++++++++
 test/utils.h                   |   19 ++
 14 files changed, 1007 insertions(+), 327 deletions(-)

New commits:
commit 5e207f825bd1ed3142a623bcbceca00508907c5e
Author: Ben Avison <bavison at riscosopen.org>
Date:   Wed Feb 6 00:39:12 2013 +0000

    Fix to lowlevel-blt-bench
    
    The source, mask and destination buffers are initialised to 0xCC just after
    they are allocated. Between each benchmark, there are a pair of memcpys,
    from the destination buffer to the source buffer and back again (there are
    no explanatory comments, but presumably this is an effort to flush the
    caches). However, it has an unintended consequence, which is to change the
    contents of the buffers on entry to subsequent benchmarks. This means it is
    not a fair test: for example, with over_n_8888 (featured in the following
    patches) it reports L2 and even M tests as being faster than the L1 test,
    because after the L1 test, the source buffer is filled with fully opaque
    pixels, for which over_n_8888 has a shortcut.
    
    The fix here is simply to reverse the order of the memcpys, so src and
    destination are both filled with 0xCC on entry to all tests.

diff --git a/test/lowlevel-blt-bench.c b/test/lowlevel-blt-bench.c
index 8e80b42..4e16f7b 100644
--- a/test/lowlevel-blt-bench.c
+++ b/test/lowlevel-blt-bench.c
@@ -460,8 +460,8 @@ bench_composite (char * testname,
     printf ("%24s %c", testname, func != pixman_image_composite_wrapper ?
             '-' : '=');
 
-    memcpy (src, dst, BUFSIZE);
     memcpy (dst, src, BUFSIZE);
+    memcpy (src, dst, BUFSIZE);
 
     l1test_width = L1CACHE_SIZE / 8 - 64;
     if (l1test_width < 1)
@@ -480,8 +480,8 @@ bench_composite (char * testname,
             ((t3 - t2) - (t2 - t1)) / 1000000.);
     fflush (stdout);
 
-    memcpy (src, dst, BUFSIZE);
     memcpy (dst, src, BUFSIZE);
+    memcpy (src, dst, BUFSIZE);
 
     nlines = (L2CACHE_SIZE / l1test_width) /
 	((PIXMAN_FORMAT_BPP(src_fmt) + PIXMAN_FORMAT_BPP(dst_fmt)) / 8);
@@ -499,8 +499,8 @@ bench_composite (char * testname,
             ((t3 - t2) - (t2 - t1)) / 1000000.);
     fflush (stdout);
 
-    memcpy (src, dst, BUFSIZE);
     memcpy (dst, src, BUFSIZE);
+    memcpy (src, dst, BUFSIZE);
 
     n = 1 + npix / (WIDTH * HEIGHT);
     t1 = gettime ();
@@ -515,8 +515,8 @@ bench_composite (char * testname,
         ((double)n * (WIDTH - 64) * HEIGHT / ((t3 - t2) - (t2 - t1)) * bytes_per_pix) * (100.0 / bandwidth) );
     fflush (stdout);
 
-    memcpy (src, dst, BUFSIZE);
     memcpy (dst, src, BUFSIZE);
+    memcpy (src, dst, BUFSIZE);
 
     n = 1 + npix / (8 * TILEWIDTH * TILEWIDTH);
     t1 = gettime ();
@@ -529,8 +529,8 @@ bench_composite (char * testname,
     printf ("  HT:%6.2f", (double)pix_cnt / ((t3 - t2) - (t2 - t1)) / 1000000.);
     fflush (stdout);
 
-    memcpy (src, dst, BUFSIZE);
     memcpy (dst, src, BUFSIZE);
+    memcpy (src, dst, BUFSIZE);
 
     n = 1 + npix / (8 * TILEWIDTH * TILEWIDTH);
     t1 = gettime ();
@@ -543,8 +543,8 @@ bench_composite (char * testname,
     printf ("  VT:%6.2f", (double)pix_cnt / ((t3 - t2) - (t2 - t1)) / 1000000.);
     fflush (stdout);
 
-    memcpy (src, dst, BUFSIZE);
     memcpy (dst, src, BUFSIZE);
+    memcpy (src, dst, BUFSIZE);
 
     n = 1 + npix / (8 * TILEWIDTH * TILEWIDTH);
     t1 = gettime ();
@@ -557,8 +557,8 @@ bench_composite (char * testname,
     printf ("  R:%6.2f", (double)pix_cnt / ((t3 - t2) - (t2 - t1)) / 1000000.);
     fflush (stdout);
 
-    memcpy (src, dst, BUFSIZE);
     memcpy (dst, src, BUFSIZE);
+    memcpy (src, dst, BUFSIZE);
 
     n = 1 + npix / (16 * TINYWIDTH * TINYWIDTH);
     t1 = gettime ();
commit d26f922dc1a605dae00fa0540198707485ba1f08
Author: Stefan Weil <sw at weilnetz.de>
Date:   Sat Feb 9 12:40:16 2013 +0100

    sse2: Use uintptr_t in type casts from pointer to integral value
    
    Some recent code added new type casts from pointer to unsigned long.
    These type casts result in compiler warnings for systems like
    MinGW-w64 (64 bit Windows) where sizeof(unsigned long) != sizeof(void *).
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/pixman/pixman-sse2.c b/pixman/pixman-sse2.c
index fc873cc..c7e9a4b 100644
--- a/pixman/pixman-sse2.c
+++ b/pixman/pixman-sse2.c
@@ -4558,7 +4558,7 @@ sse2_composite_add_n_8888 (pixman_implementation_t *imp,
 	dst = dst_line;
 	dst_line += dst_stride;
 
-	while (w && (unsigned long)dst & 15)
+	while (w && (uintptr_t)dst & 15)
 	{
 	    d = *dst;
 	    *dst++ =
@@ -4617,7 +4617,7 @@ sse2_composite_add_n_8_8888 (pixman_implementation_t *imp,
 	mask_line += mask_stride;
 	w = width;
 
-	while (w && ((unsigned long)dst & 15))
+	while (w && ((uintptr_t)dst & 15))
 	{
 	    uint8_t m = *mask++;
 	    if (m)
commit dc80eb09e2831d5ad3bfe638462f80921357952b
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Thu Jan 31 14:54:49 2013 -0500

    lookup_composite: Don't update cache in case of error
    
    If we fail to find a composite function, don't update the fast path
    cache with the dummy compositing function.
    
    Also make the error message state that the bug is likely caused by
    issues with thread local storage.

diff --git a/pixman/pixman-implementation.c b/pixman/pixman-implementation.c
index c0a6436..cfb82bb 100644
--- a/pixman/pixman-implementation.c
+++ b/pixman/pixman-implementation.c
@@ -150,9 +150,16 @@ _pixman_implementation_lookup_composite (pixman_implementation_t  *toplevel,
     }
 
     /* We should never reach this point */
-    _pixman_log_error (FUNC, "No known composite function\n");
+    _pixman_log_error (
+        FUNC,
+        "No composite function found\n"
+        "\n"
+        "The most likely cause of this is that this system has issues with\n"
+        "thread local storage\n");
+
     *out_imp = NULL;
     *out_func = dummy_composite_rect;
+    return;
 
 update_cache:
     if (i)
commit 4dced81c917c753a4e699e3793efa15a39361cf0
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Thu Jan 31 14:36:38 2013 -0500

    Turn on error logging at all times
    
    While releasing 0.29.2 the distcheck run produced a number of error
    messages that had to be fixed in 349015e1fc5d912ba4253133b90e751d0b.
    These were not caught before so nobody had actually run pixman with
    debugging turned on. It's not the first time this has happened, see
    5b0563f39eb29e4ae431717696174da5 for example.
    
    So this patch makes the return_if_fail() macros use unlikely() around
    the expressions and then turns on error logging at all times. The
    performance hit should negligible since we were already evaluating the
    expressions.
    
    The place where DEBUG actually does cause a performance hit is in the
    region selfcheck code, and that will still only be enabled in
    development snapshots.

diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index cb78a2e..181ab5c 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -1014,15 +1014,13 @@ float pixman_unorm_to_float (uint16_t u, int n_bits);
 
 #endif
 
-#ifdef DEBUG
-
 void
 _pixman_log_error (const char *function, const char *message);
 
 #define return_if_fail(expr)                                            \
     do                                                                  \
     {                                                                   \
-	if (!(expr))							\
+	if (unlikely (!(expr)))                                         \
 	{								\
 	    _pixman_log_error (FUNC, "The expression " # expr " was false"); \
 	    return;							\
@@ -1033,7 +1031,7 @@ _pixman_log_error (const char *function, const char *message);
 #define return_val_if_fail(expr, retval)                                \
     do                                                                  \
     {                                                                   \
-	if (!(expr))                                                    \
+	if (unlikely (!(expr)))                                         \
 	{								\
 	    _pixman_log_error (FUNC, "The expression " # expr " was false"); \
 	    return (retval);						\
@@ -1044,39 +1042,11 @@ _pixman_log_error (const char *function, const char *message);
 #define critical_if_fail(expr)						\
     do									\
     {									\
-	if (!(expr))							\
+	if (unlikely (!(expr)))                                         \
 	    _pixman_log_error (FUNC, "The expression " # expr " was false"); \
     }									\
     while (0)
 
-
-#else
-
-#define _pixman_log_error(f,m) do { } while (0)
-
-#define return_if_fail(expr)						\
-    do                                                                  \
-    {                                                                   \
-	if (!(expr))							\
-	    return;							\
-    }                                                                   \
-    while (0)
-
-#define return_val_if_fail(expr, retval)                                \
-    do                                                                  \
-    {                                                                   \
-	if (!(expr))							\
-	    return (retval);						\
-    }                                                                   \
-    while (0)
-
-#define critical_if_fail(expr)						\
-    do									\
-    {									\
-    }									\
-    while (0)
-#endif
-
 /*
  * Matrix
  */
diff --git a/pixman/pixman-utils.c b/pixman/pixman-utils.c
index b1e9fb6..f31171f 100644
--- a/pixman/pixman-utils.c
+++ b/pixman/pixman-utils.c
@@ -292,8 +292,6 @@ _pixman_internal_only_get_implementation (void)
     return get_implementation ();
 }
 
-#ifdef DEBUG
-
 void
 _pixman_log_error (const char *function, const char *message)
 {
@@ -310,5 +308,3 @@ _pixman_log_error (const char *function, const char *message)
 	n_messages++;
     }
 }
-
-#endif
commit f4c9492c12d98f76d99b4dbdca56d517e1ffdb19
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Thu Jan 31 14:31:26 2013 -0500

    pixman-compiler.h: Add unlikely() macro
    
    When compiling with GCC this macro expands to __builtin_expect((expr), 0).
    On other compilers, it just expands to (expr).

diff --git a/pixman/pixman-compiler.h b/pixman/pixman-compiler.h
index 2e45dea..9b190b4 100644
--- a/pixman/pixman-compiler.h
+++ b/pixman/pixman-compiler.h
@@ -19,6 +19,12 @@
 #endif
 
 #if defined (__GNUC__)
+#  define unlikely(expr) __builtin_expect ((expr), 0)
+#else
+#  define unlikely(expr)  (expr)
+#endif
+
+#if defined (__GNUC__)
 #  define MAYBE_UNUSED  __attribute__((unused))
 #else
 #  define MAYBE_UNUSED
commit 5ebb5ac3807cdc7bb76358041a15cc5adca2ef23
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Tue Jan 22 08:29:57 2013 -0500

    utils.c: Increase acceptable deviation to 0.0064 in pixel_checker_t
    
    The check-formats programs reveals that the 8 bit pipeline cannot meet
    the current 0.004 acceptable deviation specified in utils.c, so we
    have to increase it. Some of the failing pixels were captured in
    pixel-test, which with this commit now passes.
    
    == a4r4g4b4 DISJOINT_XOR a8r8g8b8 ==
    
    The DISJOINT_XOR operator applied to an a4r4g4b4 source pixel of
    0xd0c0 and a destination pixel of 0x5300ea00 results in the exact
    value:
    
        fa = (1 - da) / sa = (1 - 0x53 / 255.0) / (0xd / 15.0) = 0.7782
        fb = (1 - sa) / da = (1 - 0xd / 15.0) / (0x53 / 255.0) = 0.4096
    
        r = fa * (0xc / 15.0) + fb * (0xea / 255.0) = 0.99853
    
    But when computing in 8 bits, we get:
    
        fa8 = ((255 - 0x53) * 255 + 0xdd / 2) / 0xdd = 0xc6
        fb8 = ((255 - 0xdd) * 255 + 0x53 / 3) / 0x53 = 0x68
    
        r8 = (fa8 * 0xcc + 127) / 255 + (fb8 * 0xea + 127) / 255 = 0xfd
    
    and
    
        0xfd / 255.0 = 0.9921568627450981
    
    for a deviation of 0.00637118610187, which we then have to consider
    acceptable given the current implementation.
    
    By switching to computing the result with
    
       r = (fa * s + fb * d + 127) / 255
    
    rather than
    
       r = (fa * s + 127) / 255 + (fb * d + 127) / 255
    
    the deviation would be only 0.00244961747442, so at some point it may
    be worth doing either this, or switching to floating point for
    operators that involve divisions.
    
    Note that the conversion from 4 bits to 8 bits does not cause any
    error in this case because both rounding and bit replication produces
    an exact result when the number of from-bits divide the number of
    to-bits.
    
    == a8r8g8b8 OVER r5g6b5 ==
    
    When OVER compositing the a8r8g8b8 pixel 0x0f00c300 with the x14r6g6b6
    pixel 0x03c0, the true floating point value of the resulting green
    channel is:
    
       0xc3 / 255.0 + (1.0 - 0x0f / 255.0) * (0x0f / 63.0) = 0.9887955
    
    but when compositing 8 bit values, where the 6-bit green channel is
    converted to 8 bit through bit replication, the 8-bit result is:
    
       0xc3 + ((255 - 0x0f) * 0x3c + 127) / 255 = 251
    
    which corresponds to a real value of 0.984314. The difference from the
    true value is 0.004482 which is bigger than the acceptable deviation
    of 0.004. So, if we were to compute all the CONJOINT/DISJOINT
    operators in floating point, or otherwise make them more accurate, the
    acceptable deviation could be set at 0.0045.
    
    If we were doing the 6-bit conversion with rounding:
    
       (x / 63.0 * 255.0 + 0.5)
    
    instead of bit replication, the deviation in this particular case
    would be only 0.0005, so we may want to consider this at some
    point.

diff --git a/test/utils.c b/test/utils.c
index 9a8decf..3d1ba22 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -1513,7 +1513,7 @@ get_limits (const pixel_checker_t *checker, double limit,
 
 /* The acceptable deviation in units of [0.0, 1.0]
  */
-#define DEVIATION (0.004)
+#define DEVIATION (0.0064)
 
 void
 pixel_checker_get_max (const pixel_checker_t *checker, color_t *color,
commit f2ba7fe1d812a30004b734e398f45b586833d43f
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sat Jan 19 16:32:15 2013 -0500

    test: Add new pixel-test regression test
    
    This test program contains a table of individual operator/pixel
    combinations. For each pixel combination, images of various sizes are
    filled with the pixels and then composited. The result is then
    verified against the output of do_composite(). If the result doesn't
    match, detailed error information is printed.
    
    The initial 14 pixel combinations currently all fail.

diff --git a/test/Makefile.sources b/test/Makefile.sources
index 9d0bd0f..5b30970 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -6,6 +6,7 @@ TESTPROGRAMS =			\
 	region-test		\
 	region-translate-test	\
 	combiner-test		\
+	pixel-test		\
 	fetch-test		\
 	rotate-test		\
 	oob-test		\
diff --git a/test/pixel-test.c b/test/pixel-test.c
new file mode 100644
index 0000000..8c525d2
--- /dev/null
+++ b/test/pixel-test.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright © 2013 Soeren Sandmann
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h> /* abort() */
+#include <math.h>
+#include <time.h>
+#include "utils.h"
+
+typedef struct pixel_combination_t pixel_combination_t;
+struct pixel_combination_t
+{
+    pixman_op_t			op;
+    pixman_format_code_t	src_format;
+    uint32_t			src_pixel;
+    pixman_format_code_t	dest_format;
+    uint32_t			dest_pixel;
+};
+
+static const pixel_combination_t regressions[] =
+{
+    { PIXMAN_OP_OVER,
+      PIXMAN_a8r8g8b8,	0x0f00c300,
+      PIXMAN_x14r6g6b6,	0x003c0,
+    },
+    { PIXMAN_OP_DISJOINT_XOR,
+      PIXMAN_a4r4g4b4,	0xd0c0,
+      PIXMAN_a8r8g8b8,	0x5300ea00,
+    },
+    { PIXMAN_OP_OVER,
+      PIXMAN_a8r8g8b8,	0x20c6bf00,
+      PIXMAN_r5g6b5,	0xb9ff
+    },
+    { PIXMAN_OP_OVER,
+      PIXMAN_a8r8g8b8,	0x204ac7ff,
+      PIXMAN_r5g6b5,	0xc1ff
+    },
+    { PIXMAN_OP_OVER_REVERSE,
+      PIXMAN_r5g6b5,	0xffc3,
+      PIXMAN_a8r8g8b8,	0x102d00dd
+    },
+    { PIXMAN_OP_OVER_REVERSE,
+      PIXMAN_r5g6b5,	0x1f00,
+      PIXMAN_a8r8g8b8,	0x1bdf0c89
+    },
+    { PIXMAN_OP_OVER_REVERSE,
+      PIXMAN_r5g6b5,	0xf9d2,
+      PIXMAN_a8r8g8b8,	0x1076bcf7
+    },
+    { PIXMAN_OP_OVER_REVERSE,
+      PIXMAN_r5g6b5,	0x00c3,
+      PIXMAN_a8r8g8b8,	0x1bfe9ae5
+    },
+    { PIXMAN_OP_OVER_REVERSE,
+      PIXMAN_r5g6b5,	0x09ff,
+      PIXMAN_a8r8g8b8,	0x0b00c16c
+    },
+    { PIXMAN_OP_DISJOINT_ATOP,
+      PIXMAN_a2r2g2b2,	0xbc,
+      PIXMAN_a8r8g8b8,	0x9efff1ff
+    },
+    { PIXMAN_OP_DISJOINT_ATOP,
+      PIXMAN_a4r4g4b4,	0xae5f,
+      PIXMAN_a8r8g8b8,	0xf215b675
+    },
+    { PIXMAN_OP_DISJOINT_ATOP_REVERSE,
+      PIXMAN_a8r8g8b8,	0xce007980,
+      PIXMAN_a8r8g8b8,	0x80ffe4ad
+    },
+    { PIXMAN_OP_DISJOINT_XOR,
+      PIXMAN_a8r8g8b8,	0xb8b07bea,
+      PIXMAN_a4r4g4b4,	0x939c
+    },
+    { PIXMAN_OP_CONJOINT_ATOP_REVERSE,
+      PIXMAN_r5g6b5,	0x0063,
+      PIXMAN_a8r8g8b8,	0x10bb1ed7,
+    },
+};
+
+static void
+fill (pixman_image_t *image, uint32_t pixel)
+{
+    uint8_t *data = (uint8_t *)pixman_image_get_data (image);
+    int bytes_per_pixel = PIXMAN_FORMAT_BPP (pixman_image_get_format (image)) / 8;
+    int n_bytes = pixman_image_get_stride (image) * pixman_image_get_height (image);
+    int i;
+
+    switch (bytes_per_pixel)
+    {
+    case 4:
+	for (i = 0; i < n_bytes / 4; ++i)
+	    ((uint32_t *)data)[i] = pixel;
+	break;
+
+    case 2:
+	pixel &= 0xffff;
+	for (i = 0; i < n_bytes / 2; ++i)
+	    ((uint16_t *)data)[i] = pixel;
+	break;
+
+    case 1:
+	pixel &= 0xff;
+	for (i = 0; i < n_bytes; ++i)
+	    ((uint8_t *)data)[i] = pixel;
+	break;
+
+    default:
+	assert (0);
+	break;
+    }
+}
+
+static uint32_t
+access (pixman_image_t *image, int x, int y)
+{
+    int bytes_per_pixel;
+    int stride;
+    uint32_t result;
+    uint8_t *location;
+
+    if (x < 0 || x >= image->bits.width || y < 0 || y >= image->bits.height)
+        return 0;
+
+    bytes_per_pixel = PIXMAN_FORMAT_BPP (image->bits.format) / 8;
+    stride = image->bits.rowstride * 4;
+
+    location = (uint8_t *)image->bits.bits + y * stride + x * bytes_per_pixel;
+
+    if (bytes_per_pixel == 4)
+        result = *(uint32_t *)location;
+    else if (bytes_per_pixel == 2)
+        result = *(uint16_t *)location;
+    else if (bytes_per_pixel == 1)
+        result = *(uint8_t *)location;
+    else
+	assert (0);
+
+    return result;
+}
+
+static pixman_bool_t
+verify (int test_no, const pixel_combination_t *combination, int size)
+{
+    pixman_image_t *src, *dest;
+    pixel_checker_t src_checker, dest_checker;
+    color_t source_color, dest_color, reference_color;
+    pixman_bool_t result = TRUE;
+    int i, j;
+
+    /* Compute reference color */
+    pixel_checker_init (&src_checker, combination->src_format);
+    pixel_checker_init (&dest_checker, combination->dest_format);
+    pixel_checker_convert_pixel_to_color (
+	&src_checker, combination->src_pixel, &source_color);
+    pixel_checker_convert_pixel_to_color (
+	&dest_checker, combination->dest_pixel, &dest_color);
+    do_composite (combination->op,
+		  &source_color, NULL, &dest_color,
+		  &reference_color, FALSE);
+
+    src = pixman_image_create_bits (
+	combination->src_format, size, size, NULL, -1);
+    dest = pixman_image_create_bits (
+	combination->dest_format, size, size, NULL, -1);
+
+    fill (src, combination->src_pixel);
+    fill (dest, combination->dest_pixel);
+
+    pixman_image_composite32 (
+	combination->op, src, NULL, dest, 0, 0, 0, 0, 0, 0, size, size);
+
+    for (j = 0; j < size; ++j)
+    {
+	for (i = 0; i < size; ++i)
+	{
+	    uint32_t computed = access (dest, i, j);
+	    int32_t a, r, g, b;
+
+	    if (!pixel_checker_check (&dest_checker, computed, &reference_color))
+	    {
+		printf ("----------- Test %d failed ----------\n", test_no);
+
+		printf ("   operator:         %s\n", operator_name (combination->op));
+		printf ("   src format:       %s\n", format_name (combination->src_format));
+		printf ("   dest format:      %s\n", format_name (combination->dest_format));
+                printf (" - source ARGB:      %f  %f  %f  %f   (pixel: %8x)\n",
+                        source_color.a, source_color.r, source_color.g, source_color.b,
+                        combination->src_pixel);
+		pixel_checker_split_pixel (&src_checker, combination->src_pixel,
+					   &a, &r, &g, &b);
+                printf ("                     %8d  %8d  %8d  %8d\n", a, r, g, b);
+
+                printf (" - dest ARGB:        %f  %f  %f  %f   (pixel: %8x)\n",
+                        dest_color.a, dest_color.r, dest_color.g, dest_color.b,
+                        combination->dest_pixel);
+		pixel_checker_split_pixel (&dest_checker, combination->dest_pixel,
+					   &a, &r, &g, &b);
+                printf ("                     %8d  %8d  %8d  %8d\n", a, r, g, b);
+
+                pixel_checker_split_pixel (&dest_checker, computed, &a, &r, &g, &b);
+                printf (" - expected ARGB:    %f  %f  %f  %f\n",
+                        reference_color.a, reference_color.r, reference_color.g, reference_color.b);
+
+                pixel_checker_get_min (&dest_checker, &reference_color, &a, &r, &g, &b);
+                printf ("   min acceptable:   %8d  %8d  %8d  %8d\n", a, r, g, b);
+
+                pixel_checker_split_pixel (&dest_checker, computed, &a, &r, &g, &b);
+                printf ("   got:              %8d  %8d  %8d  %8d   (pixel: %8x)\n", a, r, g, b, computed);
+
+                pixel_checker_get_max (&dest_checker, &reference_color, &a, &r, &g, &b);
+                printf ("   max acceptable:   %8d  %8d  %8d  %8d\n", a, r, g, b);
+
+		result = FALSE;
+		goto done;
+	    }
+	}
+    }
+
+done:
+    pixman_image_unref (src);
+    pixman_image_unref (dest);
+
+    return result;
+}
+
+int
+main (int argc, char **argv)
+{
+    int result = 0;
+    int i, j;
+
+    for (i = 0; i < ARRAY_LENGTH (regressions); ++i)
+    {
+	const pixel_combination_t *combination = &(regressions[i]);
+
+	for (j = 1; j < 34; ++j)
+	{
+	    if (!verify (i, combination, j))
+	    {
+		result = 1;
+		break;
+	    }
+	}
+    }
+
+    return result;
+}
commit 6781636740099633b9a8f7e0cc8e7828770f2fc3
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Mon Jan 21 15:02:53 2013 -0500

    a1-trap-test: Add tests for operator_name and format_name()
    
    The check-formats.c test depends on the exact format of the strings
    returned from these functions, so add a test here.
    
    a1-trap-test isn't the ideal place, but it seems like overkill to add
    a new test just for these trivial checks.

diff --git a/test/a1-trap-test.c b/test/a1-trap-test.c
index 93c6caa..c2b4883 100644
--- a/test/a1-trap-test.c
+++ b/test/a1-trap-test.c
@@ -45,6 +45,14 @@ main (int argc, char **argv)
     assert (bits[1] == 0xffffffff);
     assert (bits[1 * WIDTH + 0] == 0xffffffff);
     assert (bits[1 * WIDTH + 1] == 0xffffffff);
+
+    /* The check-formats test depends on operator_name() and format_name() returning
+     * these precise formats, so if those change, check-formats.c must be updated too.
+     */
+    assert (
+        strcmp (operator_name (PIXMAN_OP_DISJOINT_OVER), "PIXMAN_OP_DISJOINT_OVER") == 0);
+    assert (
+        strcmp (format_name (PIXMAN_r5g6b5), "r5g6b5") == 0);
     
     return 0;
 }
commit d1434d112ca5cd325e4fb85fc60afd1b9e902786
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Mon Jan 21 15:54:05 2013 -0500

    test: Add new check-formats utility
    
    Given an operator and two formats, this program will composite and
    check all pixels where the red and blue channels are 0. That is, if
    the two formats are a8r8g8b8 and a4r4g4b4, all source pixels matching
    the mask
    
        0xff00ff00
    
    are composited with the given operator against all destination pixels
    matching the mask
    
        0xf0f0
    
    and the result is then verified against the do_composite() function
    that was moved to utils.c earlier.
    
    This program reveals that a number of operators and format
    combinations are not computed to within the precision currently
    accepted by pixel_checker_t. For example:
    
        check-formats over a8r8g8b8 r5g6b5 | grep failed | wc -l
        30
    
    reveals that there are 30 pixel combinations where OVER produces
    insufficiently precise results for the a8r8g8b8 and r5g6b5 formats.

diff --git a/test/Makefile.am b/test/Makefile.am
index ca87f4e..5d901d5 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -8,6 +8,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/pixman -I$(top_builddir)/pixman $(PNG_CFLAGS)
 libutils_la_SOURCES = $(libutils_sources) $(libutils_headers)
 
 noinst_LTLIBRARIES = libutils.la
-noinst_PROGRAMS = $(TESTPROGRAMS) $(BENCHMARKS)
+noinst_PROGRAMS = $(TESTPROGRAMS) $(OTHERPROGRAMS)
 
 TESTS = $(TESTPROGRAMS)
diff --git a/test/Makefile.sources b/test/Makefile.sources
index e323a8e..9d0bd0f 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -28,8 +28,9 @@ TESTPROGRAMS =			\
 	$(NULL)
 
 # Benchmarks
-BENCHMARKS =			\
+OTHERPROGRAMS =                 \
 	lowlevel-blt-bench	\
+        check-formats           \
 	$(NULL)
 
 # Utility functions
diff --git a/test/check-formats.c b/test/check-formats.c
new file mode 100644
index 0000000..7edc198
--- /dev/null
+++ b/test/check-formats.c
@@ -0,0 +1,352 @@
+#include <ctype.h>
+#include "utils.h"
+
+static int
+check_op (pixman_op_t          op,
+          pixman_format_code_t src_format,
+          pixman_format_code_t dest_format)
+{
+    uint32_t src_alpha_mask, src_green_mask;
+    uint32_t dest_alpha_mask, dest_green_mask;
+    pixel_checker_t src_checker, dest_checker;
+    pixman_image_t *si, *di;
+    uint32_t sa, sg, da, dg;
+    uint32_t s, d;
+    int retval = 0;
+
+    pixel_checker_init (&src_checker, src_format);
+    pixel_checker_init (&dest_checker, dest_format);
+
+    pixel_checker_get_masks (
+        &src_checker, &src_alpha_mask, NULL, &src_green_mask, NULL);
+    pixel_checker_get_masks (
+        &dest_checker, &dest_alpha_mask, NULL, &dest_green_mask, NULL);
+
+    /* printf ("masks: %x %x %x %x\n", */
+    /* 	    src_alpha_mask, src_green_mask, */
+    /* 	    dest_alpha_mask, dest_green_mask); */
+
+    si = pixman_image_create_bits (src_format, 1, 1, &s, 4);
+    di = pixman_image_create_bits (dest_format, 1, 1, &d, 4);
+
+    sa = 0;
+    do
+    {
+        sg = 0;
+        do
+        {
+            da = 0;
+            do
+            {
+                dg = 0;
+                do
+                {
+                    color_t src_color, dest_color, result_color;
+                    uint32_t orig_d;
+
+                    s = sa | sg;
+                    d = da | dg;
+
+                    orig_d = d;
+
+		    pixel_checker_convert_pixel_to_color (&src_checker, s, &src_color);
+		    pixel_checker_convert_pixel_to_color (&dest_checker, d, &dest_color);
+
+		    do_composite (op, &src_color, NULL, &dest_color, &result_color, FALSE);
+
+
+		    if (!is_little_endian())
+                    {
+			s <<= 32 - PIXMAN_FORMAT_BPP (src_format);
+			d <<= 32 - PIXMAN_FORMAT_BPP (dest_format);
+                    }
+
+		    pixman_image_composite32 (op, si, NULL, di,
+					      0, 0, 0, 0, 0, 0, 1, 1);
+
+		    if (!is_little_endian())
+                        d >>= (32 - PIXMAN_FORMAT_BPP (dest_format));
+
+                    if (!pixel_checker_check (&dest_checker, d, &result_color))
+                    {
+                        printf ("---- test failed ----\n");
+                        printf ("operator: %-32s\n", operator_name (op));
+                        printf ("source:   %-12s pixel: %08x\n", format_name (src_format), s);
+                        printf ("dest:     %-12s pixel: %08x\n", format_name (dest_format), orig_d);
+                        printf ("got:      %-12s pixel: %08x\n", format_name (dest_format), d);
+
+                        retval = 1;
+                    }
+
+                    dg -= dest_green_mask;
+                    dg &= dest_green_mask;
+                }
+                while (dg != 0);
+
+                da -= dest_alpha_mask;
+                da &= dest_alpha_mask;
+            }
+            while (da != 0);
+
+            sg -= src_green_mask;
+            sg &= src_green_mask;
+        }
+        while (sg != 0);
+
+        sa -= src_alpha_mask;
+        sa &= src_alpha_mask;
+    }
+    while (sa != 0);
+
+    pixman_image_unref (si);
+    pixman_image_unref (di);
+
+    return retval;
+}
+
+static const pixman_op_t op_list[] =
+{
+    PIXMAN_OP_CLEAR,
+    PIXMAN_OP_SRC,
+    PIXMAN_OP_DST,
+    PIXMAN_OP_OVER,
+    PIXMAN_OP_OVER_REVERSE,
+    PIXMAN_OP_IN,
+    PIXMAN_OP_IN_REVERSE,
+    PIXMAN_OP_OUT,
+    PIXMAN_OP_OUT_REVERSE,
+    PIXMAN_OP_ATOP,
+    PIXMAN_OP_ATOP_REVERSE,
+    PIXMAN_OP_XOR,
+    PIXMAN_OP_ADD,
+    PIXMAN_OP_SATURATE,
+
+    PIXMAN_OP_DISJOINT_CLEAR,
+    PIXMAN_OP_DISJOINT_SRC,
+    PIXMAN_OP_DISJOINT_DST,
+    PIXMAN_OP_DISJOINT_OVER,
+    PIXMAN_OP_DISJOINT_OVER_REVERSE,
+    PIXMAN_OP_DISJOINT_IN,
+    PIXMAN_OP_DISJOINT_IN_REVERSE,
+    PIXMAN_OP_DISJOINT_OUT,
+    PIXMAN_OP_DISJOINT_OUT_REVERSE,
+    PIXMAN_OP_DISJOINT_ATOP,
+    PIXMAN_OP_DISJOINT_ATOP_REVERSE,
+    PIXMAN_OP_DISJOINT_XOR,
+
+    PIXMAN_OP_CONJOINT_CLEAR,
+    PIXMAN_OP_CONJOINT_SRC,
+    PIXMAN_OP_CONJOINT_DST,
+    PIXMAN_OP_CONJOINT_OVER,
+    PIXMAN_OP_CONJOINT_OVER_REVERSE,
+    PIXMAN_OP_CONJOINT_IN,
+    PIXMAN_OP_CONJOINT_IN_REVERSE,
+    PIXMAN_OP_CONJOINT_OUT,
+    PIXMAN_OP_CONJOINT_OUT_REVERSE,
+    PIXMAN_OP_CONJOINT_ATOP,
+    PIXMAN_OP_CONJOINT_ATOP_REVERSE,
+    PIXMAN_OP_CONJOINT_XOR,
+};
+
+static const pixman_format_code_t format_list[] =
+{
+    PIXMAN_a8r8g8b8,
+    PIXMAN_x8r8g8b8,
+    PIXMAN_a8b8g8r8,
+    PIXMAN_x8b8g8r8,
+    PIXMAN_b8g8r8a8,
+    PIXMAN_b8g8r8x8,
+    PIXMAN_r8g8b8a8,
+    PIXMAN_r8g8b8x8,
+    PIXMAN_x14r6g6b6,
+    PIXMAN_x2r10g10b10,
+    PIXMAN_a2r10g10b10,
+    PIXMAN_x2b10g10r10,
+    PIXMAN_a2b10g10r10,
+    PIXMAN_a8r8g8b8_sRGB,
+    PIXMAN_r8g8b8,
+    PIXMAN_b8g8r8,
+    PIXMAN_r5g6b5,
+    PIXMAN_b5g6r5,
+    PIXMAN_a1r5g5b5,
+    PIXMAN_x1r5g5b5,
+    PIXMAN_a1b5g5r5,
+    PIXMAN_x1b5g5r5,
+    PIXMAN_a4r4g4b4,
+    PIXMAN_x4r4g4b4,
+    PIXMAN_a4b4g4r4,
+    PIXMAN_x4b4g4r4,
+    PIXMAN_a8,
+    PIXMAN_r3g3b2,
+    PIXMAN_b2g3r3,
+    PIXMAN_a2r2g2b2,
+    PIXMAN_a2b2g2r2,
+    PIXMAN_x4a4,
+    PIXMAN_a4,
+    PIXMAN_r1g2b1,
+    PIXMAN_b1g2r1,
+    PIXMAN_a1r1g1b1,
+    PIXMAN_a1b1g1r1,
+    PIXMAN_a1,
+};
+
+static pixman_format_code_t
+format_from_string (const char *s)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_LENGTH (format_list); ++i)
+    {
+        if (strcasecmp (format_name (format_list[i]), s) == 0)
+            return format_list[i];
+    }
+
+    return PIXMAN_null;
+}
+
+static void
+emit (const char *s, int *n_chars)
+{
+    *n_chars += printf ("%s,", s);
+    if (*n_chars > 60)
+    {
+        printf ("\n    ");
+        *n_chars = 0;
+    }
+    else
+    {
+        printf (" ");
+        (*n_chars)++;
+    }
+}
+
+static void
+list_formats (void)
+{
+    int n_chars;
+    int i;
+
+    printf ("Formats:\n    ");
+
+    n_chars = 0;
+    for (i = 0; i < ARRAY_LENGTH (format_list); ++i)
+        emit (format_name (format_list[i]), &n_chars);
+
+    printf ("\n\n");
+}
+
+static void
+list_operators (void)
+{
+    char short_name [128] = { 0 };
+    int i, n_chars;
+
+    printf ("Operators:\n    ");
+
+    n_chars = 0;
+    for (i = 0; i < ARRAY_LENGTH (op_list); ++i)
+    {
+        pixman_op_t op = op_list[i];
+        int j;
+
+        snprintf (short_name, sizeof (short_name) - 1, "%s",
+                  operator_name (op) + strlen ("PIXMAN_OP_"));
+
+        for (j = 0; short_name[j] != '\0'; ++j)
+            short_name[j] = tolower (short_name[j]);
+
+        emit (short_name, &n_chars);
+    }
+
+    printf ("\n\n");
+}
+
+static pixman_op_t
+operator_from_string (const char *s)
+{
+    char full_name[128] = { 0 };
+    int i;
+
+    snprintf (full_name, (sizeof full_name) - 1, "PIXMAN_OP_%s", s);
+
+    for (i = 0; i < ARRAY_LENGTH (op_list); ++i)
+    {
+        pixman_op_t op = op_list[i];
+
+        if (strcasecmp (operator_name (op), full_name) == 0)
+            return op;
+    }
+
+    return PIXMAN_OP_NONE;
+}
+
+int
+main (int argc, char **argv)
+{
+    enum { OPTION_OP, OPTION_SRC, OPTION_DEST, LAST_OPTION } option;
+    pixman_format_code_t src_fmt, dest_fmt;
+    pixman_op_t op;
+
+    op = PIXMAN_OP_NONE;
+    src_fmt = PIXMAN_null;
+    dest_fmt = PIXMAN_null;
+
+    argc--;
+    argv++;
+
+    for (option = OPTION_OP; option < LAST_OPTION; ++option)
+    {
+        char *arg = NULL;
+
+        if (argc)
+        {
+            argc--;
+            arg = *argv++;
+        }
+
+        switch (option)
+        {
+        case OPTION_OP:
+            if (!arg)
+                printf ("  - missing operator\n");
+            else if ((op = operator_from_string (arg)) == PIXMAN_OP_NONE)
+                printf ("  - unknown operator %s\n", arg);
+            break;
+
+        case OPTION_SRC:
+            if (!arg)
+                printf ("  - missing source format\n");
+            else if ((src_fmt = format_from_string (arg)) == PIXMAN_null)
+                printf ("  - unknown source format %s\n", arg);
+            break;
+
+        case OPTION_DEST:
+            if (!arg)
+                printf ("  - missing destination format\n");
+            else if ((dest_fmt = format_from_string (arg)) == PIXMAN_null)
+                printf ("  - unknown destination format %s\n", arg);
+            break;
+
+        default:
+            assert (0);
+            break;
+        }
+    }
+
+    while (argc--)
+    {
+        op = PIXMAN_OP_NONE;
+        printf ("  - unexpected argument: %s\n", *argv++);
+    }
+
+    if (op == PIXMAN_OP_NONE || src_fmt == PIXMAN_null || dest_fmt == PIXMAN_null)
+    {
+        printf ("\nUsage:\n    check-formats <operator> <src-format> <dest-format>\n\n");
+        list_operators();
+        list_formats();
+
+        return -1;
+    }
+
+    return check_op (op, src_fmt, dest_fmt);
+}
commit 1820131fe6674d46b9876965b30b331d593124a8
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Tue Jan 22 07:36:19 2013 -0500

    utils.[ch]: Add pixel_checker_get_masks()
    
    This function returns the a, r, g, and b masks corresponding to the
    pixel checker's format.

diff --git a/test/utils.c b/test/utils.c
index eed2476..9a8decf 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -1422,6 +1422,23 @@ pixel_checker_split_pixel (const pixel_checker_t *checker, uint32_t pixel,
 }
 
 void
+pixel_checker_get_masks (const pixel_checker_t *checker,
+                         uint32_t              *am,
+                         uint32_t              *rm,
+                         uint32_t              *gm,
+                         uint32_t              *bm)
+{
+    if (am)
+        *am = checker->am;
+    if (rm)
+        *rm = checker->rm;
+    if (gm)
+        *gm = checker->gm;
+    if (bm)
+        *bm = checker->bm;
+}
+
+void
 pixel_checker_convert_pixel_to_color (const pixel_checker_t *checker,
                                       uint32_t pixel, color_t *color)
 {
diff --git a/test/utils.h b/test/utils.h
index f6dc193..c278151 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -229,3 +229,10 @@ pixel_checker_check (const pixel_checker_t *checker,
 void
 pixel_checker_convert_pixel_to_color (const pixel_checker_t *checker,
                                       uint32_t pixel, color_t *color);
+
+void
+pixel_checker_get_masks (const pixel_checker_t *checker,
+                         uint32_t              *am,
+                         uint32_t              *rm,
+                         uint32_t              *gm,
+                         uint32_t              *bm);
commit 5eb61f72ea50e02eb185c746108909945b589e65
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Tue Jan 22 11:57:53 2013 -0500

    test/utils.[ch]: Add pixel_checker_convert_pixel_to_color()
    
    This function takes a pixel in the format corresponding to the pixel
    checker, and converts to a color_t.

diff --git a/test/utils.c b/test/utils.c
index 27d8fd9..eed2476 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -1421,6 +1421,42 @@ pixel_checker_split_pixel (const pixel_checker_t *checker, uint32_t pixel,
     *b = (pixel & checker->bm) >> checker->bs;
 }
 
+void
+pixel_checker_convert_pixel_to_color (const pixel_checker_t *checker,
+                                      uint32_t pixel, color_t *color)
+{
+    int a, r, g, b;
+
+    pixel_checker_split_pixel (checker, pixel, &a, &r, &g, &b);
+
+    if (checker->am == 0)
+        color->a = 1.0;
+    else
+        color->a = a / (double)(checker->am >> checker->as);
+
+    if (checker->rm == 0)
+        color->r = 0.0;
+    else
+        color->r = r / (double)(checker->rm >> checker->rs);
+
+    if (checker->gm == 0)
+        color->g = 0.0;
+    else
+        color->g = g / (double)(checker->gm >> checker->gs);
+
+    if (checker->bm == 0)
+        color->b = 0.0;
+    else
+        color->b = b / (double)(checker->bm >> checker->bs);
+
+    if (PIXMAN_FORMAT_TYPE (checker->format) == PIXMAN_TYPE_ARGB_SRGB)
+    {
+	color->r = convert_srgb_to_linear (color->r);
+	color->g = convert_srgb_to_linear (color->g);
+	color->b = convert_srgb_to_linear (color->b);
+    }
+}
+
 static int32_t
 convert (double v, uint32_t width, uint32_t mask, uint32_t shift, double def)
 {
diff --git a/test/utils.h b/test/utils.h
index 162aacb..f6dc193 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -225,3 +225,7 @@ pixel_checker_get_min (const pixel_checker_t *checker, color_t *color,
 pixman_bool_t
 pixel_checker_check (const pixel_checker_t *checker,
 		     uint32_t pixel, color_t *color);
+
+void
+pixel_checker_convert_pixel_to_color (const pixel_checker_t *checker,
+                                      uint32_t pixel, color_t *color);
commit 3ae717f71a31620a5cb28792b9effd0c69ffb822
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sat Jan 19 12:14:24 2013 -0500

    test: Move do_composite() function from composite.c to utils.c
    
    So that it can be used in other tests.

diff --git a/test/composite.c b/test/composite.c
index b107b11..9e51a8f 100644
--- a/test/composite.c
+++ b/test/composite.c
@@ -181,283 +181,6 @@ static const pixman_op_t operators[] =
     PIXMAN_OP_CONJOINT_XOR,
 };
 
-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 uint32_t
 get_value (pixman_image_t *image)
 {
diff --git a/test/utils.c b/test/utils.c
index ba7e353..27d8fd9 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -1033,6 +1033,283 @@ format_name (pixman_format_code_t format)
 };
 
 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
+}
+
+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 double
 round_channel (double p, int m)
 {
     int t;
diff --git a/test/utils.h b/test/utils.h
index 4988314..162aacb 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -189,6 +189,14 @@ typedef struct
 } color_t;
 
 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);
+
+void
 round_color (pixman_format_code_t format, color_t *color);
 
 typedef struct


More information about the xorg-commit mailing list