[Spice-devel,2/3] Add support for QXLComposite to spice server

Submitted by Soeren Sandmann on Aug. 24, 2012, 1:02 a.m.

Details

Message ID 1345770124-13252-3-git-send-email-sandmann@cs.au.dk
State New
Headers show

Not browsing as part of any series.

Commit Message

Soeren Sandmann Aug. 24, 2012, 1:02 a.m.
From: Søren Sandmann Pedersen <ssp@redhat.com>

In red-parse-qxl.c add support for parsing QXLComposite into
SpiceComposite. In red-worker.c add support for marshalling
SpiceComposite onto the wire.
---
 server/red_memslots.c  |   2 +-
 server/red_parse_qxl.c |  59 +++++++++++++++++++++++++++-
 server/red_parse_qxl.h |   1 +
 server/red_worker.c    | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 164 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/server/red_memslots.c b/server/red_memslots.c
index 523890d..d9153d3 100644
--- a/server/red_memslots.c
+++ b/server/red_memslots.c
@@ -120,7 +120,7 @@  unsigned long get_virt(RedMemSlotInfo *info, QXLPHYSICAL addr, uint32_t add_size
     slot_id = get_memslot_id(info, addr);
     if (slot_id > info->num_memslots) {
         print_memslots(info);
-        spice_critical("slot_id too big, addr=%" PRIx64, addr);
+        spice_critical("slot_id %d too big, addr=%" PRIx64, slot_id, addr);
         *error = 1;
         return 0;
     }
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index 2953e80..bf57709 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -626,10 +626,61 @@  static void red_put_alpha_blend(SpiceAlphaBlend *red)
     red_put_image(red->src_bitmap);
 }
 
+static bool get_transform(RedMemSlotInfo *slots,
+                          int group_id,
+                          QXLPHYSICAL qxl_transform,
+                          SpiceTransform *dst_transform)
+                                                    
+{
+    const uint32_t *t = NULL;
+    int error;
+
+    if (qxl_transform == 0)
+        return FALSE;
+    
+    t = (uint32_t *)get_virt(slots, qxl_transform, sizeof(*dst_transform), group_id, &error);
+
+    if (!t || error)
+        return FALSE;
+
+    memcpy(dst_transform, t, sizeof(*dst_transform));
+    return TRUE;
+}
+
+static void red_get_composite_ptr(RedMemSlotInfo *slots, int group_id,
+                                  SpiceComposite *red, QXLComposite *qxl, uint32_t flags)
+{
+    red->flags = qxl->flags;
+
+    red->src_bitmap = red_get_image(slots, group_id, qxl->src, flags);
+    if (get_transform(slots, group_id, qxl->src_transform, &red->src_transform))
+        red->flags |= SPICE_COMPOSITE_HAS_SRC_TRANSFORM;
+    
+    if (qxl->mask) {
+        red->mask_bitmap = red_get_image(slots, group_id, qxl->mask, flags);
+        red->flags |= SPICE_COMPOSITE_HAS_MASK;
+        if (get_transform(slots, group_id, qxl->mask_transform, &red->mask_transform))
+            red->flags |= SPICE_COMPOSITE_HAS_MASK_TRANSFORM;
+    } else {
+        red->mask_bitmap = NULL;
+    }
+    red->src_origin.x = qxl->src_origin.x;
+    red->src_origin.y = qxl->src_origin.y;
+    red->mask_origin.x = qxl->mask_origin.x;
+    red->mask_origin.y = qxl->mask_origin.y;
+}
+
+static void red_put_composite(SpiceComposite *red)
+{
+    red_put_image(red->src_bitmap);
+    if (red->mask_bitmap)
+        red_put_image(red->mask_bitmap);
+}
+
 static void red_get_rop3_ptr(RedMemSlotInfo *slots, int group_id,
                              SpiceRop3 *red, QXLRop3 *qxl, uint32_t flags)
 {
-    red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags);
+   red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags);
    red_get_rect_ptr(&red->src_area, &qxl->src_area);
    red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
    red->rop3       = qxl->rop3;
@@ -900,6 +951,9 @@  static int red_get_native_drawable(RedMemSlotInfo *slots, int group_id,
     case QXL_DRAW_ROP3:
         red_get_rop3_ptr(slots, group_id, &red->u.rop3, &qxl->u.rop3, flags);
         break;
+    case QXL_DRAW_COMPOSITE:
+        red_get_composite_ptr(slots, group_id, &red->u.composite, &qxl->u.composite, flags);
+        break;
     case QXL_DRAW_STROKE:
         error = red_get_stroke_ptr(slots, group_id, &red->u.stroke, &qxl->u.stroke, flags);
         break;
@@ -1052,6 +1106,9 @@  void red_put_drawable(RedDrawable *red)
     case QXL_DRAW_ROP3:
         red_put_rop3(&red->u.rop3);
         break;
+    case QXL_DRAW_COMPOSITE:
+        red_put_composite(&red->u.composite);
+        break;
     case QXL_DRAW_STROKE:
         red_put_stroke(&red->u.stroke);
         break;
diff --git a/server/red_parse_qxl.h b/server/red_parse_qxl.h
index 70f8509..3adc9fa 100644
--- a/server/red_parse_qxl.h
+++ b/server/red_parse_qxl.h
@@ -53,6 +53,7 @@  typedef struct RedDrawable {
         SpiceBlackness blackness;
         SpiceInvers invers;
         SpiceWhiteness whiteness;
+        SpiceComposite composite;
     } u;
 } RedDrawable;
 
diff --git a/server/red_worker.c b/server/red_worker.c
index 59749f9..bd6de1c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1254,6 +1254,8 @@  static inline void validate_surface(RedWorker *worker, uint32_t surface_id)
 {
     spice_warn_if(surface_id >= worker->n_surfaces);
     if (!worker->surfaces[surface_id].context.canvas) {
+        spice_warning("canvas address is %p for %d (and is NULL)\n",
+                   &(worker->surfaces[surface_id].context.canvas), surface_id);
         spice_warning("failed on %d", surface_id);
         spice_warn_if(!worker->surfaces[surface_id].context.canvas);
     }
@@ -1284,6 +1286,8 @@  static const char *draw_type_to_str(uint8_t type)
         return "QXL_DRAW_INVERS";
     case QXL_DRAW_ROP3:
         return "QXL_DRAW_ROP3";
+    case QXL_DRAW_COMPOSITE:
+        return "QXL_DRAW_COMPOSITE";
     case QXL_DRAW_STROKE:
         return "QXL_DRAW_STROKE";
     case QXL_DRAW_TEXT:
@@ -1319,6 +1323,7 @@  static void show_red_drawable(RedWorker *worker, RedDrawable *drawable, const ch
     case QXL_DRAW_WHITENESS:
     case QXL_DRAW_INVERS:
     case QXL_DRAW_ROP3:
+    case QXL_DRAW_COMPOSITE:
     case QXL_DRAW_STROKE:
     case QXL_DRAW_TEXT:
         break;
@@ -4347,6 +4352,16 @@  static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
                                &clip, &rop3);
         break;
     }
+    case QXL_DRAW_COMPOSITE: {
+        SpiceComposite composite = drawable->red_drawable->u.composite;
+        SpiceImage src, mask;
+        localize_bitmap(worker, &composite.src_bitmap, &src, drawable);
+        if (composite.mask_bitmap)
+            localize_bitmap(worker, &composite.mask_bitmap, &mask, drawable);
+        canvas->ops->draw_composite(canvas, &drawable->red_drawable->bbox,
+                                    &clip, &composite);
+        break;
+    }
     case QXL_DRAW_STROKE: {
         SpiceStroke stroke = drawable->red_drawable->u.stroke;
         SpiceImage img1;
@@ -7679,6 +7694,89 @@  static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
     }
 }
 
+static void red_marshall_qxl_draw_composite(RedWorker *worker,
+                                     RedChannelClient *rcc,
+                                     SpiceMarshaller *base_marshaller,
+                                     DrawablePipeItem *dpi)
+{
+    Drawable *item = dpi->drawable;
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    RedDrawable *drawable = item->red_drawable;
+    SpiceMarshaller *src_bitmap_out;
+    SpiceMarshaller *mask_bitmap_out;
+    SpiceComposite composite;
+
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COMPOSITE, &dpi->dpi_pipe_item);
+    fill_base(base_marshaller, item);
+    composite = drawable->u.composite;
+    spice_marshall_Composite(base_marshaller,
+                             &composite,
+                             &src_bitmap_out,
+                             &mask_bitmap_out);
+
+    fill_bits(dcc, src_bitmap_out, composite.src_bitmap, item, FALSE);
+    if (mask_bitmap_out) {
+        fill_bits(dcc, mask_bitmap_out, composite.mask_bitmap, item, FALSE);
+    }
+}
+
+static void red_lossy_marshall_qxl_draw_composite(RedWorker *worker,
+                                                  RedChannelClient *rcc,
+                                                  SpiceMarshaller *base_marshaller,
+                                                  DrawablePipeItem *dpi)
+{
+    Drawable *item = dpi->drawable;
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    RedDrawable *drawable = item->red_drawable;
+    int src_is_lossy;
+    BitmapData src_bitmap_data;
+    int mask_is_lossy;
+    BitmapData mask_bitmap_data;
+    int dest_is_lossy;
+    SpiceRect dest_lossy_area;
+
+    src_is_lossy = is_bitmap_lossy(rcc, drawable->u.composite.src_bitmap,
+                                   NULL, item, &src_bitmap_data);
+    mask_is_lossy = drawable->u.composite.mask_bitmap &&
+        is_bitmap_lossy(rcc, drawable->u.composite.mask_bitmap, NULL, item, &mask_bitmap_data);
+
+    dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
+                                          &drawable->bbox, &dest_lossy_area);
+
+    if ((!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))   &&
+        (!mask_is_lossy || (mask_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
+        !dest_is_lossy) {
+        red_marshall_qxl_draw_composite(worker, rcc, base_marshaller, dpi);
+        surface_lossy_region_update(worker, dcc, item, FALSE, FALSE);
+    }
+    else {
+        int resend_surface_ids[3];
+        SpiceRect *resend_areas[3];
+        int num_resend = 0;
+
+        if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) {
+            resend_surface_ids[num_resend] = src_bitmap_data.id;
+            resend_areas[num_resend] = &src_bitmap_data.lossy_rect;
+            num_resend++;
+        }
+
+        if (mask_is_lossy && (mask_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) {
+            resend_surface_ids[num_resend] = mask_bitmap_data.id;
+            resend_areas[num_resend] = &mask_bitmap_data.lossy_rect;
+            num_resend++;
+        }
+
+        if (dest_is_lossy) {
+            resend_surface_ids[num_resend] = item->surface_id;
+            resend_areas[num_resend] = &dest_lossy_area;
+            num_resend++;
+        }
+
+        red_add_lossless_drawable_dependencies(worker, rcc, item,
+                                               resend_surface_ids, resend_areas, num_resend);
+    }
+}
+
 static void red_marshall_qxl_draw_stroke(RedWorker *worker,
                                      RedChannelClient *rcc,
                                      SpiceMarshaller *base_marshaller,
@@ -7895,6 +7993,9 @@  static void red_lossy_marshall_qxl_drawable(RedWorker *worker, RedChannelClient
     case QXL_DRAW_ROP3:
         red_lossy_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, dpi);
         break;
+    case QXL_DRAW_COMPOSITE:
+        red_lossy_marshall_qxl_draw_composite(worker, rcc, base_marshaller, dpi);
+        break;
     case QXL_DRAW_STROKE:
         red_lossy_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, dpi);
         break;
@@ -7949,6 +8050,9 @@  static inline void red_marshall_qxl_drawable(RedWorker *worker, RedChannelClient
     case QXL_DRAW_STROKE:
         red_marshall_qxl_draw_stroke(worker, rcc, m, dpi);
         break;
+    case QXL_DRAW_COMPOSITE:
+        red_marshall_qxl_draw_composite(worker, rcc, m, dpi);
+        break;
     case QXL_DRAW_TEXT:
         red_marshall_qxl_draw_text(worker, rcc, m, dpi);
         break;