[Spice-devel] [PATCH 2/2] worker: move compress to dcc_compress_image()
Frediano Ziglio
fziglio at redhat.com
Fri Nov 20 02:06:12 PST 2015
>
> On Thu, 2015-11-19 at 14:16 +0000, Frediano Ziglio wrote:
> > Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
> > Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> > ---
> > server/dcc.c | 631 +++++++++++++++++++++++++++++++++++++++++++
> > server/dcc.h | 31 +++
> > server/display-channel.h | 4 +
> > server/red_parse_qxl.h | 6 +
> > server/red_worker.c | 678
> > +---------------------------------------------
> > -
> > 5 files changed, 681 insertions(+), 669 deletions(-)
> >
> > diff --git a/server/dcc.c b/server/dcc.c
> > index a14247c..1e18814 100644
> > --- a/server/dcc.c
> > +++ b/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);
> > +}
> > diff --git a/server/dcc.h b/server/dcc.h
> > index a6ca9be..7827f72 100644
> > --- a/server/dcc.h
> > +++ b/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_ */
> > diff --git a/server/display-channel.h b/server/display-channel.h
> > index 7f3949f..111e014 100644
> > --- a/server/display-channel.h
> > +++ b/server/display-channel.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,
> > diff --git a/server/red_parse_qxl.h b/server/red_parse_qxl.h
> > index 87862fa..b3b28e1 100644
> > --- a/server/red_parse_qxl.h
> > +++ b/server/red_parse_qxl.h
> > @@ -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;
> > diff --git a/server/red_worker.c b/server/red_worker.c
> > index eab00ff..d744f48 100644
> > --- a/server/red_worker.c
> > +++ b/server/red_worker.c
> > @@ -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,
>
>
> ACK
>
Merged
Frediano
More information about the Spice-devel
mailing list