From 810caf0e779bf280370221018bee6a0d4d63160b Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 23 Apr 2010 15:15:40 +0200 Subject: Support alpha surface sources and destinations --- common/cairo_canvas.c | 79 ++++++++++++++++++++++++++++++++++++++++++--------- common/canvas_base.c | 32 +++++++++++++++++---- common/canvas_base.h | 6 ++++ 3 files changed, 99 insertions(+), 18 deletions(-) (limited to 'common') diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c index 931fd36b..a324c446 100644 --- a/common/cairo_canvas.c +++ b/common/cairo_canvas.c @@ -555,8 +555,28 @@ static void scale_image_rop_from_surface(SpiceCanvas *spice_canvas, src_height, dest_x, dest_y, dest_width, dest_height, scale_mode, rop); } +static pixman_image_t *canvas_get_as_surface(CairoCanvas *canvas, + int with_alpha) +{ + pixman_image_t *target; + + if (with_alpha && + canvas->base.format == SPICE_SURFACE_FMT_32_xRGB) { + target = pixman_image_create_bits(PIXMAN_a8r8g8b8, + pixman_image_get_width(canvas->image), + pixman_image_get_height(canvas->image), + pixman_image_get_data(canvas->image), + pixman_image_get_stride(canvas->image)); + } else { + target = pixman_image_ref(canvas->image); + } + + return target; +} + static void __blend_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, + int dest_has_alpha, pixman_image_t *src, int src_x, int src_y, int dest_x, int dest_y, @@ -564,9 +584,11 @@ static void __blend_image(SpiceCanvas *spice_canvas, int overall_alpha) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - pixman_image_t *mask; + pixman_image_t *mask, *dest; - pixman_image_set_clip_region32(canvas->image, region); + dest = canvas_get_as_surface(canvas, dest_has_alpha); + + pixman_image_set_clip_region32(dest, region); mask = NULL; if (overall_alpha != 0xff) { @@ -578,7 +600,7 @@ static void __blend_image(SpiceCanvas *spice_canvas, pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE); pixman_image_composite32(PIXMAN_OP_OVER, - src, mask, canvas->image, + src, mask, dest, src_x, src_y, /* src */ 0, 0, /* mask */ dest_x, dest_y, /* dst */ @@ -589,36 +611,48 @@ static void __blend_image(SpiceCanvas *spice_canvas, pixman_image_unref(mask); } - pixman_image_set_clip_region32(canvas->image, NULL); + pixman_image_set_clip_region32(dest, NULL); + pixman_image_unref(dest); } static void blend_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, + int dest_has_alpha, pixman_image_t *src, int src_x, int src_y, int dest_x, int dest_y, int width, int height, int overall_alpha) { - __blend_image(spice_canvas, region, src, src_x, src_y, dest_x, dest_y, width, height, + __blend_image(spice_canvas, region, dest_has_alpha, src, src_x, src_y, + dest_x, dest_y, width, height, overall_alpha); } static void blend_image_from_surface(SpiceCanvas *spice_canvas, pixman_region32_t *region, + int dest_has_alpha, SpiceCanvas *surface_canvas, + int src_has_alpha, int src_x, int src_y, int dest_x, int dest_y, int width, int height, int overall_alpha) { CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; - __blend_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, dest_x, dest_y, + pixman_image_t *src; + + src = canvas_get_as_surface(cairo_surface_canvas, src_has_alpha); + __blend_image(spice_canvas, region, dest_has_alpha, + src, src_x, src_y, + dest_x, dest_y, width, height, overall_alpha); + pixman_image_unref(src); } static void __blend_scale_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, + int dest_has_alpha, pixman_image_t *src, int src_x, int src_y, int src_width, int src_height, @@ -629,13 +663,15 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas, { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; - pixman_image_t *mask; + pixman_image_t *mask, *dest; double sx, sy; sx = (double)(src_width) / (dest_width); sy = (double)(src_height) / (dest_height); - pixman_image_set_clip_region32(canvas->image, region); + dest = canvas_get_as_surface(canvas, dest_has_alpha); + + pixman_image_set_clip_region32(dest, region); pixman_transform_init_scale(&transform, pixman_double_to_fixed(sx), @@ -658,7 +694,7 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas, NULL, 0); pixman_image_composite32(PIXMAN_OP_OVER, - src, mask, canvas->image, + src, mask, dest, ROUND(src_x / sx), ROUND(src_y / sy), /* src */ 0, 0, /* mask */ dest_x, dest_y, /* dst */ @@ -671,11 +707,13 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas, pixman_image_unref(mask); } - pixman_image_set_clip_region32(canvas->image, NULL); + pixman_image_set_clip_region32(dest, NULL); + pixman_image_unref(dest); } static void blend_scale_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, + int dest_has_alpha, pixman_image_t *src, int src_x, int src_y, int src_width, int src_height, @@ -684,13 +722,17 @@ static void blend_scale_image(SpiceCanvas *spice_canvas, int scale_mode, int overall_alpha) { - __blend_scale_image(spice_canvas, region, src, src_x, src_y, src_width, src_height, dest_x, - dest_y, dest_width, dest_height, scale_mode, overall_alpha); + __blend_scale_image(spice_canvas, region, dest_has_alpha, + src, src_x, src_y, src_width, src_height, + dest_x, dest_y, dest_width, dest_height, + scale_mode, overall_alpha); } static void blend_scale_image_from_surface(SpiceCanvas *spice_canvas, pixman_region32_t *region, + int dest_has_alpha, SpiceCanvas *surface_canvas, + int src_has_alpha, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y, @@ -699,9 +741,13 @@ static void blend_scale_image_from_surface(SpiceCanvas *spice_canvas, int overall_alpha) { CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; - __blend_scale_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, src_width, + pixman_image_t *src; + + src = canvas_get_as_surface(cairo_surface_canvas, src_has_alpha); + __blend_scale_image(spice_canvas, region, dest_has_alpha, src, src_x, src_y, src_width, src_height, dest_x, dest_y, dest_width, dest_height, scale_mode, overall_alpha); + pixman_image_unref(src); } static void __colorkey_image(SpiceCanvas *spice_canvas, @@ -1116,6 +1162,9 @@ SpiceCanvas *canvas_create(int width, int height, uint32_t format { pixman_image_t *image; + if (format == SPICE_SURFACE_FMT_32_ARGB) { + format = SPICE_SURFACE_FMT_32_xRGB; + } image = pixman_image_create_bits(spice_surface_format_to_pixman (format), width, height, NULL, 0); @@ -1151,6 +1200,10 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, { pixman_image_t *image; + if (format == SPICE_SURFACE_FMT_32_ARGB) { + format = SPICE_SURFACE_FMT_32_xRGB; + } + image = pixman_image_create_bits(spice_surface_format_to_pixman (format), width, height, (uint32_t *)data, stride); diff --git a/common/canvas_base.c b/common/canvas_base.c index e1201af7..c305f4df 100644 --- a/common/canvas_base.c +++ b/common/canvas_base.c @@ -414,10 +414,26 @@ static pixman_format_code_t canvas_get_target_format(CanvasBase *canvas, /* Convert to target surface format */ format = spice_surface_format_to_pixman (canvas->format); - if (!source_has_alpha) { + if (source_has_alpha) { + /* Even though the destination has no alpha, we make the source + * remember there are alpha bits instead of throwing away this + * information. The results are the same if alpha is not + * interpreted, and if need to interpret alpha, don't use + * conversion to target format. + * This is needed for instance when doing the final + * canvas_get_target_format() in canvas_get_image_internal + * as otherwise we wouldn't know if the bitmap source + * really had alpha. + */ + if (format == PIXMAN_x8r8g8b8) { + format = PIXMAN_a8r8g8b8; + } + } else { /* !source_has_alpha */ /* If the source doesn't have alpha, but the destination has, - don't convert to alpha, since that would fill the alpha bytes - with 0xff which is not expected if we just use the raw bits */ + don't convert to alpha, since that would just do an unnecessary + copy to fill the alpha bytes with 0xff which is not expected if + we just use the raw bits, (and handled implicitly by pixman if + we're interpreting data) */ if (format == PIXMAN_a8r8g8b8) { format = PIXMAN_x8r8g8b8; } @@ -914,7 +930,7 @@ static SpiceCanvas *canvas_get_surface_internal(CanvasBase *canvas, SPICE_ADDRES static SpiceCanvas *canvas_get_surface_mask_internal(CanvasBase *canvas, SPICE_ADDRESS addr) { SpiceImageDescriptor *descriptor; - + descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr); access_test(canvas, descriptor, sizeof(SpiceImageDescriptor)); @@ -2222,7 +2238,9 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, if (surface_canvas) { if (rect_is_same_size(bbox, &alpha_blend->src_area)) { spice_canvas->ops->blend_image_from_surface(spice_canvas, &dest_region, + alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA, surface_canvas, + alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA, alpha_blend->src_area.left, alpha_blend->src_area.top, bbox->left, @@ -2232,7 +2250,9 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, alpha_blend->alpha); } else { spice_canvas->ops->blend_scale_image_from_surface(spice_canvas, &dest_region, + alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA, surface_canvas, + alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA, alpha_blend->src_area.left, alpha_blend->src_area.top, alpha_blend->src_area.right - alpha_blend->src_area.left, @@ -2248,6 +2268,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, src_image = canvas_get_image(canvas, alpha_blend->src_bitmap, TRUE); if (rect_is_same_size(bbox, &alpha_blend->src_area)) { spice_canvas->ops->blend_image(spice_canvas, &dest_region, + alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA, src_image, alpha_blend->src_area.left, alpha_blend->src_area.top, @@ -2258,6 +2279,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, alpha_blend->alpha); } else { spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region, + alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA, src_image, alpha_blend->src_area.left, alpha_blend->src_area.top, @@ -2270,7 +2292,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SPICE_IMAGE_SCALE_MODE_NEAREST, alpha_blend->alpha); } - + pixman_image_unref(src_image); } diff --git a/common/canvas_base.h b/common/canvas_base.h index f2b0d5bf..f78b0b8d 100644 --- a/common/canvas_base.h +++ b/common/canvas_base.h @@ -206,6 +206,7 @@ typedef struct { int scale_mode, SpiceROP rop); void (*blend_image)(SpiceCanvas *canvas, pixman_region32_t *region, + int dest_has_alpha, pixman_image_t *src_image, int src_x, int src_y, int dest_x, int dest_y, @@ -213,13 +214,16 @@ typedef struct { int overall_alpha); void (*blend_image_from_surface)(SpiceCanvas *canvas, pixman_region32_t *region, + int dest_has_alpha, SpiceCanvas *src_image, + int src_has_alpha, int src_x, int src_y, int dest_x, int dest_y, int width, int height, int overall_alpha); void (*blend_scale_image)(SpiceCanvas *canvas, pixman_region32_t *region, + int dest_has_alpha, pixman_image_t *src_image, int src_x, int src_y, int src_width, int src_height, @@ -229,7 +233,9 @@ typedef struct { int overall_alpha); void (*blend_scale_image_from_surface)(SpiceCanvas *canvas, pixman_region32_t *region, + int dest_has_alpha, SpiceCanvas *src_image, + int src_has_alpha, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y, -- cgit