mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-09 05:51:00 +00:00
support for lossy images in the pixmap cache and fill bits
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
This commit is contained in:
parent
263646a1f7
commit
5d2ae66f50
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
} else if (descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE) {
|
||||
#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
|
||||
#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
|
||||
}
|
||||
@ -1437,6 +1477,12 @@ static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int
|
||||
surface = canvas->bits_cache->ops->get(canvas->bits_cache, descriptor->id);
|
||||
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");
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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, ©->data.src_bitmap, item->drawable);
|
||||
fill_bits(display_channel, ©->data.src_bitmap, item->drawable, FALSE);
|
||||
|
||||
display_begin_send_massage(display_channel, &item->base);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user