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 (®ion, &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 (®ion);
+
+ if (!pixman_compute_composite_region32 (
+ ®ion, src, mask, dest,
+ src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height))
+ {
+ return NULL;
+ }
+
+ extents = pixman_region32_extents (®ion);
+
+ 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