Rules are now: Compression type: off -> uncompressed quic -> jpeg if possible else quic else off lz -> lz if possible else off glz -> glz if possible else lz else off auto_lz -> lz if possible else jpeg else quic else off auto_glz -> glz if possible else lz else jpeg else quic else off lz4 -> lz4 if possible else lz else off --- v3: new approach using a function which determines the compression method based on the input parameters - SpiceBitmap and preferred compression --- server/dcc.c | 214 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 120 insertions(+), 94 deletions(-) diff --git a/server/dcc.c b/server/dcc.c index bf692f8..6f7babf 100644 --- a/server/dcc.c +++ b/server/dcc.c @@ -1027,131 +1027,157 @@ static int dcc_compress_image_quic(DisplayChannelClient *dcc, SpiceImage *dest, 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) +/** + * quic doesn't handle: + * (1) palette + */ +static bool can_quic_compress(SpiceBitmap *bitmap) { - DisplayChannel *display_channel = DCC_TO_DC(dcc); - SpiceImageCompression image_compression = dcc->image_compression; - int quic_compress = FALSE; - uint32_t group_id; + return !bitmap_fmt_is_plt(bitmap->format) && + bitmap->x >= MIN_DIMENSION_TO_QUIC && bitmap->y >= MIN_DIMENSION_TO_QUIC; +} +/** + * lz doesn't handle: + * (1) bitmaps with strides that are larger than the width of the image in bytes + * (2) unstable bitmaps + */ +static bool can_lz_compress(SpiceBitmap *bitmap) +{ + return !bitmap_has_extra_stride(bitmap) && + !(bitmap->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE); +} - 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; +#define MIN_SIZE_TO_COMPRESS 54 +static SpiceImageCompression get_compression_for_bitmap(SpiceBitmap *bitmap, + SpiceImageCompression preferred_compression, + Drawable *drawable) +{ + if (bitmap->y * bitmap->stride < MIN_SIZE_TO_COMPRESS) { // TODO: change the size cond + return SPICE_IMAGE_COMPRESSION_OFF; + } + if (preferred_compression == SPICE_IMAGE_COMPRESSION_OFF) { + return SPICE_IMAGE_COMPRESSION_OFF; + } + if (preferred_compression == SPICE_IMAGE_COMPRESSION_QUIC) { + if (can_quic_compress(bitmap)) { + return SPICE_IMAGE_COMPRESSION_QUIC; } - } 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 == NULL || - 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); - } + return SPICE_IMAGE_COMPRESSION_OFF; + } + + if (preferred_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ || + preferred_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) { + if (can_quic_compress(bitmap)) { + if (drawable == NULL || + drawable->copy_bitmap_graduality == BITMAP_GRADUAL_INVALID) { + if (bitmap_fmt_has_graduality(bitmap->format) && + bitmap_get_graduality_level(bitmap) == BITMAP_GRADUAL_HIGH) { + return SPICE_IMAGE_COMPRESSION_QUIC; } - } else { - quic_compress = FALSE; + } else if (!can_lz_compress(bitmap) || + drawable->copy_bitmap_graduality == BITMAP_GRADUAL_HIGH) { + return SPICE_IMAGE_COMPRESSION_QUIC; } } + if (preferred_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) { + preferred_compression = SPICE_IMAGE_COMPRESSION_LZ; + } else { + preferred_compression = SPICE_IMAGE_COMPRESSION_GLZ; + } + } + + if (preferred_compression == SPICE_IMAGE_COMPRESSION_GLZ) { + if (drawable == NULL || bitmap_fmt_has_graduality(bitmap->format)) { + preferred_compression = SPICE_IMAGE_COMPRESSION_LZ; + } + } + + if (preferred_compression == SPICE_IMAGE_COMPRESSION_LZ4) { + if (!bitmap_fmt_is_rgb(bitmap->format)) { + preferred_compression = SPICE_IMAGE_COMPRESSION_LZ; + } + } + + if (preferred_compression == SPICE_IMAGE_COMPRESSION_LZ || + preferred_compression == SPICE_IMAGE_COMPRESSION_LZ4 || + preferred_compression == SPICE_IMAGE_COMPRESSION_GLZ) { + if (can_lz_compress(bitmap)) { + return preferred_compression; + } + return SPICE_IMAGE_COMPRESSION_OFF; } + return SPICE_IMAGE_COMPRESSION_INVALID; +} + +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; + uint32_t group_id; + if (drawable != NULL) { group_id = drawable->group_id; } else { group_id = red_worker_get_memslot(display_channel->common.worker)->internal_groupslot_id; } - if (quic_compress) { + image_compression = get_compression_for_bitmap(src, dcc->image_compression, drawable); + switch (image_compression) { + case SPICE_IMAGE_COMPRESSION_OFF: + return FALSE; + case SPICE_IMAGE_COMPRESSION_QUIC: + if (can_lossy && display_channel->enable_jpeg && + (src->format != SPICE_BITMAP_FMT_RGBA || !bitmap_has_extra_stride(src))) { #ifdef COMPRESS_DEBUG - spice_info("QUIC compress"); + spice_info("JPEG 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, group_id); - } + return dcc_compress_image_jpeg(dcc, dest, src, o_comp_data, group_id); } +#ifdef COMPRESS_DEBUG + spice_info("QUIC compress"); +#endif return dcc_compress_image_quic(dcc, dest, src, o_comp_data, group_id); - } else { - int glz; - int ret; - if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ) || - (image_compression == SPICE_IMAGE_COMPRESSION_GLZ)) { - glz = drawable != NULL && 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) { + case SPICE_IMAGE_COMPRESSION_GLZ: + if ((src->x * src->y) < glz_enc_dictionary_get_size(dcc->glz_dict->dict)) { + int ret, frozen; /* 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; + frozen = dcc->glz_dict->migrate_freeze; + if (!frozen) { +#ifdef COMPRESS_DEBUG + spice_info("LZ global compress fmt=%d", src->format); +#endif + ret = dcc_compress_image_glz(dcc, dest, src, drawable, o_comp_data); } pthread_rwlock_unlock(&dcc->glz_dict->encode_lock); + if (!frozen) { + return ret; + } } - - 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, group_id); - } else -#endif - ret = dcc_compress_image_lz(dcc, dest, src, o_comp_data, group_id); + case SPICE_IMAGE_COMPRESSION_LZ4: + if (red_channel_client_test_remote_cap(&dcc->common.base, + SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) { #ifdef COMPRESS_DEBUG - spice_info("LZ LOCAL compress"); + spice_info("LZ4 compress"); #endif + return dcc_compress_image_lz4(dcc, dest, src, o_comp_data, group_id); } +#endif + case SPICE_IMAGE_COMPRESSION_LZ: #ifdef COMPRESS_DEBUG - else { - spice_info("LZ global compress fmt=%d", src->format); - } + spice_info("LZ LOCAL compress"); #endif - return ret; + return dcc_compress_image_lz(dcc, dest, src, o_comp_data, group_id); + default: + spice_error("invalid image compression type %u", image_compression); } + return FALSE; } #define CLIENT_PALETTE_CACHE -- 2.5.0 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel