Re: [PATCH 2/2] worker: move compress to dcc_compress_image()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2015-11-19 at 14:16 +0000, Frediano Ziglio wrote:
> Signed-off-by: Marc-André Lureau <marcandre.lureau@xxxxxxxxx>
> Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx>
> ---
>  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
_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/spice-devel





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]