dcc: Rewrite dcc_image_compress

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

jpeg is used only when jpeg-wan-compression allows it

Acked-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
Pavel Grunt 2016-02-16 17:44:40 +01:00 committed by Frediano Ziglio
parent 51bd316ce5
commit f401eb07f9

View File

@ -1081,124 +1081,152 @@ static int dcc_compress_image_quic(DisplayChannelClient *dcc, SpiceImage *dest,
return TRUE; return TRUE;
} }
#define MIN_SIZE_TO_COMPRESS 54
#define MIN_DIMENSION_TO_QUIC 3 #define MIN_DIMENSION_TO_QUIC 3
/**
* quic doesn't handle:
* (1) palette
*/
static bool can_quic_compress(SpiceBitmap *bitmap)
{
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);
}
#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;
}
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 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, int dcc_compress_image(DisplayChannelClient *dcc,
SpiceImage *dest, SpiceBitmap *src, Drawable *drawable, SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
int can_lossy, int can_lossy,
compress_send_data_t* o_comp_data) compress_send_data_t* o_comp_data)
{ {
DisplayChannel *display_channel = DCC_TO_DC(dcc); DisplayChannel *display_channel = DCC_TO_DC(dcc);
SpiceImageCompression image_compression = dcc->image_compression; SpiceImageCompression image_compression;
int quic_compress = FALSE;
if ((image_compression == SPICE_IMAGE_COMPRESSION_OFF) || image_compression = get_compression_for_bitmap(src, dcc->image_compression, drawable);
((src->y * src->stride) < MIN_SIZE_TO_COMPRESS)) { // TODO: change the size cond switch (image_compression) {
case SPICE_IMAGE_COMPRESSION_OFF:
return FALSE; return FALSE;
} else if (image_compression == SPICE_IMAGE_COMPRESSION_QUIC) { case SPICE_IMAGE_COMPRESSION_QUIC:
if (bitmap_fmt_is_plt(src->format)) { if (can_lossy && display_channel->enable_jpeg &&
return FALSE; (src->format != SPICE_BITMAP_FMT_RGBA || !bitmap_has_extra_stride(src))) {
} else { #ifdef COMPRESS_DEBUG
quic_compress = TRUE; spice_info("JPEG compress");
#endif
return dcc_compress_image_jpeg(dcc, dest, src, o_comp_data);
} }
} 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);
}
}
} else {
quic_compress = FALSE;
}
}
}
if (quic_compress) {
#ifdef COMPRESS_DEBUG #ifdef COMPRESS_DEBUG
spice_info("QUIC compress"); spice_info("QUIC compress");
#endif #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);
}
}
return dcc_compress_image_quic(dcc, dest, src, o_comp_data); return dcc_compress_image_quic(dcc, dest, src, o_comp_data);
} else { case SPICE_IMAGE_COMPRESSION_GLZ:
int glz; if ((src->x * src->y) < glz_enc_dictionary_get_size(dcc->glz_dict->dict)) {
int ret; int ret, frozen;
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) {
/* using the global dictionary only if it is not frozen */ /* using the global dictionary only if it is not frozen */
pthread_rwlock_rdlock(&dcc->glz_dict->encode_lock); pthread_rwlock_rdlock(&dcc->glz_dict->encode_lock);
if (!dcc->glz_dict->migrate_freeze) { frozen = dcc->glz_dict->migrate_freeze;
ret = dcc_compress_image_glz(dcc, if (!frozen) {
dest, src, #ifdef COMPRESS_DEBUG
drawable, o_comp_data); spice_info("LZ global compress fmt=%d", src->format);
} else { #endif
glz = FALSE; ret = dcc_compress_image_glz(dcc, dest, src, drawable, o_comp_data);
} }
pthread_rwlock_unlock(&dcc->glz_dict->encode_lock); pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
if (!frozen) {
return ret;
}
} }
goto lz_compress;
if (!glz) {
#ifdef USE_LZ4 #ifdef USE_LZ4
if (image_compression == SPICE_IMAGE_COMPRESSION_LZ4 && case SPICE_IMAGE_COMPRESSION_LZ4:
bitmap_fmt_is_rgb(src->format) && if (red_channel_client_test_remote_cap(&dcc->common.base,
red_channel_client_test_remote_cap(&dcc->common.base, SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) {
SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) {
ret = dcc_compress_image_lz4(dcc, dest, src, o_comp_data);
} else
#endif
ret = dcc_compress_image_lz(dcc, dest, src, o_comp_data);
#ifdef COMPRESS_DEBUG #ifdef COMPRESS_DEBUG
spice_info("LZ LOCAL compress"); spice_info("LZ4 compress");
#endif #endif
} return dcc_compress_image_lz4(dcc, dest, src, o_comp_data);
#ifdef COMPRESS_DEBUG
else {
spice_info("LZ global compress fmt=%d", src->format);
} }
#endif #endif
return ret; lz_compress:
case SPICE_IMAGE_COMPRESSION_LZ:
#ifdef COMPRESS_DEBUG
spice_info("LZ LOCAL compress");
#endif
return dcc_compress_image_lz(dcc, dest, src, o_comp_data);
default:
spice_error("invalid image compression type %u", image_compression);
} }
return FALSE;
} }
#define CLIENT_PALETTE_CACHE #define CLIENT_PALETTE_CACHE