[Spice-devel] [PATCH 2/9] support for lossy images in the pixmap cache and fill bits

Yonit Halperin yhalperi at redhat.com
Tue Jun 1 00:30:51 PDT 2010


1) add an option to determine if a bitmap can be sent lossy to the client
2) when required, replacing lossy cache items with their correspending
   lossless bitmaps
---
 client/canvas.cpp                |    1 +
 client/canvas.h                  |   23 ++++++++++-
 client/shared_cache.hpp          |   80 +++++++++++++++++++++++++++++++++--
 common/canvas_base.c             |   56 ++++++++++++++++++++++--
 common/canvas_base.h             |   10 ++++
 server/red_client_shared_cache.h |   24 ++++++++++-
 server/red_worker.c              |   86 ++++++++++++++++++++++++++------------
 7 files changed, 241 insertions(+), 39 deletions(-)

diff --git a/client/canvas.cpp b/client/canvas.cpp
index 0a4d8e5..4ed1e18 100644
--- a/client/canvas.cpp
+++ b/client/canvas.cpp
@@ -91,6 +91,7 @@ void Canvas::localalize_image(SPICE_ADDRESS* in_bitmap)
     case SPICE_IMAGE_TYPE_JPEG:
         break;
     case SPICE_IMAGE_TYPE_FROM_CACHE:
+    case SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS:
         break;
     default:
         THROW("invalid image type %u", image->type);
diff --git a/client/canvas.h b/client/canvas.h
index 8d64ca3..f0314b9 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -163,17 +163,38 @@ public:
         cache->add(id, surface);
     }
 
+    static void op_put_lossy(SpiceImageCache *c, uint64_t id, pixman_image_t *surface)
+    {
+        PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
+        cache->add(id, surface, TRUE);
+    }
+
+    static void op_replace_lossy(SpiceImageCache *c, uint64_t id, pixman_image_t *surface)
+    {
+        PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
+        cache->replace(id, surface);
+    }
+
     static pixman_image_t* op_get(SpiceImageCache *c, uint64_t id)
     {
         PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
         return cache->get(id);
     }
 
+    static pixman_image_t* op_get_lossless(SpiceImageCache *c, uint64_t id)
+    {
+        PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
+        return cache->get_lossless(id);
+    }
+
     SpiceImageCacheBase()
     {
         static SpiceImageCacheOps cache_ops = {
             op_put,
-            op_get
+            op_get,
+            op_put_lossy,
+            op_replace_lossy,
+            op_get_lossless
         };
         base.ops = &cache_ops;
     }
diff --git a/client/shared_cache.hpp b/client/shared_cache.hpp
index 8836025..a830854 100644
--- a/client/shared_cache.hpp
+++ b/client/shared_cache.hpp
@@ -41,7 +41,7 @@ public:
         clear();
     }
 
-    void add(uint64_t id, T* data)
+    void add(uint64_t id, T* data, bool is_lossy = FALSE)
     {
         Lock lock(_lock);
         Item** item = &_hash[key(id)];
@@ -53,7 +53,7 @@ public:
             }
             item = &(*item)->next;
         }
-        *item = new Item(id, data);
+        *item = new Item(id, data, is_lossy);
         _new_item_cond.notify_all();
     }
 
@@ -81,6 +81,68 @@ public:
         }
     }
 
+    T* get_lossless(uint64_t id)
+    {
+        Lock lock(_lock);
+        Item* item = _hash[key(id)];
+
+        for (;;) {
+            if (!item) {
+                if (_aborting) {
+                    THROW("%s aborting", Treat::name());
+                }
+                _new_item_cond.wait(lock);
+                item = _hash[key(id)];
+                continue;
+            }
+
+            if (item->id != id) {
+                item = item->next;
+                continue;
+            }
+            break;
+        }
+
+        // item has been retreived. Now checking if lossless
+        for (;;) {
+            if (item->lossy) {
+                if (_aborting) {
+                    THROW("%s aborting", Treat::name());
+                }
+                _replace_data_cond.wait(lock);
+                continue;
+            }
+
+            return Treat::get(item->data);
+        }
+    }
+
+    void replace(uint64_t id, T* data, bool is_lossy = FALSE)
+    {
+        Lock lock(_lock);
+        Item* item = _hash[key(id)];
+
+        for (;;) {
+            if (!item) {
+                if (_aborting) {
+                    THROW("%s aborting", Treat::name());
+                }
+                _new_item_cond.wait(lock);
+                item = _hash[key(id)];
+                continue;
+            }
+
+            if (item->id != id) {
+                item = item->next;
+                continue;
+            }
+
+            item->replace(data, is_lossy);
+            break;
+        }
+        _replace_data_cond.notify_all();
+    }
+
     void remove(uint64_t id)
     {
         Lock lock(_lock);
@@ -125,26 +187,36 @@ private:
 private:
     class Item {
     public:
-        Item(uint64_t in_id, T* data)
+        Item(uint64_t in_id, T* data, bool is_lossy = FALSE)
             : id (in_id)
             , refs (1)
             , next (NULL)
-            , data (Treat::get(data)) {}
+            , data (Treat::get(data))
+            , lossy (is_lossy) {}
 
         ~Item()
         {
             Treat::release(data);
         }
 
+        void replace(T* new_data, bool is_lossy = FALSE)
+        {
+            Treat::release(data);
+            data = Treat::get(new_data);
+            lossy = is_lossy;
+        }
+
         uint64_t id;
         int refs;
         Item* next;
         T* data;
+        bool lossy;
     };
 
     Item* _hash[HASH_SIZE];
     Mutex _lock;
     Condition _new_item_cond;
+    Condition _replace_data_cond;
     bool _aborting;
 };
 
diff --git a/common/canvas_base.c b/common/canvas_base.c
index 8180f09..aac472c 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -567,7 +567,7 @@ static void dump_jpeg(uint8_t* data, int data_size)
     if (!f) {
         return;
     }
-    
+
     fwrite(data, 1, data_size, f);
     fclose(f);
 }
@@ -1044,12 +1044,19 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
      * to happen which breaks if we don't. */
     if (!real_get &&
         !(descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME) &&
+#ifdef SW_CANVAS_CACHE
+        !(descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME) &&
+#endif
         (descriptor->type != SPICE_IMAGE_TYPE_GLZ_RGB)) {
         return NULL;
     }
 
     saved_want_original = want_original;
-    if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME) {
+    if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME
+#ifdef SW_CANVAS_CACHE
+        || descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME
+#endif
+       ) {
         want_original = TRUE;
     }
 
@@ -1092,7 +1099,11 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
     case SPICE_IMAGE_TYPE_FROM_CACHE:
         surface = canvas->bits_cache->ops->get(canvas->bits_cache, descriptor->id);
         break;
-
+#ifdef SW_CANVAS_CACHE
+    case SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS:
+        surface = canvas->bits_cache->ops->get_lossless(canvas->bits_cache, descriptor->id);
+        break;
+#endif
     case SPICE_IMAGE_TYPE_BITMAP: {
         SpiceBitmapImage *bitmap = (SpiceBitmapImage *)descriptor;
         access_test(canvas, descriptor, sizeof(SpiceBitmapImage));
@@ -1107,6 +1118,9 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
 
     if (descriptor->flags & SPICE_IMAGE_FLAGS_HIGH_BITS_SET &&
         descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE &&
+#ifdef SW_CANVAS_CACHE
+        descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS &&
+#endif
         surface_format == PIXMAN_x8r8g8b8) {
         spice_pixman_fill_rect_rop(surface,
                                    0, 0,
@@ -1116,13 +1130,39 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
     }
 
     if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME &&
-        descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE) {
+#ifdef SW_CANVAS_CACHE
+        descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS &&
+#endif
+        descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE ) {
+#ifdef SW_CANVAS_CACHE
+       if (descriptor->type != SPICE_IMAGE_TYPE_JPEG) {
+            canvas->bits_cache->ops->put(canvas->bits_cache, descriptor->id, surface);
+        } else {
+            canvas->bits_cache->ops->put_lossy(canvas->bits_cache, descriptor->id, surface);
+        }
+#else
         canvas->bits_cache->ops->put(canvas->bits_cache, descriptor->id, surface);
+#endif
+#ifdef DEBUG_DUMP_SURFACE
+        dump_surface(surface, 1);
+#endif
+#ifdef SW_CANVAS_CACHE
+    } else if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME) {
+        if (descriptor->type == SPICE_IMAGE_TYPE_JPEG) {
+            CANVAS_ERROR("invalid cache replace request: the image is lossy");
+        }
+        canvas->bits_cache->ops->replace_lossy(canvas->bits_cache, descriptor->id, surface);
 #ifdef DEBUG_DUMP_SURFACE
         dump_surface(surface, 1);
 #endif
-    } else if (descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE) {
+#endif
 #ifdef DEBUG_DUMP_SURFACE
+    } else if (descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE
+#ifdef SW_CANVAS_CACHE
+               && descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS
+#endif
+    ) {
+
         dump_surface(surface, 0);
 #endif
     }
@@ -1438,6 +1478,12 @@ static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int
         is_invers = 0;
         break;
 #endif
+#ifdef SW_CANVAS_CACHE
+    case SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS:
+        surface = canvas->bits_cache->ops->get_lossless(canvas->bits_cache, descriptor->id);
+        is_invers = 0;
+        break;
+#endif
     default:
         CANVAS_ERROR("invalid image type");
     }
diff --git a/common/canvas_base.h b/common/canvas_base.h
index 4eaafbb..1bbe465 100644
--- a/common/canvas_base.h
+++ b/common/canvas_base.h
@@ -41,6 +41,16 @@ typedef struct {
                 pixman_image_t *surface);
     pixman_image_t *(*get)(SpiceImageCache *cache,
                            uint64_t id);
+#ifdef SW_CANVAS_CACHE
+    void (*put_lossy)(SpiceImageCache *cache,
+                      uint64_t id,
+                      pixman_image_t *surface);
+    void (*replace_lossy)(SpiceImageCache *cache,
+                          uint64_t id,
+                          pixman_image_t *surface);
+    pixman_image_t *(*get_lossless)(SpiceImageCache *cache,
+                                    uint64_t id);
+#endif
 } SpiceImageCacheOps;
 
 struct _SpiceImageCache {
diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
index 4d1989d..716b812 100644
--- a/server/red_client_shared_cache.h
+++ b/server/red_client_shared_cache.h
@@ -35,7 +35,7 @@
 #endif
 
 
-static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, CHANNEL *channel)
+static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, CHANNEL *channel)
 {
     NewCacheItem *item;
     uint64_t serial;
@@ -51,6 +51,7 @@ static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, CHANNEL *channel)
             ASSERT(channel->base.id < MAX_CACHE_CLIENTS)
             item->sync[channel->base.id] = serial;
             cache->sync[channel->base.id] = serial;
+            *lossy = item->lossy;
             break;
         }
         item = item->next;
@@ -60,7 +61,25 @@ static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, CHANNEL *channel)
     return !!item;
 }
 
-static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, CHANNEL *channel)
+static int FUNC_NAME(set_lossy)(CACHE *cache, uint64_t id, int lossy)
+{
+    NewCacheItem *item;
+    pthread_mutex_lock(&cache->lock);
+
+    item = cache->hash_table[CACHE_HASH_KEY(id)];
+
+    while (item) {
+        if (item->id == id) {
+            item->lossy = lossy;
+            break;
+        }
+        item = item->next;
+   } 
+    pthread_mutex_unlock(&cache->lock);
+    return !!item;
+}
+
+static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, CHANNEL *channel)
 {
     NewCacheItem *item;
     uint64_t serial;
@@ -119,6 +138,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, CHANNEL *cha
     ring_add(&cache->lru, &item->lru_link);
     item->id = id;
     item->size = size;
+    item->lossy = lossy;
     memset(item->sync, 0, sizeof(item->sync));
     item->sync[channel->base.id] = serial;
     cache->sync[channel->base.id] = serial;
diff --git a/server/red_worker.c b/server/red_worker.c
index 89c3deb..55d181d 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -268,6 +268,7 @@ struct NewCacheItem {
     uint64_t id;
     uint64_t sync[MAX_CACHE_CLIENTS];
     size_t size;
+    int lossy;
 };
 
 typedef struct CacheItem CacheItem;
@@ -5969,6 +5970,7 @@ typedef struct compress_send_data_t {
     uint32_t comp_buf_size;
     SPICE_ADDRESS  *plt_ptr;
     uint8_t    *flags_ptr;
+    int is_lossy;
 } compress_send_data_t;
 
 
@@ -6034,6 +6036,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
     o_comp_data->comp_buf_size = size;
     o_comp_data->plt_ptr = NULL;
     o_comp_data->flags_ptr = NULL;
+    o_comp_data->is_lossy = FALSE;
 
     stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y,
                       o_comp_data->comp_buf_size);
@@ -6121,6 +6124,8 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
         o_comp_data->plt_ptr = &(dest->lz_plt.palette);
         o_comp_data->flags_ptr = &(dest->lz_plt.flags);
     }
+
+    o_comp_data->is_lossy = FALSE;
     stat_compress_add(&display_channel->lz_stat, start_time, src->stride * src->y,
                       o_comp_data->comp_buf_size);
     return TRUE;
@@ -6263,6 +6268,7 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, RedImage *de
     o_comp_data->comp_buf_size = size;
     o_comp_data->plt_ptr = NULL;
     o_comp_data->flags_ptr = NULL;
+    o_comp_data->is_lossy = TRUE;
     stat_compress_add(&display_channel->jpeg_stat, start_time, src->stride * src->y,
                       o_comp_data->comp_buf_size);
     return TRUE;
@@ -6409,6 +6415,7 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, RedIm
     o_comp_data->comp_buf_size = size << 2;
     o_comp_data->plt_ptr = NULL;
     o_comp_data->flags_ptr = NULL;
+    o_comp_data->is_lossy = FALSE;
 
     stat_compress_add(&display_channel->quic_stat, start_time, src->stride * src->y,
                       o_comp_data->comp_buf_size);
@@ -6419,6 +6426,7 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, RedIm
 #define MIN_DIMENSION_TO_QUIC 3
 static inline int red_compress_image(DisplayChannel *display_channel,
                                      RedImage *dest, SpiceBitmap *src, Drawable *drawable,
+                                     int can_lossy,
                                      compress_send_data_t* o_comp_data)
 {
     spice_image_compression_t image_compression =
@@ -6472,7 +6480,7 @@ static inline int red_compress_image(DisplayChannel *display_channel,
         red_printf("QUIC compress");
 #endif
         // if bitmaps is picture-like, compress it using jpeg
-        if (display_channel->base.worker->enable_jpeg &&
+        if (can_lossy && display_channel->base.worker->enable_jpeg &&
             ((image_compression == SPICE_IMAGE_COMPRESS_AUTO_LZ) ||
             (image_compression == SPICE_IMAGE_COMPRESS_AUTO_GLZ))) {
             if (src->format != SPICE_BITMAP_FMT_RGBA) {
@@ -6526,15 +6534,18 @@ static inline int red_compress_image(DisplayChannel *display_channel,
 }
 
 static inline void red_display_add_image_to_pixmap_cache(DisplayChannel *display_channel,
-                                                         QXLImage *qxl_image, RedImage *io_image)
+                                                         QXLImage *qxl_image, RedImage *io_image,
+                                                         int is_lossy)
 {
     if ((qxl_image->descriptor.flags & QXL_IMAGE_CACHE)) {
         ASSERT(qxl_image->descriptor.width * qxl_image->descriptor.height > 0);
-        if (pixmap_cache_add(display_channel->pixmap_cache, qxl_image->descriptor.id,
-                             qxl_image->descriptor.width * qxl_image->descriptor.height,
-                             display_channel)) {
-            io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
-            stat_inc_counter(display_channel->add_to_cache_counter, 1);
+        if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME)) {
+            if (pixmap_cache_add(display_channel->pixmap_cache, qxl_image->descriptor.id,
+                                 qxl_image->descriptor.width * qxl_image->descriptor.height, is_lossy,
+                                 display_channel)) {
+                io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
+                stat_inc_counter(display_channel->add_to_cache_counter, 1);
+            }
         }
     }
 
@@ -6545,7 +6556,8 @@ static inline void red_display_add_image_to_pixmap_cache(DisplayChannel *display
 
 /* if the number of times fill_bits can be called per one qxl_drawable increases -
    MAX_LZ_DRAWABLE_INSTANCES must be increased as well */
-static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, Drawable *drawable)
+static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap,
+                      Drawable *drawable, int can_lossy)
 {
     RedChannel *channel = &display_channel->base;
     RedWorker *worker = channel->worker;
@@ -6577,12 +6589,26 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
     memslot_id = get_memslot_id(&worker->mem_slots, *in_bitmap);
     *in_bitmap = channel->send_data.header.size;
     if ((qxl_image->descriptor.flags & QXL_IMAGE_CACHE)) {
+        int lossy_cache_item;
         if (pixmap_cache_hit(display_channel->pixmap_cache, image->descriptor.id,
-                             display_channel)) {
-            image->descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
-            add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceImageDescriptor), 0, 0);
-            stat_inc_counter(display_channel->cache_hits_counter, 1);
-            return;
+                             &lossy_cache_item, display_channel)) {
+            if (can_lossy || !lossy_cache_item) {
+                if (!worker->enable_jpeg || lossy_cache_item) {
+                    image->descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
+                } else {
+                    // making sure, in multiple monitor scenario, that lossy items that
+                    // should have been replaced with lossless data by one display channel,
+                    // will be retrieved as lossless by another display channel.
+                    image->descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS;
+                }
+                add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceImageDescriptor), 0, 0);
+                stat_inc_counter(display_channel->cache_hits_counter, 1);
+                return;
+            } else {
+                pixmap_cache_set_lossy(display_channel->pixmap_cache, qxl_image->descriptor.id,
+                                       FALSE);
+                image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME;
+            }
         }
     }
 
@@ -6612,12 +6638,12 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
            in order to prevent starvation in the client between pixmap_cache and
            global dictionary (in cases of multiple monitors) */
         if (!red_compress_image(display_channel, image, &qxl_image->bitmap,
-                                drawable, &comp_send_data)) {
+                                drawable, can_lossy, &comp_send_data)) {
             uint32_t y;
             uint32_t stride;
             SPICE_ADDRESS image_data;
 
-            red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image);
+            red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image, FALSE);
 
             image->bitmap = qxl_image->bitmap;
             y = image->bitmap.y;
@@ -6638,7 +6664,8 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
                 add_buf(channel, BUF_TYPE_CHUNK, data, y * stride, memslot_id, drawable->group_id);
             }
         } else {
-            red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image);
+            red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image,
+                                                  comp_send_data.is_lossy);
 
             add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, image, comp_send_data.raw_size,
                     0, 0);
@@ -6652,7 +6679,7 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
         }
         break;
     case SPICE_IMAGE_TYPE_QUIC:
-        red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image);
+        red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image, FALSE);
         image->quic = qxl_image->quic;
         add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceQUICImage), 0, 0);
         add_buf(channel, BUF_TYPE_CHUNK, qxl_image->quic.data, qxl_image->quic.data_size,
@@ -6666,7 +6693,7 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
 static void fill_brush(DisplayChannel *display_channel, SpiceBrush *brush, Drawable *drawable)
 {
     if (brush->type == SPICE_BRUSH_TYPE_PATTERN) {
-        fill_bits(display_channel, &brush->u.pattern.pat, drawable);
+        fill_bits(display_channel, &brush->u.pattern.pat, drawable, FALSE);
     }
 }
 
@@ -6677,10 +6704,10 @@ static void fill_mask(DisplayChannel *display_channel, SpiceQMask *mask, Drawabl
             spice_image_compression_t save_img_comp =
                 display_channel->base.worker->image_compression;
             display_channel->base.worker->image_compression = SPICE_IMAGE_COMPRESS_OFF;
-            fill_bits(display_channel, &mask->bitmap, drawable);
+            fill_bits(display_channel, &mask->bitmap, drawable, FALSE);
             display_channel->base.worker->image_compression = save_img_comp;
         } else {
-            fill_bits(display_channel, &mask->bitmap, drawable);
+            fill_bits(display_channel, &mask->bitmap, drawable, FALSE);
         }
     }
 }
@@ -6781,7 +6808,8 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
         fill_base(display_channel, &display_channel->send_data.u.opaque.base, item,
                   sizeof(SpiceMsgDisplayDrawOpaque), item->surface_id);
         display_channel->send_data.u.opaque.data = drawable->u.opaque;
-        fill_bits(display_channel, &display_channel->send_data.u.opaque.data.src_bitmap, item);
+        fill_bits(display_channel, &display_channel->send_data.u.opaque.data.src_bitmap,
+                  item, FALSE);
         fill_brush(display_channel, &display_channel->send_data.u.opaque.data.brush, item);
         fill_mask(display_channel, &display_channel->send_data.u.opaque.data.mask, item);
         break;
@@ -6790,7 +6818,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
         fill_base(display_channel, &display_channel->send_data.u.copy.base, item,
                   sizeof(SpiceMsgDisplayDrawCopy), item->surface_id);
         display_channel->send_data.u.copy.data = drawable->u.copy;
-        fill_bits(display_channel, &display_channel->send_data.u.copy.data.src_bitmap, item);
+        fill_bits(display_channel, &display_channel->send_data.u.copy.data.src_bitmap, item, FALSE);
         fill_mask(display_channel, &display_channel->send_data.u.copy.data.mask, item);
         break;
     case QXL_DRAW_TRANSPARENT:
@@ -6798,14 +6826,16 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
         fill_base(display_channel, &display_channel->send_data.u.transparent.base, item,
                   sizeof(SpiceMsgDisplayDrawTransparent), item->surface_id);
         display_channel->send_data.u.transparent.data = drawable->u.transparent;
-        fill_bits(display_channel, &display_channel->send_data.u.transparent.data.src_bitmap, item);
+        fill_bits(display_channel, &display_channel->send_data.u.transparent.data.src_bitmap,
+                  item, FALSE);
         break;
     case QXL_DRAW_ALPHA_BLEND:
         channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND;
         fill_base(display_channel, &display_channel->send_data.u.alpha_blend.base, item,
                   sizeof(SpiceMsgDisplayDrawAlphaBlend), item->surface_id);
         display_channel->send_data.u.alpha_blend.data = drawable->u.alpha_blend;
-        fill_bits(display_channel, &display_channel->send_data.u.alpha_blend.data.src_bitmap, item);
+        fill_bits(display_channel, &display_channel->send_data.u.alpha_blend.data.src_bitmap,
+                  item, FALSE);
         break;
     case QXL_COPY_BITS:
         channel->send_data.header.type = SPICE_MSG_DISPLAY_COPY_BITS;
@@ -6818,7 +6848,8 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
         fill_base(display_channel, &display_channel->send_data.u.blend.base, item,
                   sizeof(SpiceMsgDisplayDrawBlend), item->surface_id);
         display_channel->send_data.u.blend.data = drawable->u.blend;
-        fill_bits(display_channel, &display_channel->send_data.u.blend.data.src_bitmap, item);
+        fill_bits(display_channel, &display_channel->send_data.u.blend.data.src_bitmap,
+                  item, FALSE);
         fill_mask(display_channel, &display_channel->send_data.u.blend.data.mask, item);
         break;
     case QXL_DRAW_BLACKNESS:
@@ -6847,7 +6878,8 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
         fill_base(display_channel, &display_channel->send_data.u.rop3.base, item,
                   sizeof(SpiceMsgDisplayDrawRop3), item->surface_id);
         display_channel->send_data.u.rop3.data = drawable->u.rop3;
-        fill_bits(display_channel, &display_channel->send_data.u.rop3.data.src_bitmap, item);
+        fill_bits(display_channel, &display_channel->send_data.u.rop3.data.src_bitmap,
+                  item, FALSE);
         fill_brush(display_channel, &display_channel->send_data.u.rop3.data.brush, item);
         fill_mask(display_channel, &display_channel->send_data.u.rop3.data.mask, item);
         break;
@@ -7638,7 +7670,7 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     add_buf(channel, BUF_TYPE_RAW, &item->n_rects, sizeof(uint32_t), 0, 0);
     add_buf(channel, BUF_TYPE_RAW, item->rects, sizeof(SpiceRect) * item->n_rects, 0, 0);
     copy->data = qxl_drawable->u.copy;
-    fill_bits(display_channel, &copy->data.src_bitmap, item->drawable);
+    fill_bits(display_channel, &copy->data.src_bitmap, item->drawable, FALSE);
 
     display_begin_send_massage(display_channel, &item->base);
 }
-- 
1.6.6.1



More information about the Spice-devel mailing list