mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-26 22:48:19 +00:00
worker: move compress to dcc_compress_image()
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com> Signed-off-by: Frediano Ziglio <fziglio@redhat.com> Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
parent
5229613d51
commit
422d67dde4
631
server/dcc.c
631
server/dcc.c
@ -309,3 +309,634 @@ void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
|
||||
destroy = surface_destroy_item_new(channel, surface_id);
|
||||
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy->pipe_item);
|
||||
}
|
||||
|
||||
/* if already exists, returns it. Otherwise allocates and adds it (1) to the ring tail
|
||||
in the channel (2) to the Drawable*/
|
||||
static RedGlzDrawable *get_glz_drawable(DisplayChannelClient *dcc, Drawable *drawable)
|
||||
{
|
||||
RedGlzDrawable *ret;
|
||||
RingItem *item, *next;
|
||||
|
||||
// TODO - I don't really understand what's going on here, so doing the technical equivalent
|
||||
// now that we have multiple glz_dicts, so the only way to go from dcc to drawable glz is to go
|
||||
// over the glz_ring (unless adding some better data structure then a ring)
|
||||
DRAWABLE_FOREACH_GLZ_SAFE(drawable, item, next, ret) {
|
||||
if (ret->dcc == dcc) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = spice_new(RedGlzDrawable, 1);
|
||||
|
||||
ret->dcc = dcc;
|
||||
ret->red_drawable = red_drawable_ref(drawable->red_drawable);
|
||||
ret->drawable = drawable;
|
||||
ret->group_id = drawable->group_id;
|
||||
ret->instances_count = 0;
|
||||
ring_init(&ret->instances);
|
||||
|
||||
ring_item_init(&ret->link);
|
||||
ring_item_init(&ret->drawable_link);
|
||||
ring_add_before(&ret->link, &dcc->glz_drawables);
|
||||
ring_add(&drawable->glz_ring, &ret->drawable_link);
|
||||
DCC_TO_DC(dcc)->glz_drawable_count++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* allocates new instance and adds it to instances in the given drawable.
|
||||
NOTE - the caller should set the glz_instance returned by the encoder by itself.*/
|
||||
static GlzDrawableInstanceItem *add_glz_drawable_instance(RedGlzDrawable *glz_drawable)
|
||||
{
|
||||
spice_assert(glz_drawable->instances_count < MAX_GLZ_DRAWABLE_INSTANCES);
|
||||
// NOTE: We assume the additions are performed consecutively, without removals in the middle
|
||||
GlzDrawableInstanceItem *ret = glz_drawable->instances_pool + glz_drawable->instances_count;
|
||||
glz_drawable->instances_count++;
|
||||
|
||||
ring_item_init(&ret->free_link);
|
||||
ring_item_init(&ret->glz_link);
|
||||
ring_add(&glz_drawable->instances, &ret->glz_link);
|
||||
ret->context = NULL;
|
||||
ret->glz_drawable = glz_drawable;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MIN_GLZ_SIZE_FOR_ZLIB 100
|
||||
|
||||
int dcc_compress_image_glz(DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
|
||||
compress_send_data_t* o_comp_data)
|
||||
{
|
||||
DisplayChannel *display_channel = DCC_TO_DC(dcc);
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(display_channel->glz_stat.clock);
|
||||
#endif
|
||||
spice_assert(bitmap_fmt_is_rgb(src->format));
|
||||
GlzData *glz_data = &dcc->glz_data;
|
||||
ZlibData *zlib_data;
|
||||
LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
|
||||
RedGlzDrawable *glz_drawable;
|
||||
GlzDrawableInstanceItem *glz_drawable_instance;
|
||||
int glz_size;
|
||||
int zlib_size;
|
||||
|
||||
glz_data->data.bufs_tail = compress_buf_new();
|
||||
glz_data->data.bufs_head = glz_data->data.bufs_tail;
|
||||
glz_data->data.dcc = dcc;
|
||||
|
||||
glz_drawable = get_glz_drawable(dcc, drawable);
|
||||
glz_drawable_instance = add_glz_drawable_instance(glz_drawable);
|
||||
|
||||
glz_data->data.u.lines_data.chunks = src->data;
|
||||
glz_data->data.u.lines_data.stride = src->stride;
|
||||
glz_data->data.u.lines_data.next = 0;
|
||||
glz_data->data.u.lines_data.reverse = 0;
|
||||
|
||||
glz_size = glz_encode(dcc->glz, type, src->x, src->y,
|
||||
(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), NULL, 0,
|
||||
src->stride, glz_data->data.bufs_head->buf.bytes,
|
||||
sizeof(glz_data->data.bufs_head->buf),
|
||||
glz_drawable_instance,
|
||||
&glz_drawable_instance->context);
|
||||
|
||||
stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y, glz_size);
|
||||
|
||||
if (!display_channel->enable_zlib_glz_wrap || (glz_size < MIN_GLZ_SIZE_FOR_ZLIB)) {
|
||||
goto glz;
|
||||
}
|
||||
#ifdef COMPRESS_STAT
|
||||
start_time = stat_now(display_channel->zlib_glz_stat.clock);
|
||||
#endif
|
||||
zlib_data = &dcc->zlib_data;
|
||||
|
||||
zlib_data->data.bufs_tail = compress_buf_new();
|
||||
zlib_data->data.bufs_head = zlib_data->data.bufs_tail;
|
||||
zlib_data->data.dcc = dcc;
|
||||
|
||||
zlib_data->data.u.compressed_data.next = glz_data->data.bufs_head;
|
||||
zlib_data->data.u.compressed_data.size_left = glz_size;
|
||||
|
||||
zlib_size = zlib_encode(dcc->zlib, dcc->zlib_level,
|
||||
glz_size, zlib_data->data.bufs_head->buf.bytes,
|
||||
sizeof(zlib_data->data.bufs_head->buf));
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if (zlib_size >= glz_size) {
|
||||
while (zlib_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = zlib_data->data.bufs_head;
|
||||
zlib_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
goto glz;
|
||||
}
|
||||
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB;
|
||||
dest->u.zlib_glz.glz_data_size = glz_size;
|
||||
dest->u.zlib_glz.data_size = zlib_size;
|
||||
|
||||
o_comp_data->comp_buf = zlib_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = zlib_size;
|
||||
|
||||
stat_compress_add(&display_channel->zlib_glz_stat, start_time, glz_size, zlib_size);
|
||||
return TRUE;
|
||||
glz:
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_GLZ_RGB;
|
||||
dest->u.lz_rgb.data_size = glz_size;
|
||||
|
||||
o_comp_data->comp_buf = glz_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = glz_size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int dcc_compress_image_lz(DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src,
|
||||
compress_send_data_t* o_comp_data, uint32_t group_id)
|
||||
{
|
||||
LzData *lz_data = &dcc->lz_data;
|
||||
LzContext *lz = dcc->lz;
|
||||
LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
|
||||
int size; // size of the compressed data
|
||||
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->lz_stat.clock);
|
||||
#endif
|
||||
|
||||
lz_data->data.bufs_tail = compress_buf_new();
|
||||
lz_data->data.bufs_head = lz_data->data.bufs_tail;
|
||||
lz_data->data.dcc = dcc;
|
||||
|
||||
if (setjmp(lz_data->data.jmp_env)) {
|
||||
while (lz_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = lz_data->data.bufs_head;
|
||||
lz_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lz_data->data.u.lines_data.chunks = src->data;
|
||||
lz_data->data.u.lines_data.stride = src->stride;
|
||||
lz_data->data.u.lines_data.next = 0;
|
||||
lz_data->data.u.lines_data.reverse = 0;
|
||||
|
||||
size = lz_encode(lz, type, src->x, src->y,
|
||||
!!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN),
|
||||
NULL, 0, src->stride,
|
||||
lz_data->data.bufs_head->buf.bytes,
|
||||
sizeof(lz_data->data.bufs_head->buf));
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if (size > (src->y * src->stride)) {
|
||||
longjmp(lz_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
if (bitmap_fmt_is_rgb(src->format)) {
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_RGB;
|
||||
dest->u.lz_rgb.data_size = size;
|
||||
|
||||
o_comp_data->comp_buf = lz_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = size;
|
||||
} else {
|
||||
/* masks are 1BIT bitmaps without palettes, but they are not compressed
|
||||
* (see fill_mask) */
|
||||
spice_assert(src->palette);
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_PLT;
|
||||
dest->u.lz_plt.data_size = size;
|
||||
dest->u.lz_plt.flags = src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
|
||||
dest->u.lz_plt.palette = src->palette;
|
||||
dest->u.lz_plt.palette_id = src->palette->unique;
|
||||
o_comp_data->comp_buf = lz_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = size;
|
||||
|
||||
dcc_palette_cache_palette(dcc, dest->u.lz_plt.palette, &(dest->u.lz_plt.flags));
|
||||
o_comp_data->lzplt_palette = dest->u.lz_plt.palette;
|
||||
}
|
||||
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->lz_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int dcc_compress_image_jpeg(DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id)
|
||||
{
|
||||
JpegData *jpeg_data = &dcc->jpeg_data;
|
||||
LzData *lz_data = &dcc->lz_data;
|
||||
JpegEncoderContext *jpeg = dcc->jpeg;
|
||||
LzContext *lz = dcc->lz;
|
||||
volatile JpegEncoderImageType jpeg_in_type;
|
||||
int jpeg_size = 0;
|
||||
volatile int has_alpha = FALSE;
|
||||
int alpha_lz_size = 0;
|
||||
int comp_head_filled;
|
||||
int comp_head_left;
|
||||
int stride;
|
||||
uint8_t *lz_out_start_byte;
|
||||
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->jpeg_stat.clock);
|
||||
#endif
|
||||
switch (src->format) {
|
||||
case SPICE_BITMAP_FMT_16BIT:
|
||||
jpeg_in_type = JPEG_IMAGE_TYPE_RGB16;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_24BIT:
|
||||
jpeg_in_type = JPEG_IMAGE_TYPE_BGR24;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_32BIT:
|
||||
jpeg_in_type = JPEG_IMAGE_TYPE_BGRX32;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_RGBA:
|
||||
jpeg_in_type = JPEG_IMAGE_TYPE_BGRX32;
|
||||
has_alpha = TRUE;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
jpeg_data->data.bufs_tail = compress_buf_new();
|
||||
jpeg_data->data.bufs_head = jpeg_data->data.bufs_tail;
|
||||
jpeg_data->data.dcc = dcc;
|
||||
|
||||
if (setjmp(jpeg_data->data.jmp_env)) {
|
||||
while (jpeg_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = jpeg_data->data.bufs_head;
|
||||
jpeg_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
|
||||
spice_chunks_linearize(src->data);
|
||||
}
|
||||
|
||||
jpeg_data->data.u.lines_data.chunks = src->data;
|
||||
jpeg_data->data.u.lines_data.stride = src->stride;
|
||||
if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
||||
jpeg_data->data.u.lines_data.next = 0;
|
||||
jpeg_data->data.u.lines_data.reverse = 0;
|
||||
stride = src->stride;
|
||||
} else {
|
||||
jpeg_data->data.u.lines_data.next = src->data->num_chunks - 1;
|
||||
jpeg_data->data.u.lines_data.reverse = 1;
|
||||
stride = -src->stride;
|
||||
}
|
||||
jpeg_size = jpeg_encode(jpeg, dcc->jpeg_quality, jpeg_in_type,
|
||||
src->x, src->y, NULL,
|
||||
0, stride, jpeg_data->data.bufs_head->buf.bytes,
|
||||
sizeof(jpeg_data->data.bufs_head->buf));
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if (jpeg_size > (src->y * src->stride)) {
|
||||
longjmp(jpeg_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
if (!has_alpha) {
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG;
|
||||
dest->u.jpeg.data_size = jpeg_size;
|
||||
|
||||
o_comp_data->comp_buf = jpeg_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = jpeg_size;
|
||||
o_comp_data->is_lossy = TRUE;
|
||||
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->jpeg_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
lz_data->data.bufs_head = jpeg_data->data.bufs_tail;
|
||||
lz_data->data.bufs_tail = lz_data->data.bufs_head;
|
||||
|
||||
comp_head_filled = jpeg_size % sizeof(lz_data->data.bufs_head->buf);
|
||||
comp_head_left = sizeof(lz_data->data.bufs_head->buf) - comp_head_filled;
|
||||
lz_out_start_byte = lz_data->data.bufs_head->buf.bytes + comp_head_filled;
|
||||
|
||||
lz_data->data.dcc = dcc;
|
||||
|
||||
lz_data->data.u.lines_data.chunks = src->data;
|
||||
lz_data->data.u.lines_data.stride = src->stride;
|
||||
lz_data->data.u.lines_data.next = 0;
|
||||
lz_data->data.u.lines_data.reverse = 0;
|
||||
|
||||
alpha_lz_size = lz_encode(lz, LZ_IMAGE_TYPE_XXXA, src->x, src->y,
|
||||
!!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN),
|
||||
NULL, 0, src->stride,
|
||||
lz_out_start_byte,
|
||||
comp_head_left);
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if ((jpeg_size + alpha_lz_size) > (src->y * src->stride)) {
|
||||
longjmp(jpeg_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG_ALPHA;
|
||||
dest->u.jpeg_alpha.flags = 0;
|
||||
if (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN) {
|
||||
dest->u.jpeg_alpha.flags |= SPICE_JPEG_ALPHA_FLAGS_TOP_DOWN;
|
||||
}
|
||||
|
||||
dest->u.jpeg_alpha.jpeg_size = jpeg_size;
|
||||
dest->u.jpeg_alpha.data_size = jpeg_size + alpha_lz_size;
|
||||
|
||||
o_comp_data->comp_buf = jpeg_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = jpeg_size + alpha_lz_size;
|
||||
o_comp_data->is_lossy = TRUE;
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->jpeg_alpha_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef USE_LZ4
|
||||
int dcc_compress_image_lz4(DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id)
|
||||
{
|
||||
DisplayChannel *display_channel = DCC_TO_DC(dcc);
|
||||
Lz4Data *lz4_data = &dcc->lz4_data;
|
||||
Lz4EncoderContext *lz4 = dcc->lz4;
|
||||
int lz4_size = 0;
|
||||
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(display_channel->lz4_stat.clock);
|
||||
#endif
|
||||
|
||||
lz4_data->data.bufs_tail = compress_buf_new();
|
||||
lz4_data->data.bufs_head = lz4_data->data.bufs_tail;
|
||||
|
||||
if (!lz4_data->data.bufs_head) {
|
||||
spice_warning("failed to allocate compress buffer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lz4_data->data.bufs_head->send_next = NULL;
|
||||
lz4_data->data.dcc = dcc;
|
||||
|
||||
if (setjmp(lz4_data->data.jmp_env)) {
|
||||
while (lz4_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = lz4_data->data.bufs_head;
|
||||
lz4_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
|
||||
spice_chunks_linearize(src->data);
|
||||
}
|
||||
|
||||
lz4_data->data.u.lines_data.chunks = src->data;
|
||||
lz4_data->data.u.lines_data.stride = src->stride;
|
||||
lz4_data->data.u.lines_data.next = 0;
|
||||
lz4_data->data.u.lines_data.reverse = 0;
|
||||
|
||||
lz4_size = lz4_encode(lz4, src->y, src->stride, lz4_data->data.bufs_head->buf.bytes,
|
||||
sizeof(lz4_data->data.bufs_head->buf),
|
||||
src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN, src->format);
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if (lz4_size > (src->y * src->stride)) {
|
||||
longjmp(lz4_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_LZ4;
|
||||
dest->u.lz4.data_size = lz4_size;
|
||||
|
||||
o_comp_data->comp_buf = lz4_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = lz4_size;
|
||||
|
||||
stat_compress_add(&display_channel->lz4_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
int dcc_compress_image_quic(DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id)
|
||||
{
|
||||
QuicData *quic_data = &dcc->quic_data;
|
||||
QuicContext *quic = dcc->quic;
|
||||
volatile QuicImageType type;
|
||||
int size, stride;
|
||||
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->quic_stat.clock);
|
||||
#endif
|
||||
|
||||
switch (src->format) {
|
||||
case SPICE_BITMAP_FMT_32BIT:
|
||||
type = QUIC_IMAGE_TYPE_RGB32;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_RGBA:
|
||||
type = QUIC_IMAGE_TYPE_RGBA;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_16BIT:
|
||||
type = QUIC_IMAGE_TYPE_RGB16;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_24BIT:
|
||||
type = QUIC_IMAGE_TYPE_RGB24;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
quic_data->data.bufs_tail = compress_buf_new();
|
||||
quic_data->data.bufs_head = quic_data->data.bufs_tail;
|
||||
quic_data->data.dcc = dcc;
|
||||
|
||||
if (setjmp(quic_data->data.jmp_env)) {
|
||||
while (quic_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = quic_data->data.bufs_head;
|
||||
quic_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
|
||||
spice_chunks_linearize(src->data);
|
||||
}
|
||||
|
||||
quic_data->data.u.lines_data.chunks = src->data;
|
||||
quic_data->data.u.lines_data.stride = src->stride;
|
||||
if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
||||
quic_data->data.u.lines_data.next = 0;
|
||||
quic_data->data.u.lines_data.reverse = 0;
|
||||
stride = src->stride;
|
||||
} else {
|
||||
quic_data->data.u.lines_data.next = src->data->num_chunks - 1;
|
||||
quic_data->data.u.lines_data.reverse = 1;
|
||||
stride = -src->stride;
|
||||
}
|
||||
size = quic_encode(quic, type, src->x, src->y, NULL, 0, stride,
|
||||
quic_data->data.bufs_head->buf.words,
|
||||
G_N_ELEMENTS(quic_data->data.bufs_head->buf.words));
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if ((size << 2) > (src->y * src->stride)) {
|
||||
longjmp(quic_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_QUIC;
|
||||
dest->u.quic.data_size = size << 2;
|
||||
|
||||
o_comp_data->comp_buf = quic_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = size << 2;
|
||||
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->quic_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define MIN_SIZE_TO_COMPRESS 54
|
||||
#define MIN_DIMENSION_TO_QUIC 3
|
||||
int dcc_compress_image(DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
|
||||
int can_lossy,
|
||||
compress_send_data_t* o_comp_data)
|
||||
{
|
||||
DisplayChannel *display_channel = DCC_TO_DC(dcc);
|
||||
SpiceImageCompression image_compression = dcc->image_compression;
|
||||
int quic_compress = FALSE;
|
||||
|
||||
if ((image_compression == SPICE_IMAGE_COMPRESSION_OFF) ||
|
||||
((src->y * src->stride) < MIN_SIZE_TO_COMPRESS)) { // TODO: change the size cond
|
||||
return FALSE;
|
||||
} else if (image_compression == SPICE_IMAGE_COMPRESSION_QUIC) {
|
||||
if (bitmap_fmt_is_plt(src->format)) {
|
||||
return FALSE;
|
||||
} else {
|
||||
quic_compress = TRUE;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
lz doesn't handle (1) bitmaps with strides that are larger than the width
|
||||
of the image in bytes (2) unstable bitmaps
|
||||
*/
|
||||
if (bitmap_has_extra_stride(src) || (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE)) {
|
||||
if ((image_compression == SPICE_IMAGE_COMPRESSION_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_GLZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_LZ4) ||
|
||||
bitmap_fmt_is_plt(src->format)) {
|
||||
return FALSE;
|
||||
} else {
|
||||
quic_compress = TRUE;
|
||||
}
|
||||
} else {
|
||||
if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ)) {
|
||||
if ((src->x < MIN_DIMENSION_TO_QUIC) || (src->y < MIN_DIMENSION_TO_QUIC)) {
|
||||
quic_compress = FALSE;
|
||||
} else {
|
||||
if (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_INVALID) {
|
||||
quic_compress = bitmap_fmt_has_graduality(src->format) &&
|
||||
bitmap_get_graduality_level(src) == BITMAP_GRADUAL_HIGH;
|
||||
} else {
|
||||
quic_compress = (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_HIGH);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quic_compress = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (quic_compress) {
|
||||
#ifdef COMPRESS_DEBUG
|
||||
spice_info("QUIC compress");
|
||||
#endif
|
||||
// if bitmaps is picture-like, compress it using jpeg
|
||||
if (can_lossy && display_channel->enable_jpeg &&
|
||||
((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ))) {
|
||||
// if we use lz for alpha, the stride can't be extra
|
||||
if (src->format != SPICE_BITMAP_FMT_RGBA || !bitmap_has_extra_stride(src)) {
|
||||
return dcc_compress_image_jpeg(dcc, dest,
|
||||
src, o_comp_data, drawable->group_id);
|
||||
}
|
||||
}
|
||||
return dcc_compress_image_quic(dcc, dest,
|
||||
src, o_comp_data, drawable->group_id);
|
||||
} else {
|
||||
int glz;
|
||||
int ret;
|
||||
if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_GLZ)) {
|
||||
glz = bitmap_fmt_has_graduality(src->format) && (
|
||||
(src->x * src->y) < glz_enc_dictionary_get_size(
|
||||
dcc->glz_dict->dict));
|
||||
} else if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_LZ4)) {
|
||||
glz = FALSE;
|
||||
} else {
|
||||
spice_error("invalid image compression type %u", image_compression);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (glz) {
|
||||
/* using the global dictionary only if it is not frozen */
|
||||
pthread_rwlock_rdlock(&dcc->glz_dict->encode_lock);
|
||||
if (!dcc->glz_dict->migrate_freeze) {
|
||||
ret = dcc_compress_image_glz(dcc,
|
||||
dest, src,
|
||||
drawable, o_comp_data);
|
||||
} else {
|
||||
glz = FALSE;
|
||||
}
|
||||
pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
|
||||
}
|
||||
|
||||
if (!glz) {
|
||||
#ifdef USE_LZ4
|
||||
if (image_compression == SPICE_IMAGE_COMPRESSION_LZ4 &&
|
||||
bitmap_fmt_is_rgb(src->format) &&
|
||||
red_channel_client_test_remote_cap(&dcc->common.base,
|
||||
SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) {
|
||||
ret = dcc_compress_image_lz4(dcc, dest, src, o_comp_data,
|
||||
drawable->group_id);
|
||||
} else
|
||||
#endif
|
||||
ret = dcc_compress_image_lz(dcc, dest, src, o_comp_data,
|
||||
drawable->group_id);
|
||||
#ifdef COMPRESS_DEBUG
|
||||
spice_info("LZ LOCAL compress");
|
||||
#endif
|
||||
}
|
||||
#ifdef COMPRESS_DEBUG
|
||||
else {
|
||||
spice_info("LZ global compress fmt=%d", src->format);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#define CLIENT_PALETTE_CACHE
|
||||
#include "cache_item.tmpl.c"
|
||||
#undef CLIENT_PALETTE_CACHE
|
||||
|
||||
void dcc_palette_cache_palette(DisplayChannelClient *dcc, SpicePalette *palette,
|
||||
uint8_t *flags)
|
||||
{
|
||||
if (palette == NULL) {
|
||||
return;
|
||||
}
|
||||
if (palette->unique) {
|
||||
if (red_palette_cache_find(dcc, palette->unique)) {
|
||||
*flags |= SPICE_BITMAP_FLAGS_PAL_FROM_CACHE;
|
||||
return;
|
||||
}
|
||||
if (red_palette_cache_add(dcc, palette->unique, 1)) {
|
||||
*flags |= SPICE_BITMAP_FLAGS_PAL_CACHE_ME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dcc_palette_cache_reset(DisplayChannelClient *dcc)
|
||||
{
|
||||
red_palette_cache_reset(dcc, CLIENT_PALETTE_CACHE_SIZE);
|
||||
}
|
||||
|
||||
31
server/dcc.h
31
server/dcc.h
@ -163,5 +163,36 @@ ImageItem * dcc_add_surface_area_image (DisplayCha
|
||||
SpiceRect *area,
|
||||
PipeItem *pos,
|
||||
int can_lossy);
|
||||
void dcc_palette_cache_reset (DisplayChannelClient *dcc);
|
||||
void dcc_palette_cache_palette (DisplayChannelClient *dcc,
|
||||
SpicePalette *palette,
|
||||
uint8_t *flags);
|
||||
|
||||
typedef struct compress_send_data_t {
|
||||
void* comp_buf;
|
||||
uint32_t comp_buf_size;
|
||||
SpicePalette *lzplt_palette;
|
||||
int is_lossy;
|
||||
} compress_send_data_t;
|
||||
|
||||
int dcc_compress_image (DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
|
||||
int can_lossy,
|
||||
compress_send_data_t* o_comp_data);
|
||||
int dcc_compress_image_glz (DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
|
||||
compress_send_data_t* o_comp_data);
|
||||
int dcc_compress_image_lz (DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src,
|
||||
compress_send_data_t* o_comp_data, uint32_t group_id);
|
||||
int dcc_compress_image_jpeg (DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id);
|
||||
int dcc_compress_image_quic (DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id);
|
||||
int dcc_compress_image_lz4 (DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id);
|
||||
|
||||
#endif /* DCC_H_ */
|
||||
|
||||
@ -91,6 +91,10 @@ struct Drawable {
|
||||
#define DRAWABLE_FOREACH_DPI_SAFE(drawable, link, next, dpi) \
|
||||
SAFE_FOREACH(link, next, drawable, &(drawable)->pipes, dpi, LINK_TO_DPI(link))
|
||||
|
||||
#define LINK_TO_GLZ(ptr) SPICE_CONTAINEROF((ptr), RedGlzDrawable, \
|
||||
drawable_link)
|
||||
#define DRAWABLE_FOREACH_GLZ_SAFE(drawable, link, next, glz) \
|
||||
SAFE_FOREACH(link, next, drawable, &(drawable)->glz_ring, glz, LINK_TO_GLZ(link))
|
||||
|
||||
enum {
|
||||
PIPE_ITEM_TYPE_DRAW = PIPE_ITEM_TYPE_COMMON_LAST,
|
||||
|
||||
@ -57,6 +57,12 @@ typedef struct RedDrawable {
|
||||
} u;
|
||||
} RedDrawable;
|
||||
|
||||
static inline RedDrawable *red_drawable_ref(RedDrawable *drawable)
|
||||
{
|
||||
drawable->refs++;
|
||||
return drawable;
|
||||
}
|
||||
|
||||
typedef struct RedUpdateCmd {
|
||||
QXLReleaseInfo *release_info;
|
||||
SpiceRect area;
|
||||
|
||||
@ -73,12 +73,6 @@
|
||||
#define CMD_RING_POLL_RETRIES 200
|
||||
|
||||
#define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano
|
||||
#define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
|
||||
#define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
|
||||
|
||||
#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
|
||||
|
||||
#define MIN_GLZ_SIZE_FOR_ZLIB 100
|
||||
|
||||
#define VALIDATE_SURFACE_RET(worker, surface_id) \
|
||||
if (!validate_surface(worker, surface_id)) { \
|
||||
@ -202,13 +196,6 @@ static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uin
|
||||
uint32_t height, int32_t stride, uint32_t format,
|
||||
void *line_0, int data_is_valid, int send_client);
|
||||
|
||||
|
||||
#define LINK_TO_GLZ(ptr) SPICE_CONTAINEROF((ptr), RedGlzDrawable, \
|
||||
drawable_link)
|
||||
#define DRAWABLE_FOREACH_GLZ_SAFE(drawable, link, next, glz) \
|
||||
SAFE_FOREACH(link, next, drawable, &(drawable)->glz_ring, glz, LINK_TO_GLZ(link))
|
||||
|
||||
|
||||
static void display_stream_clip_unref(DisplayChannel *display, StreamClipItem *item)
|
||||
{
|
||||
if (--item->refs != 0)
|
||||
@ -545,14 +532,6 @@ static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32
|
||||
}
|
||||
}
|
||||
|
||||
#define CLIENT_PALETTE_CACHE
|
||||
#include "cache_item.tmpl.c"
|
||||
#undef CLIENT_PALETTE_CACHE
|
||||
|
||||
static void red_reset_palette_cache(DisplayChannelClient *dcc)
|
||||
{
|
||||
red_palette_cache_reset(dcc, CLIENT_PALETTE_CACHE_SIZE);
|
||||
}
|
||||
|
||||
static Drawable* drawable_try_new(DisplayChannel *display)
|
||||
{
|
||||
@ -592,13 +571,6 @@ static inline void set_surface_release_info(QXLReleaseInfoExt *release_info_ext,
|
||||
release_info_ext->group_id = group_id;
|
||||
}
|
||||
|
||||
static RedDrawable *red_drawable_ref(RedDrawable *drawable)
|
||||
{
|
||||
drawable->refs++;
|
||||
return drawable;
|
||||
}
|
||||
|
||||
|
||||
static void red_drawable_unref(RedWorker *worker, RedDrawable *red_drawable,
|
||||
uint32_t group_id)
|
||||
{
|
||||
@ -2032,79 +2004,6 @@ static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
|
||||
spice_marshall_DisplayBase(base_marshaller, &base);
|
||||
}
|
||||
|
||||
static inline void fill_palette(DisplayChannelClient *dcc,
|
||||
SpicePalette *palette,
|
||||
uint8_t *flags)
|
||||
{
|
||||
if (palette == NULL) {
|
||||
return;
|
||||
}
|
||||
if (palette->unique) {
|
||||
if (red_palette_cache_find(dcc, palette->unique)) {
|
||||
*flags |= SPICE_BITMAP_FLAGS_PAL_FROM_CACHE;
|
||||
return;
|
||||
}
|
||||
if (red_palette_cache_add(dcc, palette->unique, 1)) {
|
||||
*flags |= SPICE_BITMAP_FLAGS_PAL_CACHE_ME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* Global lz red drawables routines
|
||||
*******************************************************/
|
||||
|
||||
/* if already exists, returns it. Otherwise allocates and adds it (1) to the ring tail
|
||||
in the channel (2) to the Drawable*/
|
||||
static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannelClient *dcc, Drawable *drawable)
|
||||
{
|
||||
RedGlzDrawable *ret;
|
||||
RingItem *item, *next;
|
||||
|
||||
// TODO - I don't really understand what's going on here, so doing the technical equivalent
|
||||
// now that we have multiple glz_dicts, so the only way to go from dcc to drawable glz is to go
|
||||
// over the glz_ring (unless adding some better data structure then a ring)
|
||||
DRAWABLE_FOREACH_GLZ_SAFE(drawable, item, next, ret) {
|
||||
if (ret->dcc == dcc) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = spice_new(RedGlzDrawable, 1);
|
||||
|
||||
ret->dcc = dcc;
|
||||
ret->red_drawable = red_drawable_ref(drawable->red_drawable);
|
||||
ret->drawable = drawable;
|
||||
ret->group_id = drawable->group_id;
|
||||
ret->instances_count = 0;
|
||||
ring_init(&ret->instances);
|
||||
|
||||
ring_item_init(&ret->link);
|
||||
ring_item_init(&ret->drawable_link);
|
||||
ring_add_before(&ret->link, &dcc->glz_drawables);
|
||||
ring_add(&drawable->glz_ring, &ret->drawable_link);
|
||||
DCC_TO_DC(dcc)->glz_drawable_count++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* allocates new instance and adds it to instances in the given drawable.
|
||||
NOTE - the caller should set the glz_instance returned by the encoder by itself.*/
|
||||
static GlzDrawableInstanceItem *red_display_add_glz_drawable_instance(RedGlzDrawable *glz_drawable)
|
||||
{
|
||||
spice_assert(glz_drawable->instances_count < MAX_GLZ_DRAWABLE_INSTANCES);
|
||||
// NOTE: We assume the additions are performed consecutively, without removals in the middle
|
||||
GlzDrawableInstanceItem *ret = glz_drawable->instances_pool + glz_drawable->instances_count;
|
||||
glz_drawable->instances_count++;
|
||||
|
||||
ring_item_init(&ret->free_link);
|
||||
ring_item_init(&ret->glz_link);
|
||||
ring_add(&glz_drawable->instances, &ret->glz_link);
|
||||
ret->context = NULL;
|
||||
ret->glz_drawable = glz_drawable;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Remove from the to_free list and the instances_list.
|
||||
When no instance is left - the RedGlzDrawable is released too. (and the qxl drawable too, if
|
||||
it is not used by Drawable).
|
||||
@ -2261,565 +2160,6 @@ static int red_display_free_some_independent_glz_drawables(DisplayChannelClient
|
||||
return n;
|
||||
}
|
||||
|
||||
typedef struct compress_send_data_t {
|
||||
void* comp_buf;
|
||||
uint32_t comp_buf_size;
|
||||
SpicePalette *lzplt_palette;
|
||||
int is_lossy;
|
||||
} compress_send_data_t;
|
||||
|
||||
static inline int red_glz_compress_image(DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
|
||||
compress_send_data_t* o_comp_data)
|
||||
{
|
||||
DisplayChannel *display_channel = DCC_TO_DC(dcc);
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(display_channel->zlib_glz_stat.clock);
|
||||
#endif
|
||||
spice_assert(bitmap_fmt_is_rgb(src->format));
|
||||
GlzData *glz_data = &dcc->glz_data;
|
||||
ZlibData *zlib_data;
|
||||
LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
|
||||
RedGlzDrawable *glz_drawable;
|
||||
GlzDrawableInstanceItem *glz_drawable_instance;
|
||||
int glz_size;
|
||||
int zlib_size;
|
||||
|
||||
glz_data->data.bufs_tail = compress_buf_new();
|
||||
glz_data->data.bufs_head = glz_data->data.bufs_tail;
|
||||
glz_data->data.dcc = dcc;
|
||||
|
||||
glz_drawable = red_display_get_glz_drawable(dcc, drawable);
|
||||
glz_drawable_instance = red_display_add_glz_drawable_instance(glz_drawable);
|
||||
|
||||
glz_data->data.u.lines_data.chunks = src->data;
|
||||
glz_data->data.u.lines_data.stride = src->stride;
|
||||
glz_data->data.u.lines_data.next = 0;
|
||||
glz_data->data.u.lines_data.reverse = 0;
|
||||
|
||||
glz_size = glz_encode(dcc->glz, type, src->x, src->y,
|
||||
(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), NULL, 0,
|
||||
src->stride, glz_data->data.bufs_head->buf.bytes,
|
||||
sizeof(glz_data->data.bufs_head->buf),
|
||||
glz_drawable_instance,
|
||||
&glz_drawable_instance->context);
|
||||
|
||||
stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y, glz_size);
|
||||
|
||||
if (!display_channel->enable_zlib_glz_wrap || (glz_size < MIN_GLZ_SIZE_FOR_ZLIB)) {
|
||||
goto glz;
|
||||
}
|
||||
#ifdef COMPRESS_STAT
|
||||
start_time = stat_now(display_channel->zlib_glz_stat.clock);
|
||||
#endif
|
||||
zlib_data = &dcc->zlib_data;
|
||||
|
||||
zlib_data->data.bufs_tail = compress_buf_new();
|
||||
zlib_data->data.bufs_head = zlib_data->data.bufs_tail;
|
||||
zlib_data->data.dcc = dcc;
|
||||
|
||||
zlib_data->data.u.compressed_data.next = glz_data->data.bufs_head;
|
||||
zlib_data->data.u.compressed_data.size_left = glz_size;
|
||||
|
||||
zlib_size = zlib_encode(dcc->zlib, dcc->zlib_level,
|
||||
glz_size, zlib_data->data.bufs_head->buf.bytes,
|
||||
sizeof(zlib_data->data.bufs_head->buf));
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if (zlib_size >= glz_size) {
|
||||
while (zlib_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = zlib_data->data.bufs_head;
|
||||
zlib_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
goto glz;
|
||||
}
|
||||
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB;
|
||||
dest->u.zlib_glz.glz_data_size = glz_size;
|
||||
dest->u.zlib_glz.data_size = zlib_size;
|
||||
|
||||
o_comp_data->comp_buf = zlib_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = zlib_size;
|
||||
|
||||
stat_compress_add(&display_channel->zlib_glz_stat, start_time, glz_size, zlib_size);
|
||||
return TRUE;
|
||||
glz:
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_GLZ_RGB;
|
||||
dest->u.lz_rgb.data_size = glz_size;
|
||||
|
||||
o_comp_data->comp_buf = glz_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = glz_size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline int red_lz_compress_image(DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src,
|
||||
compress_send_data_t* o_comp_data, uint32_t group_id)
|
||||
{
|
||||
LzData *lz_data = &dcc->lz_data;
|
||||
LzContext *lz = dcc->lz;
|
||||
LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
|
||||
int size; // size of the compressed data
|
||||
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->lz_stat.clock);
|
||||
#endif
|
||||
|
||||
lz_data->data.bufs_tail = compress_buf_new();
|
||||
lz_data->data.bufs_head = lz_data->data.bufs_tail;
|
||||
lz_data->data.dcc = dcc;
|
||||
|
||||
if (setjmp(lz_data->data.jmp_env)) {
|
||||
while (lz_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = lz_data->data.bufs_head;
|
||||
lz_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lz_data->data.u.lines_data.chunks = src->data;
|
||||
lz_data->data.u.lines_data.stride = src->stride;
|
||||
lz_data->data.u.lines_data.next = 0;
|
||||
lz_data->data.u.lines_data.reverse = 0;
|
||||
|
||||
size = lz_encode(lz, type, src->x, src->y,
|
||||
!!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN),
|
||||
NULL, 0, src->stride,
|
||||
lz_data->data.bufs_head->buf.bytes,
|
||||
sizeof(lz_data->data.bufs_head->buf));
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if (size > (src->y * src->stride)) {
|
||||
longjmp(lz_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
if (bitmap_fmt_is_rgb(src->format)) {
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_RGB;
|
||||
dest->u.lz_rgb.data_size = size;
|
||||
|
||||
o_comp_data->comp_buf = lz_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = size;
|
||||
} else {
|
||||
/* masks are 1BIT bitmaps without palettes, but they are not compressed
|
||||
* (see fill_mask) */
|
||||
spice_assert(src->palette);
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_PLT;
|
||||
dest->u.lz_plt.data_size = size;
|
||||
dest->u.lz_plt.flags = src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
|
||||
dest->u.lz_plt.palette = src->palette;
|
||||
dest->u.lz_plt.palette_id = src->palette->unique;
|
||||
o_comp_data->comp_buf = lz_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = size;
|
||||
|
||||
fill_palette(dcc, dest->u.lz_plt.palette, &(dest->u.lz_plt.flags));
|
||||
o_comp_data->lzplt_palette = dest->u.lz_plt.palette;
|
||||
}
|
||||
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->lz_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int red_jpeg_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id)
|
||||
{
|
||||
JpegData *jpeg_data = &dcc->jpeg_data;
|
||||
LzData *lz_data = &dcc->lz_data;
|
||||
JpegEncoderContext *jpeg = dcc->jpeg;
|
||||
LzContext *lz = dcc->lz;
|
||||
volatile JpegEncoderImageType jpeg_in_type;
|
||||
int jpeg_size = 0;
|
||||
volatile int has_alpha = FALSE;
|
||||
int alpha_lz_size = 0;
|
||||
int comp_head_filled;
|
||||
int comp_head_left;
|
||||
int stride;
|
||||
uint8_t *lz_out_start_byte;
|
||||
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->jpeg_alpha_stat.clock);
|
||||
#endif
|
||||
switch (src->format) {
|
||||
case SPICE_BITMAP_FMT_16BIT:
|
||||
jpeg_in_type = JPEG_IMAGE_TYPE_RGB16;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_24BIT:
|
||||
jpeg_in_type = JPEG_IMAGE_TYPE_BGR24;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_32BIT:
|
||||
jpeg_in_type = JPEG_IMAGE_TYPE_BGRX32;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_RGBA:
|
||||
jpeg_in_type = JPEG_IMAGE_TYPE_BGRX32;
|
||||
has_alpha = TRUE;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
jpeg_data->data.bufs_tail = compress_buf_new();
|
||||
jpeg_data->data.bufs_head = jpeg_data->data.bufs_tail;
|
||||
jpeg_data->data.dcc = dcc;
|
||||
|
||||
if (setjmp(jpeg_data->data.jmp_env)) {
|
||||
while (jpeg_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = jpeg_data->data.bufs_head;
|
||||
jpeg_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
|
||||
spice_chunks_linearize(src->data);
|
||||
}
|
||||
|
||||
jpeg_data->data.u.lines_data.chunks = src->data;
|
||||
jpeg_data->data.u.lines_data.stride = src->stride;
|
||||
if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
||||
jpeg_data->data.u.lines_data.next = 0;
|
||||
jpeg_data->data.u.lines_data.reverse = 0;
|
||||
stride = src->stride;
|
||||
} else {
|
||||
jpeg_data->data.u.lines_data.next = src->data->num_chunks - 1;
|
||||
jpeg_data->data.u.lines_data.reverse = 1;
|
||||
stride = -src->stride;
|
||||
}
|
||||
jpeg_size = jpeg_encode(jpeg, dcc->jpeg_quality, jpeg_in_type,
|
||||
src->x, src->y, NULL,
|
||||
0, stride, jpeg_data->data.bufs_head->buf.bytes,
|
||||
sizeof(jpeg_data->data.bufs_head->buf));
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if (jpeg_size > (src->y * src->stride)) {
|
||||
longjmp(jpeg_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
if (!has_alpha) {
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG;
|
||||
dest->u.jpeg.data_size = jpeg_size;
|
||||
|
||||
o_comp_data->comp_buf = jpeg_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = jpeg_size;
|
||||
o_comp_data->is_lossy = TRUE;
|
||||
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->jpeg_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
lz_data->data.bufs_head = jpeg_data->data.bufs_tail;
|
||||
lz_data->data.bufs_tail = lz_data->data.bufs_head;
|
||||
|
||||
comp_head_filled = jpeg_size % sizeof(lz_data->data.bufs_head->buf);
|
||||
comp_head_left = sizeof(lz_data->data.bufs_head->buf) - comp_head_filled;
|
||||
lz_out_start_byte = lz_data->data.bufs_head->buf.bytes + comp_head_filled;
|
||||
|
||||
lz_data->data.dcc = dcc;
|
||||
|
||||
lz_data->data.u.lines_data.chunks = src->data;
|
||||
lz_data->data.u.lines_data.stride = src->stride;
|
||||
lz_data->data.u.lines_data.next = 0;
|
||||
lz_data->data.u.lines_data.reverse = 0;
|
||||
|
||||
alpha_lz_size = lz_encode(lz, LZ_IMAGE_TYPE_XXXA, src->x, src->y,
|
||||
!!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN),
|
||||
NULL, 0, src->stride,
|
||||
lz_out_start_byte,
|
||||
comp_head_left);
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if ((jpeg_size + alpha_lz_size) > (src->y * src->stride)) {
|
||||
longjmp(jpeg_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG_ALPHA;
|
||||
dest->u.jpeg_alpha.flags = 0;
|
||||
if (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN) {
|
||||
dest->u.jpeg_alpha.flags |= SPICE_JPEG_ALPHA_FLAGS_TOP_DOWN;
|
||||
}
|
||||
|
||||
dest->u.jpeg_alpha.jpeg_size = jpeg_size;
|
||||
dest->u.jpeg_alpha.data_size = jpeg_size + alpha_lz_size;
|
||||
|
||||
o_comp_data->comp_buf = jpeg_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = jpeg_size + alpha_lz_size;
|
||||
o_comp_data->is_lossy = TRUE;
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->jpeg_alpha_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef USE_LZ4
|
||||
static int red_lz4_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id)
|
||||
{
|
||||
Lz4Data *lz4_data = &dcc->lz4_data;
|
||||
Lz4EncoderContext *lz4 = dcc->lz4;
|
||||
int lz4_size = 0;
|
||||
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->lz4_stat.clock);
|
||||
#endif
|
||||
|
||||
lz4_data->data.bufs_tail = compress_buf_new();
|
||||
lz4_data->data.bufs_head = lz4_data->data.bufs_tail;
|
||||
|
||||
if (!lz4_data->data.bufs_head) {
|
||||
spice_warning("failed to allocate compress buffer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lz4_data->data.bufs_head->send_next = NULL;
|
||||
lz4_data->data.dcc = dcc;
|
||||
|
||||
if (setjmp(lz4_data->data.jmp_env)) {
|
||||
while (lz4_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = lz4_data->data.bufs_head;
|
||||
lz4_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
|
||||
spice_chunks_linearize(src->data);
|
||||
}
|
||||
|
||||
lz4_data->data.u.lines_data.chunks = src->data;
|
||||
lz4_data->data.u.lines_data.stride = src->stride;
|
||||
lz4_data->data.u.lines_data.next = 0;
|
||||
lz4_data->data.u.lines_data.reverse = 0;
|
||||
/* fixme remove? lz4_data->usr.more_lines = lz4_usr_more_lines; */
|
||||
|
||||
lz4_size = lz4_encode(lz4, src->y, src->stride, lz4_data->data.bufs_head->buf.bytes,
|
||||
sizeof(lz4_data->data.bufs_head->buf),
|
||||
src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN, src->format);
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if (lz4_size > (src->y * src->stride)) {
|
||||
longjmp(lz4_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_LZ4;
|
||||
dest->u.lz4.data_size = lz4_size;
|
||||
|
||||
o_comp_data->comp_buf = lz4_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = lz4_size;
|
||||
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->lz4_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int red_quic_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
|
||||
SpiceBitmap *src, compress_send_data_t* o_comp_data,
|
||||
uint32_t group_id)
|
||||
{
|
||||
QuicData *quic_data = &dcc->quic_data;
|
||||
QuicContext *quic = dcc->quic;
|
||||
volatile QuicImageType type;
|
||||
int size, stride;
|
||||
|
||||
#ifdef COMPRESS_STAT
|
||||
stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->quic_stat.clock);
|
||||
#endif
|
||||
|
||||
switch (src->format) {
|
||||
case SPICE_BITMAP_FMT_32BIT:
|
||||
type = QUIC_IMAGE_TYPE_RGB32;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_RGBA:
|
||||
type = QUIC_IMAGE_TYPE_RGBA;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_16BIT:
|
||||
type = QUIC_IMAGE_TYPE_RGB16;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_24BIT:
|
||||
type = QUIC_IMAGE_TYPE_RGB24;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
quic_data->data.bufs_tail = compress_buf_new();
|
||||
quic_data->data.bufs_head = quic_data->data.bufs_tail;
|
||||
quic_data->data.dcc = dcc;
|
||||
|
||||
if (setjmp(quic_data->data.jmp_env)) {
|
||||
while (quic_data->data.bufs_head) {
|
||||
RedCompressBuf *buf = quic_data->data.bufs_head;
|
||||
quic_data->data.bufs_head = buf->send_next;
|
||||
compress_buf_free(buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
|
||||
spice_chunks_linearize(src->data);
|
||||
}
|
||||
|
||||
quic_data->data.u.lines_data.chunks = src->data;
|
||||
quic_data->data.u.lines_data.stride = src->stride;
|
||||
if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
||||
quic_data->data.u.lines_data.next = 0;
|
||||
quic_data->data.u.lines_data.reverse = 0;
|
||||
stride = src->stride;
|
||||
} else {
|
||||
quic_data->data.u.lines_data.next = src->data->num_chunks - 1;
|
||||
quic_data->data.u.lines_data.reverse = 1;
|
||||
stride = -src->stride;
|
||||
}
|
||||
size = quic_encode(quic, type, src->x, src->y, NULL, 0, stride,
|
||||
quic_data->data.bufs_head->buf.words,
|
||||
G_N_ELEMENTS(quic_data->data.bufs_head->buf.words));
|
||||
|
||||
// the compressed buffer is bigger than the original data
|
||||
if ((size << 2) > (src->y * src->stride)) {
|
||||
longjmp(quic_data->data.jmp_env, 1);
|
||||
}
|
||||
|
||||
dest->descriptor.type = SPICE_IMAGE_TYPE_QUIC;
|
||||
dest->u.quic.data_size = size << 2;
|
||||
|
||||
o_comp_data->comp_buf = quic_data->data.bufs_head;
|
||||
o_comp_data->comp_buf_size = size << 2;
|
||||
|
||||
stat_compress_add(&DCC_TO_DC(dcc)->quic_stat, start_time, src->stride * src->y,
|
||||
o_comp_data->comp_buf_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define MIN_SIZE_TO_COMPRESS 54
|
||||
#define MIN_DIMENSION_TO_QUIC 3
|
||||
static inline int red_compress_image(DisplayChannelClient *dcc,
|
||||
SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
|
||||
int can_lossy,
|
||||
compress_send_data_t* o_comp_data)
|
||||
{
|
||||
DisplayChannel *display_channel = DCC_TO_DC(dcc);
|
||||
SpiceImageCompression image_compression = dcc->image_compression;
|
||||
int quic_compress = FALSE;
|
||||
|
||||
if ((image_compression == SPICE_IMAGE_COMPRESSION_OFF) ||
|
||||
((src->y * src->stride) < MIN_SIZE_TO_COMPRESS)) { // TODO: change the size cond
|
||||
return FALSE;
|
||||
} else if (image_compression == SPICE_IMAGE_COMPRESSION_QUIC) {
|
||||
if (bitmap_fmt_is_plt(src->format)) {
|
||||
return FALSE;
|
||||
} else {
|
||||
quic_compress = TRUE;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
lz doesn't handle (1) bitmaps with strides that are larger than the width
|
||||
of the image in bytes (2) unstable bitmaps
|
||||
*/
|
||||
if (bitmap_has_extra_stride(src) || (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE)) {
|
||||
if ((image_compression == SPICE_IMAGE_COMPRESSION_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_GLZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_LZ4) ||
|
||||
bitmap_fmt_is_plt(src->format)) {
|
||||
return FALSE;
|
||||
} else {
|
||||
quic_compress = TRUE;
|
||||
}
|
||||
} else {
|
||||
if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ)) {
|
||||
if ((src->x < MIN_DIMENSION_TO_QUIC) || (src->y < MIN_DIMENSION_TO_QUIC)) {
|
||||
quic_compress = FALSE;
|
||||
} else {
|
||||
if (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_INVALID) {
|
||||
quic_compress = bitmap_fmt_has_graduality(src->format) &&
|
||||
bitmap_get_graduality_level(src) == BITMAP_GRADUAL_HIGH;
|
||||
} else {
|
||||
quic_compress = (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_HIGH);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quic_compress = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (quic_compress) {
|
||||
#ifdef COMPRESS_DEBUG
|
||||
spice_info("QUIC compress");
|
||||
#endif
|
||||
// if bitmaps is picture-like, compress it using jpeg
|
||||
if (can_lossy && display_channel->enable_jpeg &&
|
||||
((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ))) {
|
||||
// if we use lz for alpha, the stride can't be extra
|
||||
if (src->format != SPICE_BITMAP_FMT_RGBA || !bitmap_has_extra_stride(src)) {
|
||||
return red_jpeg_compress_image(dcc, dest,
|
||||
src, o_comp_data, drawable->group_id);
|
||||
}
|
||||
}
|
||||
return red_quic_compress_image(dcc, dest,
|
||||
src, o_comp_data, drawable->group_id);
|
||||
} else {
|
||||
int glz;
|
||||
int ret;
|
||||
if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_GLZ)) {
|
||||
glz = bitmap_fmt_has_graduality(src->format) && (
|
||||
(src->x * src->y) < glz_enc_dictionary_get_size(
|
||||
dcc->glz_dict->dict));
|
||||
} else if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_LZ) ||
|
||||
(image_compression == SPICE_IMAGE_COMPRESSION_LZ4)) {
|
||||
glz = FALSE;
|
||||
} else {
|
||||
spice_error("invalid image compression type %u", image_compression);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (glz) {
|
||||
/* using the global dictionary only if it is not frozen */
|
||||
pthread_rwlock_rdlock(&dcc->glz_dict->encode_lock);
|
||||
if (!dcc->glz_dict->migrate_freeze) {
|
||||
ret = red_glz_compress_image(dcc,
|
||||
dest, src,
|
||||
drawable, o_comp_data);
|
||||
} else {
|
||||
glz = FALSE;
|
||||
}
|
||||
pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
|
||||
}
|
||||
|
||||
if (!glz) {
|
||||
#ifdef USE_LZ4
|
||||
if (image_compression == SPICE_IMAGE_COMPRESSION_LZ4 &&
|
||||
bitmap_fmt_is_rgb(src->format) &&
|
||||
red_channel_client_test_remote_cap(&dcc->common.base,
|
||||
SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) {
|
||||
ret = red_lz4_compress_image(dcc, dest, src, o_comp_data,
|
||||
drawable->group_id);
|
||||
} else
|
||||
#endif
|
||||
ret = red_lz_compress_image(dcc, dest, src, o_comp_data,
|
||||
drawable->group_id);
|
||||
#ifdef COMPRESS_DEBUG
|
||||
spice_info("LZ LOCAL compress");
|
||||
#endif
|
||||
}
|
||||
#ifdef COMPRESS_DEBUG
|
||||
else {
|
||||
spice_info("LZ global compress fmt=%d", src->format);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int dcc_pixmap_cache_unlocked_add(DisplayChannelClient *dcc, uint64_t id, uint32_t size, int lossy)
|
||||
{
|
||||
PixmapCache *cache = dcc->pixmap_cache;
|
||||
@ -3043,7 +2383,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
|
||||
in order to prevent starvation in the client between pixmap_cache and
|
||||
global dictionary (in cases of multiple monitors) */
|
||||
if (reds_stream_get_family(rcc->stream) == AF_UNIX ||
|
||||
!red_compress_image(dcc, &image, &simage->u.bitmap,
|
||||
!dcc_compress_image(dcc, &image, &simage->u.bitmap,
|
||||
drawable, can_lossy, &comp_send_data)) {
|
||||
SpicePalette *palette;
|
||||
|
||||
@ -3053,7 +2393,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
|
||||
bitmap->flags = bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
|
||||
|
||||
palette = bitmap->palette;
|
||||
fill_palette(dcc, palette, &bitmap->flags);
|
||||
dcc_palette_cache_palette(dcc, palette, &bitmap->flags);
|
||||
spice_marshall_Image(m, &image,
|
||||
&bitmap_palette_out, &lzplt_palette_out);
|
||||
spice_assert(lzplt_palette_out == NULL);
|
||||
@ -5021,11 +4361,11 @@ static void red_marshall_image(RedChannelClient *rcc, SpiceMarshaller *m, ImageI
|
||||
}
|
||||
|
||||
if (lossy_comp) {
|
||||
comp_succeeded = red_jpeg_compress_image(dcc, &red_image,
|
||||
comp_succeeded = dcc_compress_image_jpeg(dcc, &red_image,
|
||||
&bitmap, &comp_send_data,
|
||||
worker->mem_slots.internal_groupslot_id);
|
||||
} else if (quic_comp) {
|
||||
comp_succeeded = red_quic_compress_image(dcc, &red_image, &bitmap,
|
||||
comp_succeeded = dcc_compress_image_quic(dcc, &red_image, &bitmap,
|
||||
&comp_send_data,
|
||||
worker->mem_slots.internal_groupslot_id);
|
||||
#ifdef USE_LZ4
|
||||
@ -5033,12 +4373,12 @@ static void red_marshall_image(RedChannelClient *rcc, SpiceMarshaller *m, ImageI
|
||||
bitmap_fmt_is_rgb(bitmap.format) &&
|
||||
red_channel_client_test_remote_cap(&dcc->common.base,
|
||||
SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) {
|
||||
comp_succeeded = red_lz4_compress_image(dcc, &red_image, &bitmap,
|
||||
comp_succeeded = dcc_compress_image_lz4(dcc, &red_image, &bitmap,
|
||||
&comp_send_data,
|
||||
worker->mem_slots.internal_groupslot_id);
|
||||
#endif
|
||||
} else if (comp_mode != SPICE_IMAGE_COMPRESSION_OFF) {
|
||||
comp_succeeded = red_lz_compress_image(dcc, &red_image, &bitmap,
|
||||
comp_succeeded = dcc_compress_image_lz(dcc, &red_image, &bitmap,
|
||||
&comp_send_data,
|
||||
worker->mem_slots.internal_groupslot_id);
|
||||
}
|
||||
@ -5286,7 +4626,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
|
||||
display_channel_marshall_reset_cache(rcc, m);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE:
|
||||
red_reset_palette_cache(dcc);
|
||||
dcc_palette_cache_reset(dcc);
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES, NULL);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_CREATE_SURFACE: {
|
||||
@ -5355,7 +4695,7 @@ static void display_channel_client_on_disconnect(RedChannelClient *rcc)
|
||||
pixmap_cache_unref(dcc->pixmap_cache);
|
||||
dcc->pixmap_cache = NULL;
|
||||
red_release_glz(dcc);
|
||||
red_reset_palette_cache(dcc);
|
||||
dcc_palette_cache_reset(dcc);
|
||||
free(dcc->send_data.stream_outbuf);
|
||||
free(dcc->send_data.free_list.res);
|
||||
dcc_destroy_stream_agents(dcc);
|
||||
@ -6944,7 +6284,7 @@ static void handle_dev_oom(void *opaque, void *payload)
|
||||
RedChannel *display_red_channel = &worker->display_channel->common.base;
|
||||
int ring_is_empty;
|
||||
|
||||
spice_assert(worker->running);
|
||||
spice_return_if_fail(worker->running);
|
||||
// streams? but without streams also leak
|
||||
spice_debug("OOM1 #draw=%u, #red_draw=%u, #glz_draw=%u current %u pipes %u",
|
||||
display->drawable_count,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user