pixman: Branch 'master' - 9 commits

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Sun Mar 14 09:36:34 PDT 2010


 pixman/pixman-compiler.h |    9 +
 pixman/pixman-private.h  |    2 
 pixman/pixman.c          |  281 ++++++++++++++++++++++++++++++-----------------
 pixman/pixman.h          |    5 
 test/blitters-test.c     |   27 ++++
 5 files changed, 225 insertions(+), 99 deletions(-)

New commits:
commit ff30a5cbb941a9559082c6a6052ef761c7de949c
Author: Søren Sandmann Pedersen <sandmann at redhat.com>
Date:   Wed Mar 3 13:24:13 2010 -0500

    test: Add support for indexed formats to blitters-test
    
    These formats work fine, they just need to have a palette set.

diff --git a/test/blitters-test.c b/test/blitters-test.c
index 0b4b6c9..c11917d 100644
--- a/test/blitters-test.c
+++ b/test/blitters-test.c
@@ -27,6 +27,8 @@
 #include <config.h>
 #include "utils.h"
 
+static pixman_indexed_t palette;
+
 static void *
 aligned_malloc (size_t align, size_t size)
 {
@@ -58,6 +60,7 @@ create_random_image (pixman_format_code_t *allowed_formats,
     while (allowed_formats[n] != -1)
 	n++;
     fmt = allowed_formats[lcg_rand_n (n)];
+
     width = lcg_rand_n (max_width) + 1;
     height = lcg_rand_n (max_height) + 1;
     stride = (width * PIXMAN_FORMAT_BPP (fmt) + 7) / 8 +
@@ -79,6 +82,12 @@ create_random_image (pixman_format_code_t *allowed_formats,
 
     img = pixman_image_create_bits (fmt, width, height, buf, stride);
 
+    if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_COLOR	||
+	PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_GRAY)
+    {
+	pixman_image_set_indexed (img, &palette);
+    }
+
     image_endian_swap (img, PIXMAN_FORMAT_BPP (fmt));
 
     if (used_fmt) *used_fmt = fmt;
@@ -221,7 +230,6 @@ static pixman_format_code_t img_fmt_list[] = {
     PIXMAN_b2g3r3,
     PIXMAN_a2r2g2b2,
     PIXMAN_a2b2g2r2,
-#if 0 /* using these crashes the test */
     PIXMAN_c8,
     PIXMAN_g8,
     PIXMAN_x4c4,
@@ -229,7 +237,6 @@ static pixman_format_code_t img_fmt_list[] = {
     PIXMAN_c4,
     PIXMAN_g4,
     PIXMAN_g1,
-#endif
     PIXMAN_x4a4,
     PIXMAN_a4,
     PIXMAN_r1g2b1,
@@ -418,6 +425,18 @@ test_composite (uint32_t initcrc, int testnum, int verbose)
     return crc32;
 }
 
+static void
+initialize_palette (void)
+{
+    int i;
+
+    for (i = 0; i < PIXMAN_MAX_INDEXED; ++i)
+	palette.rgba[i] = lcg_rand ();
+
+    for (i = 0; i < 32768; ++i)
+	palette.ent[i] = lcg_rand() & 0xff;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -425,6 +444,8 @@ main (int argc, char *argv[])
     uint32_t crc = 0;
     int verbose = getenv ("VERBOSE") != NULL;
 
+    initialize_palette();
+
     if (argc >= 3)
     {
 	n1 = atoi (argv[1]);
@@ -461,7 +482,7 @@ main (int argc, char *argv[])
 	    /* Predefined value for running with all the fastpath functions
 	       disabled. It needs to be updated every time when changes are
 	       introduced to this program or behavior of pixman changes! */
-	    if (crc == 0x20CBE02C)
+	    if (crc == 0xEF7A1179)
 	    {
 		printf ("blitters test passed\n");
 	    }
commit 2b5f7be6c05ce3643b7d29e7237f91bfaedd80e5
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Mon Mar 1 10:32:39 2010 -0500

    pixman.h: Only define stdint types when PIXMAN_DONT_DEFINE_STDINT is undefined
    
    In SPICE, with Microsoft Visual C++, pixman.h is included after
    another file that defines these types, which causes warnings and
    errors.
    
    This patch allows such code to just define PIXMAN_DONT_DEFINE_STDINT
    to use its own version of those types.

diff --git a/pixman/pixman.h b/pixman/pixman.h
index 23feb2f..85fcc8c 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -84,6 +84,9 @@ PIXMAN_BEGIN_DECLS
 /*
  * Standard integers
  */
+
+#if !defined (PIXMAN_DONT_DEFINE_STDINT)
+
 #if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__) || defined (__HP_cc)
 #  include <inttypes.h>
 #elif defined (_MSC_VER)
@@ -101,6 +104,8 @@ typedef unsigned __int64 uint64_t;
 #  include <stdint.h>
 #endif
 
+#endif
+
 /*
  * Boolean
  */
commit f4da05c9f988133079cac2b8d54589386f46398f
Merge: a12d868... f534509...
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sun Mar 14 12:12:05 2010 -0400

    Merge branch 'operator-table'

commit a12d868df8b673df2b563f309563954e2b3f977d
Merge: 18f0de4... 54e39e0...
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sun Mar 14 12:12:00 2010 -0400

    Merge branch 'fast-path-cache'

commit f534509d007de40592dedc574e7eb78445453ec0
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sat Jan 30 11:37:25 2010 -0500

    Change operator table to be an array of arrays of four bytes.
    
    This makes gcc generate slightly better code for optimize_operator.

diff --git a/pixman/pixman.c b/pixman/pixman.c
index 924ef7c..c71617e 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -32,13 +32,20 @@
 
 static pixman_implementation_t *imp;
 
-#define PACK(a, b, c, d)			\
-    (((uint8_t)PIXMAN_OP_ ## a <<  0)	|	\
-     ((uint8_t)PIXMAN_OP_ ## b <<  8)	|	\
-     ((uint8_t)PIXMAN_OP_ ## c << 16)	|	\
-     ((uint8_t)PIXMAN_OP_ ## d << 24))
+typedef struct operator_info_t operator_info_t;
 
-static const uint32_t operator_table[] =
+struct operator_info_t
+{
+    uint8_t	opaque_info[4];
+};
+
+#define PACK(neither, src, dest, both)			\
+    {{	    (uint8_t)PIXMAN_OP_ ## neither,		\
+	    (uint8_t)PIXMAN_OP_ ## src,			\
+	    (uint8_t)PIXMAN_OP_ ## dest,		\
+	    (uint8_t)PIXMAN_OP_ ## both		}}
+
+static const operator_info_t operator_table[] =
 {
     /*    Neither Opaque         Src Opaque             Dst Opaque             Both Opaque */
     PACK (CLEAR,                 CLEAR,                 CLEAR,                 CLEAR),
@@ -56,8 +63,8 @@ static const uint32_t operator_table[] =
     PACK (ADD,                   ADD,                   ADD,                   ADD),
     PACK (SATURATE,              OVER_REVERSE,          DST,                   DST),
 
-    0 /* 0x0e */,
-    0 /* 0x0f */,
+    {{ 0 /* 0x0e */ }},
+    {{ 0 /* 0x0f */ }},
 
     PACK (CLEAR,                 CLEAR,                 CLEAR,                 CLEAR),
     PACK (SRC,                   SRC,                   SRC,                   SRC),
@@ -72,10 +79,10 @@ static const uint32_t operator_table[] =
     PACK (DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE),
     PACK (DISJOINT_XOR,          DISJOINT_XOR,          DISJOINT_XOR,          DISJOINT_XOR),
 
-    0 /* 0x1c */,
-    0 /* 0x1d */,
-    0 /* 0x1e */,
-    0 /* 0x1f */,
+    {{ 0 /* 0x1c */ }},
+    {{ 0 /* 0x1d */ }},
+    {{ 0 /* 0x1e */ }},
+    {{ 0 /* 0x1f */ }},
 
     PACK (CLEAR,                 CLEAR,                 CLEAR,                 CLEAR),
     PACK (SRC,                   SRC,                   SRC,                   SRC),
@@ -90,10 +97,10 @@ static const uint32_t operator_table[] =
     PACK (CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE),
     PACK (CONJOINT_XOR,          CONJOINT_XOR,          CONJOINT_XOR,          CONJOINT_XOR),
 
-    0 /* 0x2c */,
-    0 /* 0x2d */,
-    0 /* 0x2e */,
-    0 /* 0x2f */,
+    {{ 0 /* 0x2c */ }},
+    {{ 0 /* 0x2d */ }},
+    {{ 0 /* 0x2e */ }},
+    {{ 0 /* 0x2f */ }},
 
     PACK (MULTIPLY,              MULTIPLY,              MULTIPLY,              MULTIPLY),
     PACK (SCREEN,                SCREEN,                SCREEN,                SCREEN),
@@ -110,8 +117,6 @@ static const uint32_t operator_table[] =
     PACK (HSL_SATURATION,        HSL_SATURATION,        HSL_SATURATION,        HSL_SATURATION),
     PACK (HSL_COLOR,             HSL_COLOR,             HSL_COLOR,             HSL_COLOR),
     PACK (HSL_LUMINOSITY,        HSL_LUMINOSITY,        HSL_LUMINOSITY,        HSL_LUMINOSITY),
-
-    0
 };
 
 /*
@@ -125,14 +130,14 @@ optimize_operator (pixman_op_t     op,
 		   uint32_t        dst_flags)
 {
     pixman_bool_t is_source_opaque, is_dest_opaque;
-    int shift;
+    int opaqueness;
 
     is_source_opaque = ((src_flags & mask_flags) & FAST_PATH_IS_OPAQUE) != 0;
     is_dest_opaque = (dst_flags & FAST_PATH_IS_OPAQUE) != 0;
 
-    shift = 8 * ((is_dest_opaque << 1) | is_source_opaque);
+    opaqueness = ((is_dest_opaque << 1) | is_source_opaque);
 
-    return (operator_table[op] >> shift) & 0xff;
+    return operator_table[op].opaque_info[opaqueness];
 }
 
 static void
commit 94d75ebd2167b44c142a6202b2d7bbe238dfd830
Author: Søren Sandmann Pedersen <sandmann at redhat.com>
Date:   Sat Sep 19 02:40:56 2009 -0400

    Strength reduce certain conjoint/disjoint to their normal counterparts.
    
    This allows us to not test for them later on.

diff --git a/pixman/pixman.c b/pixman/pixman.c
index 2156529..924ef7c 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -59,9 +59,9 @@ static const uint32_t operator_table[] =
     0 /* 0x0e */,
     0 /* 0x0f */,
 
-    PACK (DISJOINT_CLEAR,        DISJOINT_CLEAR,        DISJOINT_CLEAR,        DISJOINT_CLEAR),
-    PACK (DISJOINT_SRC,          DISJOINT_SRC,          DISJOINT_SRC,          DISJOINT_SRC),
-    PACK (DISJOINT_DST,          DISJOINT_DST,          DISJOINT_DST,          DISJOINT_DST),
+    PACK (CLEAR,                 CLEAR,                 CLEAR,                 CLEAR),
+    PACK (SRC,                   SRC,                   SRC,                   SRC),
+    PACK (DST,                   DST,                   DST,                   DST),
     PACK (DISJOINT_OVER,         DISJOINT_OVER,         DISJOINT_OVER,         DISJOINT_OVER),
     PACK (DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE),
     PACK (DISJOINT_IN,           DISJOINT_IN,           DISJOINT_IN,           DISJOINT_IN),
@@ -77,9 +77,9 @@ static const uint32_t operator_table[] =
     0 /* 0x1e */,
     0 /* 0x1f */,
 
-    PACK (CONJOINT_CLEAR,        CONJOINT_CLEAR,        CONJOINT_CLEAR,        CONJOINT_CLEAR),
-    PACK (CONJOINT_SRC,          CONJOINT_SRC,          CONJOINT_SRC,          CONJOINT_SRC),
-    PACK (CONJOINT_DST,          CONJOINT_DST,          CONJOINT_DST,          CONJOINT_DST),
+    PACK (CLEAR,                 CLEAR,                 CLEAR,                 CLEAR),
+    PACK (SRC,                   SRC,                   SRC,                   SRC),
+    PACK (DST,                   DST,                   DST,                   DST),
     PACK (CONJOINT_OVER,         CONJOINT_OVER,         CONJOINT_OVER,         CONJOINT_OVER),
     PACK (CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE),
     PACK (CONJOINT_IN,           CONJOINT_IN,           CONJOINT_IN,           CONJOINT_IN),
@@ -588,13 +588,10 @@ do_composite (pixman_implementation_t *imp,
      * mathematically equivalent to the source.
      */
     op = optimize_operator (op, src_flags, mask_flags, dest_flags);
-    if (op == PIXMAN_OP_DST ||
-	op == PIXMAN_OP_CONJOINT_DST ||
-	op == PIXMAN_OP_DISJOINT_DST)
-    {
+    if (op == PIXMAN_OP_DST)
 	return;
-    }
 
+    /* Check cache for fast paths */
     cache = tls_cache;
 
     for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
commit 58be9c71d2b1d0ed9d8feed1db0581b250d0a7d2
Author: Søren Sandmann Pedersen <sandmann at redhat.com>
Date:   Sat Sep 19 02:32:28 2009 -0400

    Store the operator table more compactly.
    
    The four cases for each operator:
    
        none-are-opaque, src-is-opaque, dest-is-opaque, both-are-opaque
    
    are packed into one uint32_t per operator. The relevant strength
    reduced operator can then be found by packing the source-is-opaque and
    dest-is-opaque into two bits and shifting that number of bytes.
    
    Chris Wilson pointed out a bug in the original version of this commit:
    dest_is_opaque and source_is_opaque were used as booleans, but their
    actual values were the results of a logical AND with the
    FAST_PATH_OPAQUE flag, so the shift value was wildly wrong.
    
    The only reason it actually passed the test suite (on x86) was that
    the compiler computed the shift amount in the cl register, and the low
    byte of FAST_PATH_OPAQUE happens to be 0, so no shifting actually took
    place, and the original operator was returned.

diff --git a/pixman/pixman.c b/pixman/pixman.c
index bbd978c..2156529 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -30,97 +30,90 @@
 
 #include <stdlib.h>
 
-/*
- * Operator optimizations based on source or destination opacity
- */
-typedef struct
-{
-    pixman_op_t op;
-    pixman_op_t op_src_dst_opaque;
-    pixman_op_t op_src_opaque;
-    pixman_op_t op_dst_opaque;
-} operator_info_t;
+static pixman_implementation_t *imp;
 
-#define NO_OPTIMIZATION(a) (a), (a), (a), (a)
+#define PACK(a, b, c, d)			\
+    (((uint8_t)PIXMAN_OP_ ## a <<  0)	|	\
+     ((uint8_t)PIXMAN_OP_ ## b <<  8)	|	\
+     ((uint8_t)PIXMAN_OP_ ## c << 16)	|	\
+     ((uint8_t)PIXMAN_OP_ ## d << 24))
 
-static const operator_info_t operator_table[] =
+static const uint32_t operator_table[] =
 {
-    /* Input Operator           SRC&DST Opaque          SRC Opaque              DST Opaque      */
-    { NO_OPTIMIZATION (PIXMAN_OP_CLEAR) },
-    { NO_OPTIMIZATION (PIXMAN_OP_SRC) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DST) },
-    { PIXMAN_OP_OVER,           PIXMAN_OP_SRC,          PIXMAN_OP_SRC,          PIXMAN_OP_OVER },
-    { PIXMAN_OP_OVER_REVERSE,   PIXMAN_OP_DST,          PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_DST },
-    { PIXMAN_OP_IN,             PIXMAN_OP_SRC,          PIXMAN_OP_IN,           PIXMAN_OP_SRC },
-    { PIXMAN_OP_IN_REVERSE,     PIXMAN_OP_DST,          PIXMAN_OP_DST,          PIXMAN_OP_IN_REVERSE },
-    { PIXMAN_OP_OUT,            PIXMAN_OP_CLEAR,        PIXMAN_OP_OUT,          PIXMAN_OP_CLEAR },
-    { PIXMAN_OP_OUT_REVERSE,    PIXMAN_OP_CLEAR,        PIXMAN_OP_CLEAR,        PIXMAN_OP_OUT_REVERSE },
-    { PIXMAN_OP_ATOP,           PIXMAN_OP_SRC,          PIXMAN_OP_IN,           PIXMAN_OP_OVER },
-    { PIXMAN_OP_ATOP_REVERSE,   PIXMAN_OP_DST,          PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_IN_REVERSE },
-    { PIXMAN_OP_XOR,            PIXMAN_OP_CLEAR,        PIXMAN_OP_OUT,          PIXMAN_OP_OUT_REVERSE },
-    { NO_OPTIMIZATION (PIXMAN_OP_ADD) },
-    { PIXMAN_OP_SATURATE,       PIXMAN_OP_DST,          PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_DST },
-
-    { PIXMAN_OP_NONE /* 0x0e */ },
-    { PIXMAN_OP_NONE /* 0x0f */ },
-
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_CLEAR) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_SRC) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_DST) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_OVER) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_OVER_REVERSE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_IN) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_IN_REVERSE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_OUT) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_OUT_REVERSE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_ATOP) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_ATOP_REVERSE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_XOR) },
-
-    { PIXMAN_OP_NONE /* 0x1c */ },
-    { PIXMAN_OP_NONE /* 0x1d */ },
-    { PIXMAN_OP_NONE /* 0x1e */ },
-    { PIXMAN_OP_NONE /* 0x1f */ },
-
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_CLEAR) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_SRC) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_DST) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_OVER) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_OVER_REVERSE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_IN) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_IN_REVERSE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_OUT) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_OUT_REVERSE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_ATOP) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_ATOP_REVERSE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_XOR) },
-
-    { PIXMAN_OP_NONE /* 0x2c */ },
-    { PIXMAN_OP_NONE /* 0x2d */ },
-    { PIXMAN_OP_NONE /* 0x2e */ },
-    { PIXMAN_OP_NONE /* 0x2f */ },
-
-    { NO_OPTIMIZATION (PIXMAN_OP_MULTIPLY) },
-    { NO_OPTIMIZATION (PIXMAN_OP_SCREEN) },
-    { NO_OPTIMIZATION (PIXMAN_OP_OVERLAY) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DARKEN) },
-    { NO_OPTIMIZATION (PIXMAN_OP_LIGHTEN) },
-    { NO_OPTIMIZATION (PIXMAN_OP_COLOR_DODGE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_COLOR_BURN) },
-    { NO_OPTIMIZATION (PIXMAN_OP_HARD_LIGHT) },
-    { NO_OPTIMIZATION (PIXMAN_OP_SOFT_LIGHT) },
-    { NO_OPTIMIZATION (PIXMAN_OP_DIFFERENCE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_EXCLUSION) },
-    { NO_OPTIMIZATION (PIXMAN_OP_HSL_HUE) },
-    { NO_OPTIMIZATION (PIXMAN_OP_HSL_SATURATION) },
-    { NO_OPTIMIZATION (PIXMAN_OP_HSL_COLOR) },
-    { NO_OPTIMIZATION (PIXMAN_OP_HSL_LUMINOSITY) },
-
-    { PIXMAN_OP_NONE }
+    /*    Neither Opaque         Src Opaque             Dst Opaque             Both Opaque */
+    PACK (CLEAR,                 CLEAR,                 CLEAR,                 CLEAR),
+    PACK (SRC,                   SRC,                   SRC,                   SRC),
+    PACK (DST,                   DST,                   DST,                   DST),
+    PACK (OVER,                  SRC,                   OVER,                  SRC),
+    PACK (OVER_REVERSE,          OVER_REVERSE,          DST,                   DST),
+    PACK (IN,                    IN,                    SRC,                   SRC),
+    PACK (IN_REVERSE,            DST,                   IN_REVERSE,            DST),
+    PACK (OUT,                   OUT,                   CLEAR,                 CLEAR),
+    PACK (OUT_REVERSE,           CLEAR,                 OUT_REVERSE,           CLEAR),
+    PACK (ATOP,                  IN,                    OVER,                  SRC),
+    PACK (ATOP_REVERSE,          OVER_REVERSE,          IN_REVERSE,            DST),
+    PACK (XOR,                   OUT,                   OUT_REVERSE,           CLEAR),
+    PACK (ADD,                   ADD,                   ADD,                   ADD),
+    PACK (SATURATE,              OVER_REVERSE,          DST,                   DST),
+
+    0 /* 0x0e */,
+    0 /* 0x0f */,
+
+    PACK (DISJOINT_CLEAR,        DISJOINT_CLEAR,        DISJOINT_CLEAR,        DISJOINT_CLEAR),
+    PACK (DISJOINT_SRC,          DISJOINT_SRC,          DISJOINT_SRC,          DISJOINT_SRC),
+    PACK (DISJOINT_DST,          DISJOINT_DST,          DISJOINT_DST,          DISJOINT_DST),
+    PACK (DISJOINT_OVER,         DISJOINT_OVER,         DISJOINT_OVER,         DISJOINT_OVER),
+    PACK (DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE),
+    PACK (DISJOINT_IN,           DISJOINT_IN,           DISJOINT_IN,           DISJOINT_IN),
+    PACK (DISJOINT_IN_REVERSE,   DISJOINT_IN_REVERSE,   DISJOINT_IN_REVERSE,   DISJOINT_IN_REVERSE),
+    PACK (DISJOINT_OUT,          DISJOINT_OUT,          DISJOINT_OUT,          DISJOINT_OUT),
+    PACK (DISJOINT_OUT_REVERSE,  DISJOINT_OUT_REVERSE,  DISJOINT_OUT_REVERSE,  DISJOINT_OUT_REVERSE),
+    PACK (DISJOINT_ATOP,         DISJOINT_ATOP,         DISJOINT_ATOP,         DISJOINT_ATOP),
+    PACK (DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE),
+    PACK (DISJOINT_XOR,          DISJOINT_XOR,          DISJOINT_XOR,          DISJOINT_XOR),
+
+    0 /* 0x1c */,
+    0 /* 0x1d */,
+    0 /* 0x1e */,
+    0 /* 0x1f */,
+
+    PACK (CONJOINT_CLEAR,        CONJOINT_CLEAR,        CONJOINT_CLEAR,        CONJOINT_CLEAR),
+    PACK (CONJOINT_SRC,          CONJOINT_SRC,          CONJOINT_SRC,          CONJOINT_SRC),
+    PACK (CONJOINT_DST,          CONJOINT_DST,          CONJOINT_DST,          CONJOINT_DST),
+    PACK (CONJOINT_OVER,         CONJOINT_OVER,         CONJOINT_OVER,         CONJOINT_OVER),
+    PACK (CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE),
+    PACK (CONJOINT_IN,           CONJOINT_IN,           CONJOINT_IN,           CONJOINT_IN),
+    PACK (CONJOINT_IN_REVERSE,   CONJOINT_IN_REVERSE,   CONJOINT_IN_REVERSE,   CONJOINT_IN_REVERSE),
+    PACK (CONJOINT_OUT,          CONJOINT_OUT,          CONJOINT_OUT,          CONJOINT_OUT),
+    PACK (CONJOINT_OUT_REVERSE,  CONJOINT_OUT_REVERSE,  CONJOINT_OUT_REVERSE,  CONJOINT_OUT_REVERSE),
+    PACK (CONJOINT_ATOP,         CONJOINT_ATOP,         CONJOINT_ATOP,         CONJOINT_ATOP),
+    PACK (CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE),
+    PACK (CONJOINT_XOR,          CONJOINT_XOR,          CONJOINT_XOR,          CONJOINT_XOR),
+
+    0 /* 0x2c */,
+    0 /* 0x2d */,
+    0 /* 0x2e */,
+    0 /* 0x2f */,
+
+    PACK (MULTIPLY,              MULTIPLY,              MULTIPLY,              MULTIPLY),
+    PACK (SCREEN,                SCREEN,                SCREEN,                SCREEN),
+    PACK (OVERLAY,               OVERLAY,               OVERLAY,               OVERLAY),
+    PACK (DARKEN,                DARKEN,                DARKEN,                DARKEN),
+    PACK (LIGHTEN,               LIGHTEN,               LIGHTEN,               LIGHTEN),
+    PACK (COLOR_DODGE,           COLOR_DODGE,           COLOR_DODGE,           COLOR_DODGE),
+    PACK (COLOR_BURN,            COLOR_BURN,            COLOR_BURN,            COLOR_BURN),
+    PACK (HARD_LIGHT,            HARD_LIGHT,            HARD_LIGHT,            HARD_LIGHT),
+    PACK (SOFT_LIGHT,            SOFT_LIGHT,            SOFT_LIGHT,            SOFT_LIGHT),
+    PACK (DIFFERENCE,            DIFFERENCE,            DIFFERENCE,            DIFFERENCE),
+    PACK (EXCLUSION,             EXCLUSION,             EXCLUSION,             EXCLUSION),
+    PACK (HSL_HUE,               HSL_HUE,               HSL_HUE,               HSL_HUE),
+    PACK (HSL_SATURATION,        HSL_SATURATION,        HSL_SATURATION,        HSL_SATURATION),
+    PACK (HSL_COLOR,             HSL_COLOR,             HSL_COLOR,             HSL_COLOR),
+    PACK (HSL_LUMINOSITY,        HSL_LUMINOSITY,        HSL_LUMINOSITY,        HSL_LUMINOSITY),
+
+    0
 };
 
-static pixman_implementation_t *imp;
-
 /*
  * Optimize the current operator based on opacity of source or destination
  * The output operator should be mathematically equivalent to the source.
@@ -131,22 +124,15 @@ optimize_operator (pixman_op_t     op,
 		   uint32_t        mask_flags,
 		   uint32_t        dst_flags)
 {
-    const operator_info_t *info = &(operator_table[op]);
     pixman_bool_t is_source_opaque, is_dest_opaque;
+    int shift;
 
-    assert (info->op == op);
-
-    is_source_opaque = (src_flags & mask_flags) & FAST_PATH_IS_OPAQUE;
-    is_dest_opaque = dst_flags & FAST_PATH_IS_OPAQUE;
+    is_source_opaque = ((src_flags & mask_flags) & FAST_PATH_IS_OPAQUE) != 0;
+    is_dest_opaque = (dst_flags & FAST_PATH_IS_OPAQUE) != 0;
 
-    if (is_source_opaque && is_dest_opaque)
-	return info->op_src_dst_opaque;
-    else if (is_source_opaque)
-	return info->op_src_opaque;
-    else if (is_dest_opaque)
-	return info->op_dst_opaque;
+    shift = 8 * ((is_dest_opaque << 1) | is_source_opaque);
 
-    return op;
+    return (operator_table[op] >> shift) & 0xff;
 }
 
 static void
commit 7fe35f0e6b660f5667ff653f3b753bc3e5d07901
Author: Søren Sandmann Pedersen <sandmann at redhat.com>
Date:   Fri Sep 18 14:10:31 2009 -0400

    Make the operator strength reduction constant time.
    
    By extending the operator information table to cover all operators we
    can replace the loop with a table look-up. At the same time, base the
    operator optimization on the computed flags rather than the ones in
    the image struct.
    
    Finally, as an extra optimization, we no longer ignore the case where
    there is a mask. Instead we consider the source opaque if both source
    and mask are opaque, or if the source is opaque and the mask is
    missing.

diff --git a/pixman/pixman.c b/pixman/pixman.c
index b43ea92..bbd978c 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -39,11 +39,16 @@ typedef struct
     pixman_op_t op_src_dst_opaque;
     pixman_op_t op_src_opaque;
     pixman_op_t op_dst_opaque;
-} optimized_operator_info_t;
+} operator_info_t;
 
-static const optimized_operator_info_t optimized_operators[] =
+#define NO_OPTIMIZATION(a) (a), (a), (a), (a)
+
+static const operator_info_t operator_table[] =
 {
     /* Input Operator           SRC&DST Opaque          SRC Opaque              DST Opaque      */
+    { NO_OPTIMIZATION (PIXMAN_OP_CLEAR) },
+    { NO_OPTIMIZATION (PIXMAN_OP_SRC) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DST) },
     { PIXMAN_OP_OVER,           PIXMAN_OP_SRC,          PIXMAN_OP_SRC,          PIXMAN_OP_OVER },
     { PIXMAN_OP_OVER_REVERSE,   PIXMAN_OP_DST,          PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_DST },
     { PIXMAN_OP_IN,             PIXMAN_OP_SRC,          PIXMAN_OP_IN,           PIXMAN_OP_SRC },
@@ -53,49 +58,86 @@ static const optimized_operator_info_t optimized_operators[] =
     { PIXMAN_OP_ATOP,           PIXMAN_OP_SRC,          PIXMAN_OP_IN,           PIXMAN_OP_OVER },
     { PIXMAN_OP_ATOP_REVERSE,   PIXMAN_OP_DST,          PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_IN_REVERSE },
     { PIXMAN_OP_XOR,            PIXMAN_OP_CLEAR,        PIXMAN_OP_OUT,          PIXMAN_OP_OUT_REVERSE },
+    { NO_OPTIMIZATION (PIXMAN_OP_ADD) },
     { PIXMAN_OP_SATURATE,       PIXMAN_OP_DST,          PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_DST },
+
+    { PIXMAN_OP_NONE /* 0x0e */ },
+    { PIXMAN_OP_NONE /* 0x0f */ },
+
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_CLEAR) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_SRC) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_DST) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_OVER) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_OVER_REVERSE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_IN) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_IN_REVERSE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_OUT) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_OUT_REVERSE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_ATOP) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_ATOP_REVERSE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DISJOINT_XOR) },
+
+    { PIXMAN_OP_NONE /* 0x1c */ },
+    { PIXMAN_OP_NONE /* 0x1d */ },
+    { PIXMAN_OP_NONE /* 0x1e */ },
+    { PIXMAN_OP_NONE /* 0x1f */ },
+
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_CLEAR) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_SRC) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_DST) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_OVER) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_OVER_REVERSE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_IN) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_IN_REVERSE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_OUT) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_OUT_REVERSE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_ATOP) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_ATOP_REVERSE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_CONJOINT_XOR) },
+
+    { PIXMAN_OP_NONE /* 0x2c */ },
+    { PIXMAN_OP_NONE /* 0x2d */ },
+    { PIXMAN_OP_NONE /* 0x2e */ },
+    { PIXMAN_OP_NONE /* 0x2f */ },
+
+    { NO_OPTIMIZATION (PIXMAN_OP_MULTIPLY) },
+    { NO_OPTIMIZATION (PIXMAN_OP_SCREEN) },
+    { NO_OPTIMIZATION (PIXMAN_OP_OVERLAY) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DARKEN) },
+    { NO_OPTIMIZATION (PIXMAN_OP_LIGHTEN) },
+    { NO_OPTIMIZATION (PIXMAN_OP_COLOR_DODGE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_COLOR_BURN) },
+    { NO_OPTIMIZATION (PIXMAN_OP_HARD_LIGHT) },
+    { NO_OPTIMIZATION (PIXMAN_OP_SOFT_LIGHT) },
+    { NO_OPTIMIZATION (PIXMAN_OP_DIFFERENCE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_EXCLUSION) },
+    { NO_OPTIMIZATION (PIXMAN_OP_HSL_HUE) },
+    { NO_OPTIMIZATION (PIXMAN_OP_HSL_SATURATION) },
+    { NO_OPTIMIZATION (PIXMAN_OP_HSL_COLOR) },
+    { NO_OPTIMIZATION (PIXMAN_OP_HSL_LUMINOSITY) },
+
     { PIXMAN_OP_NONE }
 };
 
 static pixman_implementation_t *imp;
 
 /*
- * Check if the current operator could be optimized
- */
-static const optimized_operator_info_t*
-pixman_operator_can_be_optimized (pixman_op_t op)
-{
-    const optimized_operator_info_t *info;
-
-    for (info = optimized_operators; info->op != PIXMAN_OP_NONE; info++)
-    {
-	if (info->op == op)
-	    return info;
-    }
-    return NULL;
-}
-
-/*
  * Optimize the current operator based on opacity of source or destination
  * The output operator should be mathematically equivalent to the source.
  */
 static pixman_op_t
-pixman_optimize_operator (pixman_op_t     op,
-                          pixman_image_t *src_image,
-                          pixman_image_t *mask_image,
-                          pixman_image_t *dst_image)
+optimize_operator (pixman_op_t     op,
+		   uint32_t        src_flags,
+		   uint32_t        mask_flags,
+		   uint32_t        dst_flags)
 {
-    pixman_bool_t is_source_opaque;
-    pixman_bool_t is_dest_opaque;
-    const optimized_operator_info_t *info = pixman_operator_can_be_optimized (op);
-    if (!info || mask_image)
-	return op;
+    const operator_info_t *info = &(operator_table[op]);
+    pixman_bool_t is_source_opaque, is_dest_opaque;
 
-    is_source_opaque = src_image->common.flags & FAST_PATH_IS_OPAQUE;
-    is_dest_opaque = dst_image->common.flags & FAST_PATH_IS_OPAQUE;
+    assert (info->op == op);
 
-    if (!is_source_opaque && !is_dest_opaque)
-	return op;
+    is_source_opaque = (src_flags & mask_flags) & FAST_PATH_IS_OPAQUE;
+    is_dest_opaque = dst_flags & FAST_PATH_IS_OPAQUE;
 
     if (is_source_opaque && is_dest_opaque)
 	return info->op_src_dst_opaque;
@@ -105,7 +147,6 @@ pixman_optimize_operator (pixman_op_t     op,
 	return info->op_dst_opaque;
 
     return op;
-
 }
 
 static void
@@ -510,7 +551,7 @@ do_composite (pixman_implementation_t *imp,
     else
     {
 	mask_format = PIXMAN_null;
-	mask_flags = 0;
+	mask_flags = FAST_PATH_IS_OPAQUE;
     }
 
     dest_format = dest->common.extended_format_code;
@@ -555,6 +596,19 @@ do_composite (pixman_implementation_t *imp,
     if (mask && image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y))
 	mask_flags |= FAST_PATH_COVERS_CLIP;
 
+    /*
+     * Check if we can replace our operator by a simpler one
+     * if the src or dest are opaque. The output operator should be
+     * mathematically equivalent to the source.
+     */
+    op = optimize_operator (op, src_flags, mask_flags, dest_flags);
+    if (op == PIXMAN_OP_DST ||
+	op == PIXMAN_OP_CONJOINT_DST ||
+	op == PIXMAN_OP_DISJOINT_DST)
+    {
+	return;
+    }
+
     cache = tls_cache;
 
     for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
@@ -713,19 +767,6 @@ pixman_image_composite32 (pixman_op_t      op,
     if (mask)
 	_pixman_image_validate (mask);
     _pixman_image_validate (dest);
-    
-    /*
-     * Check if we can replace our operator by a simpler one
-     * if the src or dest are opaque. The output operator should be
-     * mathematically equivalent to the source.
-     */
-    op = pixman_optimize_operator(op, src, mask, dest);
-    if (op == PIXMAN_OP_DST		||
-	op == PIXMAN_OP_CONJOINT_DST	||
-	op == PIXMAN_OP_DISJOINT_DST)
-    {
-        return;
-    }
 
     if (!imp)
 	imp = _pixman_choose_implementation ();
commit 54e39e00386fd2fd0eb76ead6396ddb93f1cf6c2
Author: Søren Sandmann Pedersen <sandmann at redhat.com>
Date:   Thu Sep 17 03:16:27 2009 -0400

    Add a fast path cache
    
    This patch adds a cache in front of the fast path tables to reduce the
    overhead of pixman_composite(). It is fixed size with move-to-front to
    make sure the most popular fast paths are at the beginning of the cache.
    
    The cache is thread local to avoid locking.

diff --git a/pixman/pixman-compiler.h b/pixman/pixman-compiler.h
index 9647dbb..caafd0f 100644
--- a/pixman/pixman-compiler.h
+++ b/pixman/pixman-compiler.h
@@ -69,3 +69,12 @@
 #   define PIXMAN_EXPORT
 #endif
 
+/* TLS */
+#if defined (__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR >= 3) || __GNUC__ > 3)
+#    define THREAD_LOCAL __thread
+#elif defined (_MSC_VER)
+#    define THREAD_LOCAL __declspec(thread)
+#else
+#    warning "unknown compiler"
+#    define THREAD_LOCAL __thread
+#endif
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 94451d3..9dcdca7 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -11,6 +11,8 @@
 #include "pixman.h"
 #include <time.h>
 #include <assert.h>
+#include <stdio.h>
+#include <string.h>
 
 #include "pixman-compiler.h"
 
diff --git a/pixman/pixman.c b/pixman/pixman.c
index 3aa265f..b43ea92 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -482,6 +482,8 @@ do_composite (pixman_implementation_t *imp,
 	      int		       width,
 	      int		       height)
 {
+#define N_CACHED_FAST_PATHS 8
+    static THREAD_LOCAL pixman_fast_path_t tls_cache[N_CACHED_FAST_PATHS];
     pixman_format_code_t src_format, mask_format, dest_format;
     uint32_t src_flags, mask_flags, dest_flags;
     pixman_region32_t region;
@@ -493,6 +495,9 @@ do_composite (pixman_implementation_t *imp,
     uint32_t *dest_bits;
     int dest_dx, dest_dy;
     pixman_bool_t need_workaround;
+    pixman_fast_path_t *cache;
+    const pixman_fast_path_t *info;
+    int i;
 
     src_format = src->common.extended_format_code;
     src_flags = src->common.flags;
@@ -549,45 +554,100 @@ do_composite (pixman_implementation_t *imp,
     
     if (mask && image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y))
 	mask_flags |= FAST_PATH_COVERS_CLIP;
-	    
+
+    cache = tls_cache;
+
+    for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
+    {
+	info = &(cache[i]);
+
+	/* Note that we check for equality here, not whether
+	 * the cached fast path matches. This is to prevent
+	 * us from selecting an overly general fast path
+	 * when a more specific one would work.
+	 */
+	if (info->op == op			&&
+	    info->src_format == src_format	&&
+	    info->mask_format == mask_format	&&
+	    info->dest_format == dest_format	&&
+	    info->src_flags == src_flags	&&
+	    info->mask_flags == mask_flags	&&
+	    info->dest_flags == dest_flags	&&
+	    info->func)
+	{
+	    goto found;
+	}
+    }
+
     while (imp)
     {
-	const pixman_fast_path_t *info;
-	    
-	for (info = imp->fast_paths; info->op != PIXMAN_OP_NONE; ++info)
+	info = imp->fast_paths;
+
+	while (info->op != PIXMAN_OP_NONE)
 	{
 	    if ((info->op == op || info->op == PIXMAN_OP_any)		&&
-		/* src */
+		/* Formats */
 		((info->src_format == src_format) ||
 		 (info->src_format == PIXMAN_any))			&&
-		(info->src_flags & src_flags) == info->src_flags	&&
-		/* mask */
 		((info->mask_format == mask_format) ||
 		 (info->mask_format == PIXMAN_any))			&&
-		(info->mask_flags & mask_flags) == info->mask_flags	&&
-		/* dest */
 		((info->dest_format == dest_format) ||
 		 (info->dest_format == PIXMAN_any))			&&
+		/* Flags */
+		(info->src_flags & src_flags) == info->src_flags	&&
+		(info->mask_flags & mask_flags) == info->mask_flags	&&
 		(info->dest_flags & dest_flags) == info->dest_flags)
 	    {
-		walk_region_internal (imp, op,
-				      src, mask, dest,
-				      src_x, src_y, mask_x, mask_y,
-				      dest_x, dest_y,
-				      width, height,
-				      (src_flags & FAST_PATH_SIMPLE_REPEAT),
-				      (mask_flags & FAST_PATH_SIMPLE_REPEAT),
-				      &region,
-				      info->func);
-		
-		goto done;
+		/* Set i to the last spot in the cache so that the
+		 * move-to-front code below will work
+		 */
+		i = N_CACHED_FAST_PATHS - 1;
+
+		goto found;
 	    }
+
+	    ++info;
 	}
-	
+
 	imp = imp->delegate;
     }
 
-done:
+    /* We didn't find a compositing routine. This should not happen, but if
+     * it somehow does, just exit rather than crash.
+     */
+    goto out;
+
+found:
+    walk_region_internal (imp, op,
+			  src, mask, dest,
+			  src_x, src_y, mask_x, mask_y,
+			  dest_x, dest_y,
+			  width, height,
+			  (src_flags & FAST_PATH_SIMPLE_REPEAT),
+			  (mask_flags & FAST_PATH_SIMPLE_REPEAT),
+			  &region, info->func);
+
+    if (i)
+    {
+	/* Make a copy of info->func, because info->func may change when
+	 * we update the cache.
+	 */
+	pixman_composite_func_t func = info->func;
+	
+	while (i--)
+	    cache[i + 1] = cache[i];
+
+	cache[0].op = op;
+	cache[0].src_format = src_format;
+	cache[0].src_flags = src_flags;
+	cache[0].mask_format = mask_format;
+	cache[0].mask_flags = mask_flags;
+	cache[0].dest_format = dest_format;
+	cache[0].dest_flags = dest_flags;
+	cache[0].func = func;
+    }
+
+out:
     if (need_workaround)
     {
 	unapply_workaround (src, src_bits, src_dx, src_dy);


More information about the xorg-commit mailing list