diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-08-20 17:47:18 +0100 |
---|---|---|
committer | Taekyun Kim <tkq.kim@samsung.com> | 2011-08-24 15:47:30 +0900 |
commit | caa56631a00d3e8c79aee7fb9cfaa50775810fc7 (patch) | |
tree | eeb2b6e051fefc7ef49ba1248ffdd00a44d5bba9 | |
parent | fae4f3d0eba159bd568ce28e04b63abfe044f81b (diff) |
spans
-rw-r--r-- | pixman/pixman-fast-path.c | 6 | ||||
-rw-r--r-- | pixman/pixman-general.c | 78 | ||||
-rw-r--r-- | pixman/pixman-inlines.h | 48 | ||||
-rw-r--r-- | pixman/pixman-noop.c | 2 | ||||
-rw-r--r-- | pixman/pixman-private.h | 38 | ||||
-rw-r--r-- | pixman/pixman.c | 354 | ||||
-rw-r--r-- | pixman/pixman.h | 26 | ||||
-rw-r--r-- | 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); } |