No subject


Sat Aug 20 13:13:22 PDT 2011


overheads in the current implementation. My next step is to change the
rasterisers to spit out a RLE scanline in the form of (count, opacity[],
runs[]) and pass the arrays of spans to pixman. I felt this would be a
more invasive change and so avoided it... Suggestions very welcome.

I've pushed this patch along with conversion of fast-paths and the
lowlevel-bench to

  http://cgit.freedesktop.org/~ickle/pixman/log/?h=wip/spans

-Chris

---
 pixman/pixman-fast-path.c |    6 +-
 pixman/pixman-general.c   |   78 +++++++++-
 pixman/pixman-inlines.h   |   48 +++---
 pixman/pixman-noop.c      |    2 +-
 pixman/pixman-private.h   |   38 +++++-
 pixman/pixman.c           |  354 +++++++++++++++++++++++++++++++++++++++++---
 pixman/pixman.h           |   26 ++++
 test/lowlevel-blt-bench.c |    1 +
 8 files changed, 488 insertions(+), 65 deletions(-)

diff --git a/pixman/pixman-fast-path.c b/pixman/pixman-fast-path.c
index 7fd4478..a8cd9ba 100644
--- a/pixman/pixman-fast-path.c
+++ b/pixman/pixman-fast-path.c
@@ -1829,7 +1829,7 @@ static const pixman_fast_path_t c_fast_paths[] =
     SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, r5g6b5, 8888_565),
 
 #define NEAREST_FAST_PATH(op,s,d)		\
-    {   PIXMAN_OP_ ## op,			\
+    {   PIXMAN_OP_ ## op, 0,\
 	PIXMAN_ ## s, SCALED_NEAREST_FLAGS,	\
 	PIXMAN_null, 0,				\
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,	\
@@ -1863,13 +1863,13 @@ static const pixman_fast_path_t c_fast_paths[] =
      FAST_PATH_STANDARD_FLAGS)
 
 #define SIMPLE_ROTATE_FAST_PATH(op,s,d,suffix)				  \
-    {   PIXMAN_OP_ ## op,						  \
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			  \
 	PIXMAN_ ## s, SIMPLE_ROTATE_FLAGS (90),				  \
 	PIXMAN_null, 0,							  \
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,				  \
 	fast_composite_rotate_90_##suffix,				  \
     },									  \
-    {   PIXMAN_OP_ ## op,						  \
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			  \
 	PIXMAN_ ## s, SIMPLE_ROTATE_FLAGS (270),			  \
 	PIXMAN_null, 0,							  \
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,				  \
diff --git a/pixman/pixman-general.c b/pixman/pixman-general.c
index c24a3f3..ede6a09 100644
--- a/pixman/pixman-general.c
+++ b/pixman/pixman-general.c
@@ -104,10 +104,11 @@ general_composite_rect  (pixman_implementation_t *imp,
                          pixman_composite_info_t *info)
 {
     PIXMAN_COMPOSITE_ARGS (info);
-    uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8];
+    uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 4 + 7) / 8];
     uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer;
-    uint8_t *src_buffer, *mask_buffer, *dest_buffer;
-    pixman_iter_t src_iter, mask_iter, dest_iter;
+    uint8_t *src_buffer, *mask_buffer, *dest_buffer, *opacity_buffer, *ptr;
+    pixman_iter_t src_iter, mask_iter, dest_iter, opacity_iter;
+    pixman_image_t *opacity_image = NULL;
     pixman_combine_32_func_t compose;
     pixman_bool_t component_alpha;
     iter_flags_t narrow, src_flags;
@@ -129,15 +130,26 @@ general_composite_rect  (pixman_implementation_t *imp,
 
     if (width * Bpp > SCANLINE_BUFFER_LENGTH)
     {
-	scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
+	scanline_buffer = pixman_malloc_abc (width, 4, Bpp);
 
 	if (!scanline_buffer)
 	    return;
     }
 
-    src_buffer = scanline_buffer;
-    mask_buffer = src_buffer + width * Bpp;
-    dest_buffer = mask_buffer + width * Bpp;
+    ptr = scanline_buffer;
+
+    src_buffer = ptr;
+    ptr += width * Bpp;
+
+    mask_buffer = ptr;
+    if (mask_image)
+	ptr += width * Bpp;
+
+    opacity_buffer = ptr;
+    if (opacity != 0xff)
+	ptr += width * Bpp;
+
+    dest_buffer = ptr;
 
     /* src iter */
     src_flags = narrow | op_flags[op].src;
@@ -166,6 +178,47 @@ general_composite_rect  (pixman_implementation_t *imp,
 	imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height,
 	mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB));
 
+    if (opacity != 0xff)
+    {
+	pixman_color_t color;
+
+	/* In order to implement LERP correctly we premultiply the mask
+	 * channel by opacity. This means that we may have to create
+	 * the mask channel...
+	 */
+
+	color.red = color.green = color.blue = 0;
+	color.alpha = opacity << 8 | opacity;
+	opacity_image = pixman_image_create_solid_fill (&color);
+	if (opacity_image != NULL)
+	{
+	    pixman_iter_t *iter;
+
+	    _pixman_image_validate (opacity_image);
+	    if (mask_image)
+	    {
+		/* Fill the opacity buffer and pre-combine the opacity onto
+		 * mask, i.e. mask' = mask IN dest
+		 */
+		iter = &opacity_iter;
+	    }
+	    else
+	    {
+		/* Otherwise we simply use the mask channel for opacity */
+		iter = &mask_iter;
+		opacity = 0xff; /* no need for a separate stage now */
+	    }
+	    _pixman_implementation_src_iter_init (
+		imp->toplevel, iter, opacity_image, 0, 0, width, 1,
+		opacity_buffer, narrow | ITER_IGNORE_RGB);
+	}
+	else
+	{
+	    /* Hmm, just pretend nothing happened and ignore opacity... */
+	    opacity = 0xff;
+	}
+    }
+
     /* dest iter */
     _pixman_implementation_dest_iter_init (
 	imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height,
@@ -195,6 +248,12 @@ general_composite_rect  (pixman_implementation_t *imp,
 
 	m = mask_iter.get_scanline (&mask_iter, NULL);
 	s = src_iter.get_scanline (&src_iter, m);
+
+	if (opacity != 0xff) {
+	    uint32_t *a = opacity_iter.get_scanline (&opacity_iter, NULL);
+	    compose (imp->toplevel, PIXMAN_OP_IN, m, m, a, width);
+	}
+
 	d = dest_iter.get_scanline (&dest_iter, NULL);
 
 	compose (imp->toplevel, op, d, s, m, width);
@@ -202,13 +261,16 @@ general_composite_rect  (pixman_implementation_t *imp,
 	dest_iter.write_back (&dest_iter);
     }
 
+    if (opacity_image)
+	pixman_image_unref (opacity_image);
+
     if (scanline_buffer != (uint8_t *) stack_scanline_buffer)
 	free (scanline_buffer);
 }
 
 static const pixman_fast_path_t general_fast_path[] =
 {
-    { PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any,	0, PIXMAN_any, 0, general_composite_rect },
+    { PIXMAN_OP_any, 0, PIXMAN_any, 0, PIXMAN_any,	0, PIXMAN_any, 0, general_composite_rect },
     { PIXMAN_OP_NONE }
 };
 
diff --git a/pixman/pixman-inlines.h b/pixman/pixman-inlines.h
index f1e0cbd..e2839cc 100644
--- a/pixman/pixman-inlines.h
+++ b/pixman/pixman-inlines.h
@@ -550,7 +550,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
      FAST_PATH_NARROW_FORMAT)
 
 #define SIMPLE_NEAREST_FAST_PATH_NORMAL(op,s,d,func)			\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_NORMAL_REPEAT	|				\
@@ -561,7 +561,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_FAST_PATH_PAD(op,s,d,func)			\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_PAD_REPEAT		|				\
@@ -572,7 +572,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_FAST_PATH_NONE(op,s,d,func)			\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_NONE_REPEAT		|				\
@@ -583,7 +583,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_FAST_PATH_COVER(op,s,d,func)			\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
 	PIXMAN_null, 0,							\
@@ -592,7 +592,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NORMAL(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_NORMAL_REPEAT	|				\
@@ -603,7 +603,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_PAD_REPEAT		|				\
@@ -614,7 +614,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_NONE_REPEAT		|				\
@@ -625,7 +625,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
 	PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA),		\
@@ -634,7 +634,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_NORMAL_REPEAT	|				\
@@ -645,7 +645,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_PAD_REPEAT		|				\
@@ -656,7 +656,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_NEAREST_FLAGS		|				\
 	 FAST_PATH_NONE_REPEAT		|				\
@@ -667,7 +667,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
 	PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA),	\
@@ -1133,7 +1133,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
      FAST_PATH_NARROW_FORMAT)
 
 #define SIMPLE_BILINEAR_FAST_PATH_PAD(op,s,d,func)			\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_PAD_REPEAT		|				\
@@ -1144,7 +1144,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_FAST_PATH_NONE(op,s,d,func)			\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_NONE_REPEAT		|				\
@@ -1155,7 +1155,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_FAST_PATH_COVER(op,s,d,func)			\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
 	PIXMAN_null, 0,							\
@@ -1164,7 +1164,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_FAST_PATH_NORMAL(op,s,d,func)			\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_NORMAL_REPEAT	|				\
@@ -1175,7 +1175,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_PAD_REPEAT		|				\
@@ -1186,7 +1186,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_NONE_REPEAT		|				\
@@ -1197,7 +1197,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
 	PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA),		\
@@ -1206,7 +1206,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NORMAL(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_NORMAL_REPEAT	|				\
@@ -1217,7 +1217,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_PAD_REPEAT		|				\
@@ -1228,7 +1228,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_NONE_REPEAT		|				\
@@ -1239,7 +1239,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER(op,s,d,func)		\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
 	PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA),	\
@@ -1248,7 +1248,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
     }
 
 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NORMAL(op,s,d,func)	\
-    {   PIXMAN_OP_ ## op,						\
+    {   PIXMAN_OP_ ## op, FAST_PATH_STD_OP_FLAGS,			\
 	PIXMAN_ ## s,							\
 	(SCALED_BILINEAR_FLAGS		|				\
 	 FAST_PATH_NORMAL_REPEAT	|				\
diff --git a/pixman/pixman-noop.c b/pixman/pixman-noop.c
index 906a491..2c486b9 100644
--- a/pixman/pixman-noop.c
+++ b/pixman/pixman-noop.c
@@ -120,7 +120,7 @@ noop_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
 
 static const pixman_fast_path_t noop_fast_paths[] =
 {
-    { PIXMAN_OP_DST, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, noop_composite },
+    { PIXMAN_OP_DST, 0, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, noop_composite },
     { PIXMAN_OP_NONE },
 };
 
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index a25897d..f7d215b 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -360,6 +360,7 @@ typedef struct
     int32_t                  dest_y;
     int32_t                  width;
     int32_t                  height;
+    uint8_t                  opacity;
 } pixman_composite_info_t;
 
 #define PIXMAN_COMPOSITE_ARGS(info)					\
@@ -374,7 +375,8 @@ typedef struct
     MAYBE_UNUSED int32_t            dest_x = info->dest_x;		\
     MAYBE_UNUSED int32_t            dest_y = info->dest_y;		\
     MAYBE_UNUSED int32_t            width = info->width;		\
-    MAYBE_UNUSED int32_t            height = info->height
+    MAYBE_UNUSED int32_t            height = info->height;		\
+    MAYBE_UNUSED uint8_t            opacity = info->opacity
 
 typedef void (*pixman_combine_32_func_t) (pixman_implementation_t *imp,
 					  pixman_op_t              op,
@@ -420,9 +422,25 @@ typedef void (*pixman_iter_init_func_t) (pixman_implementation_t *imp,
 void _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp);
 void _pixman_setup_combiner_functions_64 (pixman_implementation_t *imp);
 
+enum {
+    BLT_ZERO,
+    BLT_ALPHA,
+    BLT_OPAQUE,
+    BLT_N_FUNC
+};
+struct pixman_image_compositor
+{
+    pixman_composite_info_t info;
+    struct {
+	pixman_implementation_t *imp;
+	pixman_composite_func_t func;
+    } blt[BLT_N_FUNC];
+};
+
 typedef struct
 {
     pixman_op_t             op;
+    uint32_t		    op_flags;
     pixman_format_code_t    src_format;
     uint32_t		    src_flags;
     pixman_format_code_t    mask_format;
@@ -638,6 +656,9 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask);
      FAST_PATH_NO_NORMAL_REPEAT		|				\
      FAST_PATH_NO_PAD_REPEAT)
 
+#define FAST_PATH_STD_OP_FLAGS \
+    (FAST_PATH_IS_OPAQUE)
+
 #define FAST_PATH_STANDARD_FLAGS					\
     (FAST_PATH_NO_CONVOLUTION_FILTER	|				\
      FAST_PATH_NO_ACCESSORS		|				\
@@ -657,8 +678,9 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask);
 #define MASK_FLAGS(format, extra)					\
     ((PIXMAN_ ## format == PIXMAN_null) ? 0 : (SOURCE_FLAGS (format) | extra))
 
-#define FAST_PATH(op, src, src_flags, mask, mask_flags, dest, dest_flags, func) \
+#define FAST_PATH(op, op_flags, src, src_flags, mask, mask_flags, dest, dest_flags, func) \
     PIXMAN_OP_ ## op,							\
+    op_flags,								\
     PIXMAN_ ## src,							\
     src_flags,							        \
     PIXMAN_ ## mask,						        \
@@ -669,15 +691,23 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask);
 
 #define PIXMAN_STD_FAST_PATH(op, src, mask, dest, func)			\
     { FAST_PATH (							\
-	    op,								\
+	    op,	  FAST_PATH_STD_OP_FLAGS,				\
 	    src,  SOURCE_FLAGS (src),					\
 	    mask, MASK_FLAGS (mask, FAST_PATH_UNIFIED_ALPHA),		\
 	    dest, FAST_PATH_STD_DEST_FLAGS,				\
 	    func) }
 
+#define PIXMAN_OPACITY_FAST_PATH(op, src, dest, func)			\
+    { FAST_PATH (							\
+	    op,	  FAST_PATH_STD_OP_FLAGS & ~FAST_PATH_IS_OPAQUE,	\
+	    src,  SOURCE_FLAGS (src),					\
+	    null, MASK_FLAGS (null, FAST_PATH_UNIFIED_ALPHA),		\
+	    dest, FAST_PATH_STD_DEST_FLAGS,				\
+	    func) }
+
 #define PIXMAN_STD_FAST_PATH_CA(op, src, mask, dest, func)		\
     { FAST_PATH (							\
-	    op,								\
+	    op,	  FAST_PATH_STD_OP_FLAGS,				\
 	    src,  SOURCE_FLAGS (src),					\
 	    mask, MASK_FLAGS (mask, FAST_PATH_COMPONENT_ALPHA),		\
 	    dest, FAST_PATH_STD_DEST_FLAGS,				\
diff --git a/pixman/pixman.c b/pixman/pixman.c
index 1c1d674..409330b 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -136,6 +136,79 @@ static const operator_info_t operator_table[] =
     PACK (HSL_COLOR,             HSL_COLOR,             HSL_COLOR,             HSL_COLOR),
     PACK (HSL_LUMINOSITY,        HSL_LUMINOSITY,        HSL_LUMINOSITY,        HSL_LUMINOSITY),
 };
+#undef PACK
+
+#define PACK(op) PIXMAN_OP_##op
+static const uint8_t zero_opacity_operator_table[] =
+{
+    /* CLEAR */		PACK(CLEAR),
+    /* SRC */		PACK(CLEAR),
+    /* DST */		PACK(DST),
+    /* OVER */		PACK(DST),
+    /* OVER_REVERSE */	PACK(CLEAR),
+    /* IN */		PACK(CLEAR),
+    /* IN_REVERSE */	PACK(CLEAR),
+    /* OUT */		PACK(DST),
+    /* OUT_REVERSE */	PACK(DST),
+    /* ATOP */		PACK(DST),
+    /* ATOP_REVERSE */	PACK(DST),
+    /* XOR */		PACK(DST),
+    /* ADD */		PACK(DST),
+    /* SATURATE */	PACK(DST),
+
+    /* LERP */		PACK(DST),
+    /* LERP_REVERSE */	PACK(SRC),
+
+    /* XXX Review disjoint/conjoint equations */
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(DST),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+
+    0 /* 0x1c */,
+    0 /* 0x1d */,
+    0 /* 0x1e */,
+    0 /* 0x1f */,
+
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(DST),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+    PACK(CLEAR),
+
+    0 /* 0x2c */,
+    0 /* 0x2d */,
+    0 /* 0x2e */,
+    0 /* 0x2f */,
+
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+    PACK(DST),
+};
 
 /*
  * Optimize the current operator based on opacity of source or destination
@@ -143,6 +216,7 @@ static const operator_info_t operator_table[] =
  */
 static pixman_op_t
 optimize_operator (pixman_op_t     op,
+		   uint32_t        op_flags,
 		   uint32_t        src_flags,
 		   uint32_t        mask_flags,
 		   uint32_t        dst_flags)
@@ -150,11 +224,12 @@ optimize_operator (pixman_op_t     op,
     pixman_bool_t is_source_opaque, is_dest_opaque;
 
 #define OPAQUE_SHIFT 13
-    
+
     COMPILE_TIME_ASSERT (FAST_PATH_IS_OPAQUE == (1 << OPAQUE_SHIFT));
-    
-    is_dest_opaque = (dst_flags & FAST_PATH_IS_OPAQUE);
-    is_source_opaque = ((src_flags & mask_flags) & FAST_PATH_IS_OPAQUE);
+
+    is_dest_opaque = dst_flags & FAST_PATH_IS_OPAQUE;
+    is_source_opaque =
+	(op_flags & src_flags & mask_flags) & FAST_PATH_IS_OPAQUE;
 
     is_dest_opaque >>= OPAQUE_SHIFT - 1;
     is_source_opaque >>= OPAQUE_SHIFT;
@@ -350,6 +425,7 @@ PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
 
 static force_inline pixman_bool_t
 lookup_composite_function (pixman_op_t			op,
+			   uint32_t			op_flags,
 			   pixman_format_code_t		src_format,
 			   uint32_t			src_flags,
 			   pixman_format_code_t		mask_format,
@@ -379,6 +455,7 @@ lookup_composite_function (pixman_op_t			op,
 	    info->src_format == src_format	&&
 	    info->mask_format == mask_format	&&
 	    info->dest_format == dest_format	&&
+	    info->op_flags == op_flags		&&
 	    info->src_flags == src_flags	&&
 	    info->mask_flags == mask_flags	&&
 	    info->dest_flags == dest_flags	&&
@@ -406,6 +483,7 @@ lookup_composite_function (pixman_op_t			op,
 		((info->dest_format == dest_format) ||
 		 (info->dest_format == PIXMAN_any))			&&
 		/* Flags */
+		(info->op_flags & op_flags) == info->op_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)
@@ -427,13 +505,14 @@ lookup_composite_function (pixman_op_t			op,
     return FALSE;
 
 update_cache:
-    if (i)
+    if (i > N_CACHED_FAST_PATHS / 2)
     {
 	while (i--)
 	    cache->cache[i + 1] = cache->cache[i];
 
 	cache->cache[0].imp = *out_imp;
 	cache->cache[0].fast_path.op = op;
+	cache->cache[0].fast_path.op_flags = op_flags;
 	cache->cache[0].fast_path.src_format = src_format;
 	cache->cache[0].fast_path.src_flags = src_flags;
 	cache->cache[0].fast_path.mask_format = mask_format;
@@ -681,22 +760,22 @@ analyze_extent (pixman_image_t *image, int x, int y,
 #if defined (USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
 __attribute__((__force_align_arg_pointer__))
 #endif
-PIXMAN_EXPORT void
-pixman_image_composite32 (pixman_op_t      op,
-                          pixman_image_t * src,
-                          pixman_image_t * mask,
-                          pixman_image_t * dest,
-                          int32_t          src_x,
-                          int32_t          src_y,
-                          int32_t          mask_x,
-                          int32_t          mask_y,
-                          int32_t          dest_x,
-                          int32_t          dest_y,
-                          int32_t          width,
-                          int32_t          height)
+static void
+_pixman_image_composite (pixman_op_t      op,
+			 pixman_image_t * src,
+			 pixman_image_t * mask,
+			 pixman_image_t * dest,
+			 int32_t          src_x,
+			 int32_t          src_y,
+			 int32_t          mask_x,
+			 int32_t          mask_y,
+			 int32_t          dest_x,
+			 int32_t          dest_y,
+			 int32_t          width,
+			 int32_t          height)
 {
     pixman_format_code_t src_format, mask_format, dest_format;
-    uint32_t src_flags, mask_flags, dest_flags;
+    uint32_t op_flags, src_flags, mask_flags, dest_flags;
     pixman_region32_t region;
     pixman_box32_t *extents;
     pixman_implementation_t *imp;
@@ -707,6 +786,8 @@ pixman_image_composite32 (pixman_op_t      op,
 	_pixman_image_validate (mask);
     _pixman_image_validate (dest);
 
+    op_flags = FAST_PATH_IS_OPAQUE;
+
     src_format = src->common.extended_format_code;
     src_flags = src->common.flags;
 
@@ -760,18 +841,18 @@ pixman_image_composite32 (pixman_op_t      op,
 
     if ((src_flags & BOTH) == BOTH)
 	src_flags |= FAST_PATH_IS_OPAQUE;
-    
+
     if ((mask_flags & BOTH) == BOTH)
 	mask_flags |= FAST_PATH_IS_OPAQUE;
-    
+
     /*
      * 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);
+    op = optimize_operator (op, op_flags,src_flags, mask_flags, dest_flags);
 
-    if (lookup_composite_function (op,
+    if (lookup_composite_function (op, op_flags,
 				   src_format, src_flags,
 				   mask_format, mask_flags,
 				   dest_format, dest_flags,
@@ -785,6 +866,7 @@ pixman_image_composite32 (pixman_op_t      op,
 	info.src_image = src;
 	info.mask_image = mask;
 	info.dest_image = dest;
+	info.opacity = ~0;
 
 	pbox = pixman_region32_rectangles (&region, &n);
 
@@ -810,6 +892,27 @@ out:
 }
 
 PIXMAN_EXPORT void
+pixman_image_composite32 (pixman_op_t      op,
+			  pixman_image_t * src,
+			  pixman_image_t * mask,
+			  pixman_image_t * dest,
+			  int32_t          src_x,
+			  int32_t          src_y,
+			  int32_t          mask_x,
+			  int32_t          mask_y,
+			  int32_t          dest_x,
+			  int32_t          dest_y,
+			  int32_t         width,
+			  int32_t         height)
+{
+    _pixman_image_composite (op, src, mask, dest,
+			     src_x, src_y,
+			     mask_x, mask_y,
+			     dest_x, dest_y,
+			     width, height);
+}
+
+PIXMAN_EXPORT void
 pixman_image_composite (pixman_op_t      op,
                         pixman_image_t * src,
                         pixman_image_t * mask,
@@ -823,8 +926,209 @@ pixman_image_composite (pixman_op_t      op,
                         uint16_t         width,
                         uint16_t         height)
 {
-    pixman_image_composite32 (op, src, mask, dest, src_x, src_y, 
-                              mask_x, mask_y, dest_x, dest_y, width, height);
+    _pixman_image_composite (op, src, mask, dest,
+			     src_x, src_y,
+			     mask_x, mask_y,
+			     dest_x, dest_y,
+			     width, height);
+}
+
+PIXMAN_EXPORT pixman_image_compositor_t *
+pixman_image_create_compositor (pixman_op_t      op,
+				pixman_image_t * src,
+				pixman_image_t * mask,
+				pixman_image_t * dest,
+				int32_t          src_x,
+				int32_t          src_y,
+				int32_t          mask_x,
+				int32_t          mask_y,
+				int32_t          dest_x,
+				int32_t          dest_y,
+				int32_t          width,
+				int32_t          height)
+{
+    pixman_format_code_t src_format, mask_format, dest_format;
+    uint32_t op_flags, src_flags, mask_flags, dest_flags;
+    pixman_region32_t region;
+    pixman_box32_t *extents;
+    pixman_implementation_t *imp;
+    pixman_composite_func_t func;
+    pixman_image_compositor_t *compositor;
+
+    _pixman_image_validate (src);
+    if (mask)
+	_pixman_image_validate (mask);
+    _pixman_image_validate (dest);
+
+    op_flags = 0;
+
+    src_format = src->common.extended_format_code;
+    src_flags = src->common.flags;
+
+    if (mask)
+    {
+	mask_format = mask->common.extended_format_code;
+	mask_flags = mask->common.flags;
+    }
+    else
+    {
+	mask_format = PIXMAN_null;
+	mask_flags = FAST_PATH_IS_OPAQUE;
+    }
+
+    dest_format = dest->common.extended_format_code;
+    dest_flags = dest->common.flags;
+
+    /* Check for pixbufs */
+    if ((mask_format == PIXMAN_a8r8g8b8 || mask_format == PIXMAN_a8b8g8r8) &&
+	(src->type == BITS && src->bits.bits == mask->bits.bits)	   &&
+	(src->common.repeat == mask->common.repeat)			   &&
+	(src_x == mask_x && src_y == mask_y))
+    {
+	if (src_format == PIXMAN_x8b8g8r8)
+	    src_format = mask_format = PIXMAN_pixbuf;
+	else if (src_format == PIXMAN_x8r8g8b8)
+	    src_format = mask_format = PIXMAN_rpixbuf;
+    }
+
+    pixman_region32_init (&region);
+
+    if (!pixman_compute_composite_region32 (
+	    &region, src, mask, dest,
+	    src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height))
+    {
+	return NULL;
+    }
+
+    extents = pixman_region32_extents (&region);
+
+    if (!analyze_extent (src, dest_x - src_x, dest_y - src_y, extents, &src_flags))
+	return NULL;
+
+    if (!analyze_extent (mask, dest_x - mask_x, dest_y - mask_y, extents, &mask_flags))
+	return NULL;
+
+    /* If the clip is within the source samples, and the samples are opaque,
+     * then the source is effectively opaque.
+     */
+#define BOTH (FAST_PATH_SAMPLES_OPAQUE | FAST_PATH_SAMPLES_COVER_CLIP)
+
+    if ((src_flags & BOTH) == BOTH)
+	src_flags |= FAST_PATH_IS_OPAQUE;
+
+    if ((mask_flags & BOTH) == BOTH)
+	mask_flags |= FAST_PATH_IS_OPAQUE;
+
+    /*
+     * 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, op_flags, src_flags, mask_flags, dest_flags);
+    if (op == PIXMAN_OP_DST)
+	return NULL;
+
+    compositor = malloc (sizeof (*compositor));
+    if (compositor == NULL)
+	return NULL;
+
+    compositor->info.op = op;
+    compositor->info.src_image = src;
+    compositor->info.mask_image = mask;
+    compositor->info.dest_image = dest;
+
+    compositor->info.src_x = src_x - dest_x;
+    compositor->info.src_y = src_y - dest_y;
+    compositor->info.mask_x = mask_x - dest_x;
+    compositor->info.mask_y = mask_y - dest_y;
+
+    if (! lookup_composite_function (zero_opacity_operator_table[op],
+				     op_flags | FAST_PATH_IS_OPAQUE,
+				     PIXMAN_null, FAST_PATH_IS_OPAQUE,
+				     PIXMAN_null, FAST_PATH_IS_OPAQUE,
+				     dest_format, dest_flags,
+				     &imp, &func))
+    {
+	return FALSE;
+    }
+    compositor->blt[BLT_ZERO].imp = imp;
+    compositor->blt[BLT_ZERO].func = func;
+
+    if (! lookup_composite_function (op, op_flags,
+				     src_format, src_flags,
+				     mask_format, mask_flags,
+				     dest_format, dest_flags,
+				     &imp, &func))
+    {
+	free (compositor);
+	return NULL;
+    }
+    compositor->blt[BLT_ALPHA].imp = imp;
+    compositor->blt[BLT_ALPHA].func = func;
+
+    op = optimize_operator (op, op_flags | FAST_PATH_IS_OPAQUE,
+			    src_flags, mask_flags, dest_flags);
+    if (! lookup_composite_function (op, op_flags | FAST_PATH_IS_OPAQUE,
+				     src_format, src_flags,
+				     mask_format, mask_flags,
+				     dest_format, dest_flags,
+				     &imp, &func))
+    {
+	free (compositor);
+	return NULL;
+    }
+    compositor->blt[BLT_OPAQUE].imp = imp;
+    compositor->blt[BLT_OPAQUE].func = func;
+
+    return compositor;
+}
+
+PIXMAN_EXPORT void
+pixman_image_compositor_blt (pixman_image_compositor_t *compositor,
+			     int32_t          x,
+			     int32_t          y,
+			     int32_t          width,
+			     int32_t          height,
+			     uint8_t          opacity)
+{
+    compositor->info.src_x += x;
+    compositor->info.src_y += y;
+
+    compositor->info.mask_x += x;
+    compositor->info.mask_y += y;
+
+    compositor->info.dest_x = x;
+    compositor->info.dest_y = y;
+    compositor->info.width = width;
+    compositor->info.height = height;
+
+    compositor->info.opacity = opacity;
+
+    {
+	pixman_implementation_t *imp;
+	pixman_composite_func_t func;
+
+	if (opacity == 0)
+	    func = compositor->blt[BLT_ZERO].func, imp = compositor->blt[BLT_ZERO].imp;
+	else if (opacity == 0xff)
+	    func = compositor->blt[BLT_OPAQUE].func, imp = compositor->blt[BLT_OPAQUE].imp;
+	else
+	    func = compositor->blt[BLT_ALPHA].func, imp = compositor->blt[BLT_ALPHA].imp;
+
+	func(imp, &compositor->info);
+    }
+
+    compositor->info.src_x -= x;
+    compositor->info.src_y -= y;
+
+    compositor->info.mask_x -= x;
+    compositor->info.mask_y -= y;
+}
+
+PIXMAN_EXPORT void
+pixman_image_compositor_destroy (pixman_image_compositor_t *compositor)
+{
+    free (compositor);
 }
 
 PIXMAN_EXPORT pixman_bool_t
diff --git a/pixman/pixman.h b/pixman/pixman.h
index a4fcc3b..322de8a 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -852,6 +852,32 @@ void          pixman_image_composite32        (pixman_op_t        op,
 					       int32_t            width,
 					       int32_t            height);
 
+typedef struct pixman_image_compositor pixman_image_compositor_t;
+
+pixman_image_compositor_t *
+pixman_image_create_compositor (pixman_op_t      op,
+				pixman_image_t * src,
+				pixman_image_t * mask,
+				pixman_image_t * dest,
+				int32_t          src_x,
+				int32_t          src_y,
+				int32_t          mask_x,
+				int32_t          mask_y,
+				int32_t          dest_x,
+				int32_t          dest_y,
+				int32_t          width,
+				int32_t          height);
+
+void pixman_image_compositor_blt (pixman_image_compositor_t *compositor,
+				  int32_t          x,
+				  int32_t          y,
+				  int32_t          width,
+				  int32_t          height,
+				  uint8_t          opacity);
+
+void pixman_image_compositor_destroy (pixman_image_compositor_t *compositor);
+
+
 /* Executive Summary: This function is a no-op that only exists
  * for historical reasons.
  *
diff --git a/test/lowlevel-blt-bench.c b/test/lowlevel-blt-bench.c
index b00e487..d0d416b 100644
--- a/test/lowlevel-blt-bench.c
+++ b/test/lowlevel-blt-bench.c
@@ -136,6 +136,7 @@ call_func (pixman_composite_func_t func,
     info.dest_y = dest_y;
     info.width = width;
     info.height = height;
+    info.opacity = 0xff;
 
     func (0, &info);
 }
-- 
1.7.5.4



More information about the cairo mailing list