[Spice-devel] [PATCH v2 07/18] worker: move compress to dcc_compress_image()
Fabiano Fidêncio
fabiano at fidencio.org
Thu Nov 19 00:57:18 PST 2015
On Wed, Nov 18, 2015 at 10:45 PM, Jonathon Jongsma <jjongsma at redhat.com> wrote:
> From: Marc-André Lureau <marcandre.lureau at gmail.com>
>
> ---
> Changes since v1:
> - rebased to resolve conflicts due to removed "fixme: remove?" lines from
> patch 01/18
>
> server/dcc.c | 631 ++++++++++++++++++++++++++++++++++++++++++
> server/dcc.h | 33 +++
> server/display-channel.h | 4 +
> server/red_parse_qxl.h | 6 +
> server/red_worker.c | 695 ++---------------------------------------------
> 5 files changed, 695 insertions(+), 674 deletions(-)
>
> diff --git a/server/dcc.c b/server/dcc.c
> index 2fb0af6..55a810b 100644
> --- a/server/dcc.c
> +++ b/server/dcc.c
> @@ -305,3 +305,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->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->glz_instance = NULL;
> + ret->red_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->glz_instance);
> +
> + 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 94eaab3..1b2c0a9 100644
> --- a/server/dcc.h
> +++ b/server/dcc.h
> @@ -106,6 +106,8 @@ struct DisplayChannelClient {
> int use_mjpeg_encoder_rate_control;
> uint32_t streams_max_latency;
> uint64_t streams_max_bit_rate;
> +
> + uint32_t glz_drawable_count;
> };
>
> #define DCC_TO_WORKER(dcc) \
> @@ -162,5 +164,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 5f5bc51..595ced8 100644
> --- a/server/display-channel.h
> +++ b/server/display-channel.h
> @@ -90,6 +90,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 28a9ca3..de9117a 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)) { \
> @@ -146,7 +140,6 @@ struct RedWorker {
> uint32_t cursor_poll_tries;
>
> uint32_t red_drawable_count;
> - uint32_t glz_drawable_count;
> uint32_t bits_unique;
>
> RedMemSlotInfo mem_slots;
> @@ -203,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)
> @@ -546,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)
> {
> @@ -593,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)
> {
> @@ -1924,8 +1895,10 @@ static void red_free_some(RedWorker *worker)
> DisplayChannelClient *dcc;
> RingItem *item, *next;
>
> +#if FIXME
> spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d", display->drawable_count,
> worker->red_drawable_count, worker->glz_drawable_count);
> +#endif
> FOREACH_DCC(worker->display_channel, item, next, dcc) {
> GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
>
> @@ -2033,79 +2006,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_WORKER(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->glz_instance = NULL;
> - ret->red_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).
> @@ -2144,7 +2044,7 @@ void dcc_free_glz_drawable_instance(DisplayChannelClient *dcc,
> }
> red_drawable_unref(worker, glz_drawable->red_drawable,
> glz_drawable->group_id);
> - worker->glz_drawable_count--;
> + dcc->glz_drawable_count--;
> if (ring_item_is_linked(&glz_drawable->link)) {
> ring_remove(&glz_drawable->link);
> }
> @@ -2262,565 +2162,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->glz_instance);
> -
> - 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;
> @@ -3044,7 +2385,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;
>
> @@ -3054,7 +2395,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);
> @@ -5022,11 +4363,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
> @@ -5034,12 +4375,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);
> }
> @@ -5287,7 +4628,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: {
> @@ -5356,15 +4697,17 @@ 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);
>
> // this was the last channel client
> +#if FIXME
> spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d",
> display->drawable_count, worker->red_drawable_count,
> worker->glz_drawable_count);
> +#endif
> }
>
> void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
> @@ -6940,13 +6283,14 @@ static void handle_dev_wakeup(void *opaque, void *payload)
> static void handle_dev_oom(void *opaque, void *payload)
> {
> RedWorker *worker = opaque;
> - DisplayChannel *display = worker->display_channel;
> -
> - RedChannel *display_red_channel = &worker->display_channel->common.base;
> int ring_is_empty;
>
> - spice_assert(worker->running);
> + spice_return_if_fail(worker->running);
Why changing the spice_assert to spice_return_if_fail?
> // streams? but without streams also leak
> +
> +#if FIXME
> + DisplayChannel *display = worker->display_channel;
> + RedChannel *display_red_channel = &worker->display_channel->common.base;
> spice_debug("OOM1 #draw=%u, #red_draw=%u, #glz_draw=%u current %u pipes %u",
> display->drawable_count,
> worker->red_drawable_count,
> @@ -6954,6 +6298,7 @@ static void handle_dev_oom(void *opaque, void *payload)
> display->current_size,
> worker->display_channel ?
> red_channel_sum_pipes_size(display_red_channel) : 0);
> +#endif
> while (red_process_commands(worker, MAX_PIPE_SIZE, &ring_is_empty)) {
> red_channel_push(&worker->display_channel->common.base);
> }
> @@ -6961,6 +6306,7 @@ static void handle_dev_oom(void *opaque, void *payload)
> red_free_some(worker);
> worker->qxl->st->qif->flush_resources(worker->qxl);
> }
> +#if FIXME
> spice_debug("OOM2 #draw=%u, #red_draw=%u, #glz_draw=%u current %u pipes %u",
> display->drawable_count,
> worker->red_drawable_count,
> @@ -6968,6 +6314,7 @@ static void handle_dev_oom(void *opaque, void *payload)
> display->current_size,
> worker->display_channel ?
> red_channel_sum_pipes_size(display_red_channel) : 0);
> +#endif
> red_dispatcher_clear_pending(worker->red_dispatcher, RED_DISPATCHER_PENDING_OOM);
> }
>
> --
> 2.4.3
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
Seems okay, ACK
--
Fabiano Fidêncio
More information about the Spice-devel
mailing list