[Spice-devel] [PATCH 3/3] Add support for a new Composite request
Søren Sandmann Pedersen
sandmann at cs.au.dk
Thu Aug 23 18:00:51 PDT 2012
From: Søren Sandmann Pedersen <ssp at redhat.com>
Most desktop applications on Linux rely on the X11 Render extensions
for image compositing, which is poorly supported in SPICE. This patch
implements support for a compositing command that supports the image
compositing features of Render.
The pixman library that SPICE is using already contains an
implementation of Render, so this patch mainly consists of adding a
new composite method to the canvas interface, and then implementing
that method with the pixman_image_composite32() function.
---
common/Makefile.am | 2 +-
common/canvas_base.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++--
common/canvas_base.h | 3 +-
common/draw.h | 20 ++++++++
common/messages.h | 5 ++
common/sw_canvas.c | 20 +++++++-
spice-protocol | 2 +-
spice.proto | 56 ++++++++++++++++++++-
8 files changed, 231 insertions(+), 11 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 c60c5cf..0ec8526 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -1275,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);
@@ -1923,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,
@@ -3178,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);
}
@@ -3208,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);
}
@@ -3232,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;
@@ -3319,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/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/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
index 6ef7050..fa3de2f 160000
--- a/spice-protocol
+++ b/spice-protocol
@@ -1 +1 @@
-Subproject commit 6ef7050b0725dbe385eed290e73a2603af7d3fbc
+Subproject commit fa3de2fbf29c5f8819503643b25cba4598d6f68a
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;
--
1.7.11.4
More information about the Spice-devel
mailing list