diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-05-18 17:01:29 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-08-24 13:37:51 -0400 |
commit | c0b048ebef41b3a79d42e96c0ecaef65e1bb7599 (patch) | |
tree | eb634cbf7d8a07379490c36a795c6522bea58095 | |
parent | 0c1b6de4ad1b3e9d6da50979bb259f0acdc2fd2f (diff) |
Add support for A8 images to the LZ routines
This format is needed to add Render support to the X driver, so we
need the ability to compress and decompress it.
-rw-r--r-- | common/Makefile.am | 2 | ||||
-rw-r--r-- | common/canvas_base.c | 138 | ||||
-rw-r--r-- | common/canvas_base.h | 3 | ||||
-rw-r--r-- | common/draw.h | 20 | ||||
-rw-r--r-- | common/lz.c | 24 | ||||
-rw-r--r-- | common/lz_common.h | 5 | ||||
-rw-r--r-- | common/lz_compress_tmpl.c | 28 | ||||
-rw-r--r-- | common/lz_decompress_tmpl.c | 19 | ||||
-rw-r--r-- | common/messages.h | 5 | ||||
-rw-r--r-- | common/pixman_utils.c | 15 | ||||
-rw-r--r-- | common/sw_canvas.c | 20 | ||||
m--------- | spice-protocol | 0 | ||||
-rw-r--r-- | spice.proto | 56 |
13 files changed, 316 insertions, 19 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index 5f2c6e5..0e335b1 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -115,7 +115,7 @@ generated_client_marshallers1.c: $(top_srcdir)/spice1.proto $(MARSHALLERS_DEPS) generated_server_demarshallers.c: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS) $(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --server --include messages.h $< $@ >/dev/null -STRUCTS = -M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlend +STRUCTS = -M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlend -M Composite generated_server_marshallers.c: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS) $(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server --include messages.h $< $@ >/dev/null diff --git a/common/canvas_base.c b/common/canvas_base.c index 4f40306..0ec8526 100644 --- a/common/canvas_base.c +++ b/common/canvas_base.c @@ -776,6 +776,10 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image, int as_type = LZ_IMAGE_TYPE_RGB32; pixman_format = PIXMAN_x8r8g8b8; break; + case LZ_IMAGE_TYPE_A8: + as_type = LZ_IMAGE_TYPE_A8; + pixman_format = PIXMAN_a8; + break; case LZ_IMAGE_TYPE_RGB16: if (!want_original && (canvas->format == SPICE_SURFACE_FMT_32_xRGB || @@ -1271,13 +1275,25 @@ static void canvas_touch_image(CanvasBase *canvas, SpiceImage *image) static pixman_image_t* canvas_get_image_from_self(SpiceCanvas *canvas, int x, int y, - int32_t width, int32_t height) + int32_t width, int32_t height, + int force_opaque) { CanvasBase *canvas_base = (CanvasBase *)canvas; pixman_image_t *surface; uint8_t *dest; int dest_stride; SpiceRect area; + pixman_format_code_t format; + + format = spice_surface_format_to_pixman (canvas_base->format); + if (force_opaque) + { + /* Set alpha bits of the format to 0 */ + format = (pixman_format_code_t)(((uint32_t)format) & ~(0xf << 12)); + + spice_return_val_if_fail ( + pixman_format_supported_destination (format), NULL); + } surface = pixman_image_create_bits(spice_surface_format_to_pixman (canvas_base->format), width, height, NULL, 0); @@ -1919,7 +1935,7 @@ static void canvas_mask_pixman(CanvasBase *canvas, surface_canvas = canvas_get_surface_mask(canvas, mask->bitmap); if (surface_canvas) { needs_invert = mask->flags & SPICE_MASK_FLAGS_INVERS; - image = surface_canvas->ops->get_image(surface_canvas); + image = surface_canvas->ops->get_image(surface_canvas, FALSE); } else { needs_invert = FALSE; image = canvas_get_mask(canvas, @@ -3174,10 +3190,10 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, width = bbox->right - bbox->left; heigth = bbox->bottom - bbox->top; - d = canvas_get_image_from_self(spice_canvas, bbox->left, bbox->top, width, heigth); + d = canvas_get_image_from_self(spice_canvas, bbox->left, bbox->top, width, heigth, FALSE); surface_canvas = canvas_get_surface(canvas, rop3->src_bitmap); if (surface_canvas) { - s = surface_canvas->ops->get_image(surface_canvas); + s = surface_canvas->ops->get_image(surface_canvas, FALSE); } else { s = canvas_get_image(canvas, rop3->src_bitmap, FALSE); } @@ -3204,7 +3220,7 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, _surface_canvas = canvas_get_surface(canvas, rop3->brush.u.pattern.pat); if (_surface_canvas) { - p = _surface_canvas->ops->get_image(_surface_canvas); + p = _surface_canvas->ops->get_image(_surface_canvas, FALSE); } else { p = canvas_get_image(canvas, rop3->brush.u.pattern.pat, FALSE); } @@ -3228,6 +3244,117 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, pixman_region32_fini(&dest_region); } +static void transform_to_pixman_transform(SpiceTransform *transform, + pixman_transform_t *p) +{ + p->matrix[0][0] = transform->t00; + p->matrix[0][1] = transform->t01; + p->matrix[0][2] = transform->t02; + p->matrix[1][0] = transform->t10; + p->matrix[1][1] = transform->t11; + p->matrix[1][2] = transform->t12; + p->matrix[2][0] = 0; + p->matrix[2][1] = 0; + p->matrix[2][2] = pixman_fixed_1; +} + +#define MASK(lo, hi) \ + (((1U << (hi)) - 1) - (((1U << (lo))) - 1)) + +#define EXTRACT(v, lo, hi) \ + ((v & MASK(lo, hi)) >> lo) + +static void canvas_draw_composite(SpiceCanvas *spice_canvas, SpiceRect *bbox, + SpiceClip *clip, SpiceComposite *composite) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + SpiceCanvas *surface_canvas; + pixman_region32_t dest_region; + pixman_image_t *d; + pixman_image_t *s; + pixman_image_t *m; + pixman_repeat_t src_repeat; + pixman_filter_t src_filter; + pixman_op_t op; + pixman_transform_t transform; + int width, height; + + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + canvas_clip_pixman(canvas, &dest_region, clip); + + width = bbox->right - bbox->left; + height = bbox->bottom - bbox->top; + + /* Dest */ + d = canvas_get_image_from_self(spice_canvas, bbox->left, bbox->top, width, height, + (composite->flags & SPICE_COMPOSITE_DEST_OPAQUE)); + + /* Src */ + surface_canvas = canvas_get_surface(canvas, composite->src_bitmap); + if (surface_canvas) { + s = surface_canvas->ops->get_image(surface_canvas, + (composite->flags & SPICE_COMPOSITE_SOURCE_OPAQUE)); + } else { + s = canvas_get_image(canvas, composite->src_bitmap, FALSE); + } + if (composite->flags & SPICE_COMPOSITE_HAS_SRC_TRANSFORM) + { + transform_to_pixman_transform (&composite->src_transform, &transform); + pixman_image_set_transform (s, &transform); + } + src_filter = (pixman_filter_t) EXTRACT (composite->flags, 8, 11); + src_repeat = (pixman_repeat_t) EXTRACT (composite->flags, 14, 16); + pixman_image_set_filter (s, src_filter, NULL, 0); + pixman_image_set_repeat (s, src_repeat); + + /* Mask */ + m = NULL; + if (composite->flags & SPICE_COMPOSITE_HAS_MASK) { + pixman_filter_t mask_filter = (pixman_filter_t) EXTRACT (composite->flags, 11, 14); + pixman_repeat_t mask_repeat = (pixman_repeat_t) EXTRACT (composite->flags, 16, 18); + pixman_bool_t component_alpha = EXTRACT (composite->flags, 18, 19); + + surface_canvas = canvas_get_surface(canvas, composite->mask_bitmap); + if (surface_canvas) { + m = surface_canvas->ops->get_image(surface_canvas, FALSE); + } else { + m = canvas_get_image(canvas, composite->mask_bitmap, FALSE); + } + + if (composite->flags & SPICE_COMPOSITE_HAS_MASK_TRANSFORM) { + transform_to_pixman_transform (&composite->mask_transform, &transform); + pixman_image_set_transform (m, &transform); + } + + pixman_image_set_repeat (m, mask_repeat); + pixman_image_set_filter (m, mask_filter, NULL, 0); + pixman_image_set_component_alpha (m, component_alpha); + } + + op = (pixman_op_t) EXTRACT (composite->flags, 0, 8); + + pixman_image_composite32 (op, s, m, d, + composite->src_origin.x, composite->src_origin.y, + composite->mask_origin.x, composite->mask_origin.y, + 0, 0, width, height); + + pixman_image_unref(s); + if (m) + pixman_image_unref(m); + + spice_canvas->ops->blit_image(spice_canvas, &dest_region, d, + bbox->left, + bbox->top); + + pixman_image_unref(d); + + pixman_region32_fini(&dest_region); +} + static void canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos) { CanvasBase *canvas = (CanvasBase *)spice_canvas; @@ -3315,6 +3442,7 @@ inline static void canvas_base_init_ops(SpiceCanvasOps *ops) ops->draw_alpha_blend = canvas_draw_alpha_blend; ops->draw_stroke = canvas_draw_stroke; ops->draw_rop3 = canvas_draw_rop3; + ops->draw_composite = canvas_draw_composite; ops->group_start = canvas_base_group_start; ops->group_end = canvas_base_group_end; } diff --git a/common/canvas_base.h b/common/canvas_base.h index bdf12a1..637cdc1 100644 --- a/common/canvas_base.h +++ b/common/canvas_base.h @@ -133,6 +133,7 @@ typedef struct { void (*draw_text)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text); void (*draw_stroke)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke); void (*draw_rop3)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3); + void (*draw_composite)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceComposite *composite); void (*draw_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend); void (*draw_blackness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness); void (*draw_whiteness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness); @@ -306,7 +307,7 @@ typedef struct { void (*copy_region)(SpiceCanvas *canvas, pixman_region32_t *dest_region, int dx, int dy); - pixman_image_t *(*get_image)(SpiceCanvas *canvas); + pixman_image_t *(*get_image)(SpiceCanvas *canvas, int force_opaque); } SpiceCanvasOps; void spice_canvas_set_usr_data(SpiceCanvas *canvas, void *data, spice_destroy_fn_t destroy_fn); diff --git a/common/draw.h b/common/draw.h index 8fad0e5..3704358 100644 --- a/common/draw.h +++ b/common/draw.h @@ -223,6 +223,26 @@ typedef struct SpiceRop3 { SpiceQMask mask; } SpiceRop3; +/* Given in 16.16 fixed point */ +typedef struct SpiceTransform { + uint32_t t00; + uint32_t t01; + uint32_t t02; + uint32_t t10; + uint32_t t11; + uint32_t t12; +} SpiceTransform; + +typedef struct SpiceComposite { + uint32_t flags; + SpiceImage *src_bitmap; + SpiceImage *mask_bitmap; + SpiceTransform src_transform; + SpiceTransform mask_transform; + SpicePoint16 src_origin; + SpicePoint16 mask_origin; +} SpiceComposite; + typedef struct SpiceBlackness { SpiceQMask mask; } SpiceBlackness, SpiceInvers, SpiceWhiteness; diff --git a/common/lz.c b/common/lz.c index 568aae7..3d77aed 100644 --- a/common/lz.c +++ b/common/lz.c @@ -465,6 +465,13 @@ typedef uint16_t rgb16_pixel_t; #define TO_RGB32 #include "lz_decompress_tmpl.c" +#define LZ_A8 +#include "lz_compress_tmpl.c" +#define LZ_A8 +#include "lz_decompress_tmpl.c" +#define LZ_A8 +#define TO_RGB32 +#include "lz_decompress_tmpl.c" #define LZ_RGB16 #include "lz_compress_tmpl.c" @@ -514,7 +521,8 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do } } else { if (encoder->stride != width * RGB_BYTES_PER_PIXEL[encoder->type]) { - encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb)\n"); + encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb) %d %d %d\n", + encoder->stride, width, RGB_BYTES_PER_PIXEL[encoder->type]); } } @@ -560,6 +568,9 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do case LZ_IMAGE_TYPE_XXXA: lz_rgb_alpha_compress(encoder); break; + case LZ_IMAGE_TYPE_A8: + lz_a8_compress(encoder); + break; case LZ_IMAGE_TYPE_INVALID: default: encoder->usr->error(encoder->usr, "bad image type\n"); @@ -709,6 +720,17 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf) encoder->usr->error(encoder->usr, "unsupported output format\n"); } break; + case LZ_IMAGE_TYPE_A8: + if (encoder->type == to_type) { + alpha_size = lz_a8_decompress(encoder, (one_byte_pixel_t *)buf, size); + out_size = alpha_size; + } else if (to_type == LZ_IMAGE_TYPE_RGB32) { + alpha_size = lz_a8_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size); + out_size = alpha_size; + } else { + encoder->usr->error(encoder->usr, "unsupported output format\n"); + } + break; case LZ_IMAGE_TYPE_PLT1_LE: case LZ_IMAGE_TYPE_PLT1_BE: case LZ_IMAGE_TYPE_PLT4_LE: diff --git a/common/lz_common.h b/common/lz_common.h index 2ec374b..b5ce212 100644 --- a/common/lz_common.h +++ b/common/lz_common.h @@ -44,7 +44,8 @@ typedef enum { LZ_IMAGE_TYPE_RGB24, LZ_IMAGE_TYPE_RGB32, LZ_IMAGE_TYPE_RGBA, - LZ_IMAGE_TYPE_XXXA + LZ_IMAGE_TYPE_XXXA, + LZ_IMAGE_TYPE_A8 } LzImageType; #define LZ_IMAGE_TYPE_MASK 0x0f @@ -54,7 +55,7 @@ typedef enum { static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}; static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1}; -static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4}; +static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 1}; #define LZ_MAGIC (*(uint32_t *)"LZ ") diff --git a/common/lz_compress_tmpl.c b/common/lz_compress_tmpl.c index 6db5387..7e2ce42 100644 --- a/common/lz_compress_tmpl.c +++ b/common/lz_compress_tmpl.c @@ -71,6 +71,21 @@ } #endif +#ifdef LZ_A8 +#define PIXEL one_byte_pixel_t +#define FNAME(name) lz_a8_##name +#define ENCODE_PIXEL(e, pix) encode(e, (pix).a) // gets the pixel and write only the needed bytes + // from the pixel +#define SAME_PIXEL(pix1, pix2) ((pix1).a == (pix2).a) +#define HASH_FUNC(v, p) { \ + v = DJB2_START; \ + DJB2_HASH(v, p[0].a); \ + DJB2_HASH(v, p[1].a); \ + DJB2_HASH(v, p[2].a); \ + v &= HASH_MASK; \ + } +#endif + #ifdef LZ_RGB_ALPHA //#undef LZ_RGB_ALPHA #define PIXEL rgb32_pixel_t @@ -177,7 +192,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr size_t distance; /* minimum match length */ -#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) +#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8) size_t len = 3; #elif defined(LZ_RGB16) size_t len = 2; @@ -234,7 +249,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr ip++; /* minimum match length for rgb16 is 2 and for plt and alpha is 3 */ -#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16) +#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16) || defined(LZ_A8) if (!SAME_PIXEL(*ref, *ip)) { ref++; ip++; @@ -244,7 +259,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr ip++; #endif -#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) +#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8) if (!SAME_PIXEL(*ref, *ip)) { ref++; ip++; @@ -255,7 +270,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr #endif /* far, needs at least 5-byte match */ if (distance >= MAX_DISTANCE) { -#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) +#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8) if (ref >= (ref_limit - 1)) { goto literal; } @@ -272,7 +287,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr ref++; ip++; len++; -#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) +#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8) if (!SAME_PIXEL(*ref, *ip)) { ref++; ip++; @@ -464,9 +479,11 @@ static void FNAME(compress)(Encoder *encoder) LzImageSegment *cur_seg = encoder->head_image_segs; HashEntry *hslot; PIXEL *ip; + PIXEL *ip_start; // fetch the first image segment that is not too small while (cur_seg && ((((PIXEL *)cur_seg->lines_end) - ((PIXEL *)cur_seg->lines)) < 4)) { + ip_start = cur_seg->lines; // coping the segment if (cur_seg->lines != cur_seg->lines_end) { ip = (PIXEL *)cur_seg->lines; @@ -526,4 +543,5 @@ static void FNAME(compress)(Encoder *encoder) #undef LZ_RGB16 #undef LZ_RGB24 #undef LZ_RGB32 +#undef LZ_A8 #undef HASH_FUNC2 diff --git a/common/lz_decompress_tmpl.c b/common/lz_decompress_tmpl.c index fb41e77..04a5121 100644 --- a/common/lz_decompress_tmpl.c +++ b/common/lz_decompress_tmpl.c @@ -153,6 +153,22 @@ #endif // TO_RGB32 #endif +#ifdef LZ_A8 +#ifndef TO_RGB32 +#define OUT_PIXEL one_byte_pixel_t +#define FNAME(name) lz_a8_##name +#define COPY_COMP_PIXEL(encoder, out) {out->a = decode(encoder); out++;} +#else // TO_RGB32 +#define OUT_PIXEL rgb32_pixel_t +#define FNAME(name) lz_a8_to_rgb32_##name +#define COPY_COMP_PIXEL(encoder, out) { \ + (out)->b = (out)->g = (out)->r = 0; \ + (out)->pad = decode(encoder); \ + (out)++; \ + } +#endif +#endif + #ifdef LZ_RGB16 #ifndef TO_RGB32 #define OUT_PIXEL rgb16_pixel_t @@ -237,7 +253,7 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size) } } -#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) +#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8) len += 3; // length is biased by 2 + 1 (fixing bias) #elif defined(LZ_RGB16) len += 2; // length is biased by 1 + 1 (fixing bias) @@ -315,6 +331,7 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size) #undef LZ_RGB16 #undef LZ_RGB24 #undef LZ_RGB32 +#undef LZ_A8 #undef LZ_RGB_ALPHA #undef TO_RGB32 #undef OUT_PIXEL diff --git a/common/messages.h b/common/messages.h index 2b6d68a..b5f3368 100644 --- a/common/messages.h +++ b/common/messages.h @@ -253,6 +253,11 @@ typedef struct SpiceMsgDisplayDrawAlphaBlend { SpiceAlphaBlend data; } SpiceMsgDisplayDrawAlphaBlend; +typedef struct SpiceMsgDisplayDrawComposite { + SpiceMsgDisplayBase base; + SpiceComposite data; +} SpiceMsgDisplayDrawComposite; + typedef struct SpiceMsgDisplayCopyBits { SpiceMsgDisplayBase base; SpicePoint src_pos; diff --git a/common/pixman_utils.c b/common/pixman_utils.c index d4020e6..311c22e 100644 --- a/common/pixman_utils.c +++ b/common/pixman_utils.c @@ -963,6 +963,9 @@ pixman_format_code_t spice_bitmap_format_to_pixman(int bitmap_format, case SPICE_BITMAP_FMT_RGBA: return PIXMAN_a8r8g8b8; + case SPICE_BITMAP_FMT_8BIT_A: + return PIXMAN_a8; + case SPICE_BITMAP_FMT_INVALID: default: printf("Unknown bitmap format %d\n", bitmap_format); @@ -1083,6 +1086,15 @@ static void bitmap_32_to_32(uint8_t* dest, int dest_stride, #endif } +static void bitmap_8_to_8(uint8_t* dest, int dest_stride, + uint8_t* src, int src_stride, + int width, uint8_t* end) +{ + for (; src != end; src += src_stride, dest += dest_stride) { + memcpy(dest, src, width); + } +} + static void bitmap_24_to_32(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride, int width, uint8_t* end) @@ -1477,6 +1489,9 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image, case SPICE_BITMAP_FMT_RGBA: bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end); break; + case SPICE_BITMAP_FMT_8BIT_A: + bitmap_8_to_8(dest, dest_stride, src, src_stride, width, end); + break; case SPICE_BITMAP_FMT_24BIT: bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end); break; diff --git a/common/sw_canvas.c b/common/sw_canvas.c index 4b10383..f947dde 100644 --- a/common/sw_canvas.c +++ b/common/sw_canvas.c @@ -85,11 +85,27 @@ static pixman_image_t *canvas_get_pixman_brush(SwCanvas *canvas, return NULL; } -static pixman_image_t *get_image(SpiceCanvas *canvas) +static pixman_image_t *get_image(SpiceCanvas *canvas, int force_opaque) { SwCanvas *sw_canvas = (SwCanvas *)canvas; + pixman_format_code_t format; - pixman_image_ref(sw_canvas->image); + spice_pixman_image_get_format (sw_canvas->image, &format); + if (force_opaque && PIXMAN_FORMAT_A (format) != 0) { + uint32_t *data; + int stride; + int width, height; + + /* Remove alpha bits from format */ + format = (pixman_format_code_t)(((uint32_t)format) & ~(0xf << 12)); + data = pixman_image_get_data (sw_canvas->image); + stride = pixman_image_get_stride (sw_canvas->image); + width = pixman_image_get_width (sw_canvas->image); + height = pixman_image_get_height (sw_canvas->image); + return pixman_image_create_bits (format, width, height, data, stride); + } else { + pixman_image_ref(sw_canvas->image); + } return sw_canvas->image; } diff --git a/spice-protocol b/spice-protocol -Subproject da908f89b581fd4725da997fdaea209f8e6548f +Subproject 473a14b39fd7568e50456c61c95d89c742427ca diff --git a/spice.proto b/spice.proto index 1fdead9..29d6a8b 100644 --- a/spice.proto +++ b/spice.proto @@ -26,6 +26,15 @@ struct Rect { int32 right; }; +struct Transform { + uint32 t00; + uint32 t01; + uint32 t02; + uint32 t10; + uint32 t11; + uint32 t12; +}; + enum32 link_err { OK, ERROR, @@ -52,6 +61,28 @@ flags32 migrate_flags { NEED_DATA_TRANSFER } @prefix(SPICE_MIGRATE_); +flags32 composite_flags { + OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7, + SRC_FILTER0, SRC_FILTER1, SRC_FILTER2, + MASK_FILTER0, MASK_FITLER1, MASK_FILTER2, + + SRC_REPEAT0, SRC_REPEAT1, + MASK_REPEAT0, MASK_REPEAT1, + COMPONENT_ALPHA, + + HAS_MASK, + HAS_SRC_TRANSFORM, + HAS_MASK_TRANSFORM, + + /* These are used to override the formats given in the images. For + * example, if the mask image has format a8r8g8b8, but MASK_OPAQUE + * is set, the image should be treated as if it were x8r8g8b8 + */ + SOURCE_OPAQUE, + MASK_OPAQUE, + DEST_OPAQUE, +} @prefix(SPICE_COMPOSITE_); + enum32 notify_severity { INFO, WARN, @@ -321,7 +352,8 @@ enum8 bitmap_fmt { 16BIT, /* 0555 mode */ 24BIT /* 3 byte, brg */, 32BIT /* 4 byte, xrgb in little endian format */, - RGBA /* 4 byte, argb in little endian format */ + RGBA /* 4 byte, argb in little endian format */, + 8BIT_A /* 1 byte, alpha */ }; flags8 bitmap_flags { @@ -814,6 +846,28 @@ channel DisplayChannel : BaseChannel { Head heads[count] @end; } monitors_config; + message { + DisplayBase base; + struct Composite { + composite_flags flags; + Image *src_bitmap; + switch (flags) { + case HAS_MASK: + Image *mask_bitmap; + } a @anon; + switch (flags) { + case HAS_SRC_TRANSFORM: + Transform src_transform; + } b @anon; + switch (flags) { + case HAS_MASK_TRANSFORM: + Transform mask_transform; + } c @anon; + Point16 src_origin; + Point16 mask_origin; + } data; + } draw_composite; + client: message { uint8 pixmap_cache_id; |