Hello There they go. However, don't forget that, since spice-protocol is a submodule of spice- common, once you push the commit for spice-protocol, the commit for spice- common should point to it. The same with spice and spice-gtk in relation to spice-common. Regards El Jueves, 13 de noviembre de 2014 16:04:00 Christophe Fergeau escribió: > Hey, > > On Fri, Nov 07, 2014 at 10:17:11AM +0100, Javier Celaya wrote: > > Hello > > > > I resend the patch for the spice repository. I just realized I forgot to > > remove a debug message from red_worker.c, sorry. > > Thanks for the updated patches, they look good to me. There are 2 blank > lines at the end of lz4_encoder.[ch] which should be removed. > Can you resend these patches generated with git-format-patch so that > they contain a commit log, and an author name/address? Then they can be > pushed upstream. > > Christophe
>From 4c78f7b02c7ad45485851bc3c87b71a5b4cf11a0 Mon Sep 17 00:00:00 2001 From: Javier Celaya <javier.celaya@xxxxxxxxx> Date: Wed, 5 Nov 2014 16:56:29 +0100 Subject: [PATCH] Add LZ4 compression display capability. --- spice/protocol.h | 1 + 1 file changed, 1 insertion(+) diff --git a/spice/protocol.h b/spice/protocol.h index 961a303..bea376c 100644 --- a/spice/protocol.h +++ b/spice/protocol.h @@ -133,6 +133,7 @@ enum { SPICE_DISPLAY_CAP_COMPOSITE, SPICE_DISPLAY_CAP_A8_SURFACE, SPICE_DISPLAY_CAP_STREAM_REPORT, + SPICE_DISPLAY_CAP_LZ4_COMPRESSION, }; enum { -- 1.9.3
>From 7579cde0d5c1f3357e08f0a8fd2571269e7cd127 Mon Sep 17 00:00:00 2001 From: Javier Celaya <javier.celaya@xxxxxxxxx> Date: Wed, 22 Oct 2014 09:58:29 +0200 Subject: [PATCH] Add LZ4 image compression support. - Add a new LZ4 image type to spice.proto. - Add canvas_get_lz4() to common_canvas_base, to get a pixmap from an lz4 image. - Add an enable-lz4 switch to the configure script, disabled by default. --- common/canvas_base.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ common/draw.h | 3 ++- spice.proto | 3 +++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/common/canvas_base.c b/common/canvas_base.c index 2753fae..a1bfc27 100644 --- a/common/canvas_base.c +++ b/common/canvas_base.c @@ -26,6 +26,10 @@ #include <stdio.h> #include <math.h> +#ifdef USE_LZ4 +#include <arpa/inet.h> +#include <lz4.h> +#endif #include <spice/macros.h> #include "log.h" #include "quic.h" @@ -543,6 +547,64 @@ static pixman_image_t *canvas_get_jpeg(CanvasBase *canvas, SpiceImage *image, in return surface; } +#ifdef USE_LZ4 +static pixman_image_t *canvas_get_lz4(CanvasBase *canvas, SpiceImage *image, int invers) +{ + pixman_image_t *surface = NULL; + int dec_size, enc_size; + int stride; + int stride_abs; + uint8_t *dest, *data, *data_end; + int width, height, direction; + LZ4_streamDecode_t *stream; + + spice_chunks_linearize(image->u.lz4.data); + data = image->u.lz4.data->chunk[0].data; + data_end = data + image->u.lz4.data->chunk[0].len; + width = image->descriptor.width; + height = image->descriptor.height; + direction = *(data++); + + surface = surface_create( +#ifdef WIN32 + canvas->dc, +#endif + PIXMAN_a8r8g8b8, + width, height, direction == 0); + if (surface == NULL) { + spice_warning("create surface failed"); + return NULL; + } + + stream = LZ4_createStreamDecode(); + dest = (uint8_t *)pixman_image_get_data(surface); + stride = pixman_image_get_stride(surface); + stride_abs = abs(stride); + if (direction == 1) { + dest -= (stride_abs * (height - 1)); + } + + do { + // Read next compressed block + enc_size = ntohl(*((uint32_t *)data)); + data += 4; + dec_size = LZ4_decompress_safe_continue(stream, (const char *) data, + (char *) dest, enc_size, height * stride_abs); + if (dec_size <= 0) { + spice_warning("Error decoding LZ4 block\n"); + pixman_image_unref(surface); + surface = NULL; + break; + } + dest += dec_size; + data += enc_size; + } while (data < data_end); + + LZ4_freeStreamDecode(stream); + return surface; +} +#endif + static pixman_image_t *canvas_get_jpeg_alpha(CanvasBase *canvas, SpiceImage *image, int invers) { @@ -1119,6 +1181,15 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SpiceImage surface = canvas_get_jpeg_alpha(canvas, image, 0); break; } + case SPICE_IMAGE_TYPE_LZ4: { +#ifdef USE_LZ4 + surface = canvas_get_lz4(canvas, image, 0); +#else + spice_warning("Lz4 compression algorithm not supported.\n"); + surface = NULL; +#endif + break; + } #if defined(SW_CANVAS_CACHE) case SPICE_IMAGE_TYPE_GLZ_RGB: { surface = canvas_get_glz(canvas, image, want_original); diff --git a/common/draw.h b/common/draw.h index 3704358..1155dc5 100644 --- a/common/draw.h +++ b/common/draw.h @@ -120,7 +120,7 @@ typedef struct SpiceSurface { typedef struct SpiceQUICData { uint32_t data_size; SpiceChunks *data; -} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData; +} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData, SpiceLZ4Data; typedef struct SpiceLZPLTData { uint8_t flags; @@ -153,6 +153,7 @@ typedef struct SpiceImage { SpiceLZRGBData lz_rgb; SpiceLZPLTData lz_plt; SpiceJPEGData jpeg; + SpiceLZ4Data lz4; SpiceZlibGlzRGBData zlib_glz; SpiceJPEGAlphaData jpeg_alpha; } u; diff --git a/spice.proto b/spice.proto index 316d287..01493c9 100644 --- a/spice.proto +++ b/spice.proto @@ -358,6 +358,7 @@ enum8 image_type { FROM_CACHE_LOSSLESS, ZLIB_GLZ_RGB, JPEG_ALPHA, + LZ4, }; flags8 image_flags { @@ -568,6 +569,8 @@ struct Image { BinaryData lz_rgb; case JPEG: BinaryData jpeg; + case LZ4: + BinaryData lz4; case LZ_PLT: LZPLTData lz_plt; case ZLIB_GLZ_RGB: -- 1.9.3
>From e8478894e277df1afde7b14323832ef2087599e6 Mon Sep 17 00:00:00 2001 From: Javier Celaya <javier.celaya@xxxxxxxxx> Date: Thu, 13 Nov 2014 16:58:03 +0100 Subject: [PATCH] Add LZ4 compression algorithm support. - Use PKG_CHECK_MODULES to find liblz4. - Set LZ4 display channel capability. --- configure.ac | 14 ++++++++++++++ gtk/Makefile.am | 2 ++ gtk/channel-display.c | 3 +++ 3 files changed, 19 insertions(+) diff --git a/configure.ac b/configure.ac index 613a128..b55f3a0 100644 --- a/configure.ac +++ b/configure.ac @@ -695,6 +695,19 @@ if test "x$enable_dbus" != "xno"; then fi fi +AC_ARG_ENABLE([lz4], + AS_HELP_STRING([--enable-lz4=@<:@yes/no@:>@], + [Enable lz4 compression algorithm @<:@default=no@:>@]), + [], + [enable_lz4="no"]) + +if test "x$enable_lz4" = "xyes"; then + PKG_CHECK_MODULES(LZ4, liblz4) + AC_DEFINE([USE_LZ4], [1], [Define to build with Lz4 support]) +fi +AC_SUBST(LZ4_CFLAGS) +AC_SUBST(LZ4_LIBS) + dnl =========================================================================== dnl check compiler flags @@ -765,6 +778,7 @@ AC_MSG_NOTICE([ USB redirection support: ${have_usbredir} ${with_usbredir_hotplug} DBus: ${have_dbus} WebDAV support: ${have_phodav} + LZ4 support: ${enable_lz4} Now type 'make' to build $PACKAGE diff --git a/gtk/Makefile.am b/gtk/Makefile.am index f11cfb9..6003793 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -100,6 +100,7 @@ SPICE_COMMON_CPPFLAGS = \ $(GUDEV_CFLAGS) \ $(SOUP_CFLAGS) \ $(PHODAV_CFLAGS) \ + $(LZ4_CFLAGS) \ $(NULL) AM_CPPFLAGS = \ @@ -202,6 +203,7 @@ libspice_client_glib_2_0_la_LIBADD = \ $(OPUS_LIBS) \ $(JPEG_LIBS) \ $(Z_LIBS) \ + $(LZ4_LIBS) \ $(PIXMAN_LIBS) \ $(SSL_LIBS) \ $(PULSE_LIBS) \ diff --git a/gtk/channel-display.c b/gtk/channel-display.c index 940a5a7..b658954 100644 --- a/gtk/channel-display.c +++ b/gtk/channel-display.c @@ -590,6 +590,9 @@ static void spice_display_channel_reset_capabilities(SpiceChannel *channel) spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_MONITORS_CONFIG); spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_COMPOSITE); spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_A8_SURFACE); +#ifdef USE_LZ4 + spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_LZ4_COMPRESSION); +#endif if (SPICE_DISPLAY_CHANNEL(channel)->priv->enable_adaptive_streaming) { spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_STREAM_REPORT); } -- 1.9.3
>From a94ed3125f244afa9a5a0602f91d76869625aac5 Mon Sep 17 00:00:00 2001 From: Javier Celaya <javier.celaya@xxxxxxxxx> Date: Thu, 13 Nov 2014 17:00:58 +0100 Subject: [PATCH] Add LZ4 compression support. - Add lz4 encoder to compress an image of type LZ4 (see spice_common). - Add code in red_worker to use LZ4 when it is enabled, and the client supports it through its display capability, or fallback to LZ. - Add enable_lz4 switch in the configure script. Show LZ4 support at the end. --- configure.ac | 15 +++++ server/Makefile.am | 4 ++ server/lz4_encoder.c | 122 ++++++++++++++++++++++++++++++++++++ server/lz4_encoder.h | 50 +++++++++++++++ server/red_worker.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++-- server/spice.h | 1 + 6 files changed, 358 insertions(+), 6 deletions(-) create mode 100644 server/lz4_encoder.c create mode 100644 server/lz4_encoder.h diff --git a/configure.ac b/configure.ac index cedeb40..ec20b89 100644 --- a/configure.ac +++ b/configure.ac @@ -124,6 +124,12 @@ AC_ARG_ENABLE(opengl, AS_IF([test x"$enable_opengl" != "xno"], [enable_opengl="yes"]) AM_CONDITIONAL(SUPPORT_GL, test "x$enable_opengl" = "xyes") +AC_ARG_ENABLE(lz4, +[ --enable-lz4 Enable lz4 compression algorithm],, +[enable_lz4="no"]) +AS_IF([test x"$enable_lz4" != "xno"], [enable_lz4="yes"]) +AM_CONDITIONAL(SUPPORT_LZ4, test "x$enable_lz4" = "xyes") + AC_ARG_ENABLE(smartcard, [ --enable-smartcard Enable network redirection],, [enable_smartcard="no"]) @@ -268,6 +274,13 @@ AC_SUBST(GL_CFLAGS) AC_SUBST(GL_LIBS) SPICE_NONPKGCONFIG_LIBS+=" $GL_LIBS" +if test "x$enable_lz4" = "xyes"; then + PKG_CHECK_MODULES(LZ4, liblz4) + AC_DEFINE([USE_LZ4], [1], [Define to build with Lz4 support]) +fi +AC_SUBST(LZ4_CFLAGS) +AC_SUBST(LZ4_LIBS) + if test "x$red_target" = "xx11" && test "x$enable_client" = "xyes" ; then if test "$os_linux" = yes; then PKG_CHECK_MODULES(ALSA, alsa) @@ -535,6 +548,8 @@ echo " GUI: ${enable_gui} " ; fi ; echo "\ + LZ4 support: ${enable_lz4} + Smartcard: ${enable_smartcard} SASL support: ${enable_sasl} diff --git a/server/Makefile.am b/server/Makefile.am index 34219c8..c5fc164 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -6,6 +6,7 @@ AM_CPPFLAGS = \ -DRED_STATISTICS \ $(COMMON_CFLAGS) \ $(GLIB2_CFLAGS) \ + $(LZ4_CFLAGS) \ $(PIXMAN_CFLAGS) \ $(SASL_CFLAGS) \ $(SLIRP_CFLAGS) \ @@ -35,6 +36,7 @@ libspice_server_la_LIBADD = \ $(GL_LIBS) \ $(GLIB2_LIBS) \ $(JPEG_LIBS) \ + $(LZ4_LIBS) \ $(LIBRT) \ $(PIXMAN_LIBS) \ $(SASL_LIBS) \ @@ -60,6 +62,8 @@ libspice_server_la_SOURCES = \ inputs_channel.h \ jpeg_encoder.c \ jpeg_encoder.h \ + lz4_encoder.c \ + lz4_encoder.h \ main_channel.c \ main_channel.h \ mjpeg_encoder.c \ diff --git a/server/lz4_encoder.c b/server/lz4_encoder.c new file mode 100644 index 0000000..531ab4b --- /dev/null +++ b/server/lz4_encoder.c @@ -0,0 +1,122 @@ +/* + Copyright (C) 2014 Flexible Software Solutions S.L. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef USE_LZ4 + +#define SPICE_LOG_DOMAIN "SpiceLz4Encoder" + +#include <arpa/inet.h> +#include <lz4.h> +#include "red_common.h" +#include "lz4_encoder.h" + +typedef struct Lz4Encoder { + Lz4EncoderUsrContext *usr; +} Lz4Encoder; + +Lz4EncoderContext* lz4_encoder_create(Lz4EncoderUsrContext *usr) +{ + Lz4Encoder *enc; + if (!usr->more_space || !usr->more_lines) { + return NULL; + } + + enc = spice_new0(Lz4Encoder, 1); + enc->usr = usr; + + return (Lz4EncoderContext*)enc; +} + +void lz4_encoder_destroy(Lz4EncoderContext* encoder) +{ + free(encoder); +} + +int lz4_encode(Lz4EncoderContext *lz4, int height, int stride, + uint8_t *io_ptr, unsigned int num_io_bytes) +{ + Lz4Encoder *enc = (Lz4Encoder *)lz4; + uint8_t *lines; + int num_lines = 0; + int total_lines = 0; + int in_size, enc_size, out_size = 0, already_copied; + int stride_abs = abs(stride); + uint8_t *in_buf, *compressed_lines; + uint8_t *out_buf = io_ptr; + LZ4_stream_t *stream = LZ4_createStream(); + + // Encode direction + *(out_buf++) = stride < 0 ? 1 : 0; + num_io_bytes--; + + do { + num_lines = enc->usr->more_lines(enc->usr, &lines); + if (num_lines <= 0) { + spice_error("more lines failed"); + LZ4_freeStream(stream); + return 0; + } + in_buf = stride < 0 ? lines - (stride_abs * (num_lines - 1)) : lines; + lines += stride * num_lines; + in_size = stride_abs * num_lines; + compressed_lines = (uint8_t *) malloc(LZ4_compressBound(in_size) + 4); + enc_size = LZ4_compress_continue(stream, (const char *) in_buf, + (char *) compressed_lines + 4, in_size); + if (enc_size <= 0) { + spice_error("compress failed!"); + free(compressed_lines); + LZ4_freeStream(stream); + return 0; + } + *((uint32_t *)compressed_lines) = htonl(enc_size); + + out_size += enc_size += 4; + already_copied = 0; + while (num_io_bytes < enc_size) { + memcpy(out_buf, compressed_lines + already_copied, num_io_bytes); + already_copied += num_io_bytes; + enc_size -= num_io_bytes; + num_io_bytes = enc->usr->more_space(enc->usr, &io_ptr); + if (num_io_bytes <= 0) { + spice_error("more space failed"); + free(compressed_lines); + LZ4_freeStream(stream); + return 0; + } + out_buf = io_ptr; + } + memcpy(out_buf, compressed_lines + already_copied, enc_size); + out_buf += enc_size; + num_io_bytes -= enc_size; + + free(compressed_lines); + total_lines += num_lines; + } while (total_lines < height); + + LZ4_freeStream(stream); + if (total_lines != height) { + spice_error("too many lines\n"); + out_size = 0; + } + + return out_size; +} + +#endif // USE_LZ4 diff --git a/server/lz4_encoder.h b/server/lz4_encoder.h new file mode 100644 index 0000000..f3359c0 --- /dev/null +++ b/server/lz4_encoder.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2014 Flexible Software Solutions S.L. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _H_LZ4_ENCODER +#define _H_LZ4_ENCODER + +#include <spice/types.h> + +typedef void* Lz4EncoderContext; +typedef struct Lz4EncoderUsrContext Lz4EncoderUsrContext; + +struct Lz4EncoderUsrContext { + int (*more_space)(Lz4EncoderUsrContext *usr, uint8_t **io_ptr); + int (*more_lines)(Lz4EncoderUsrContext *usr, uint8_t **lines); +}; + +Lz4EncoderContext* lz4_encoder_create(Lz4EncoderUsrContext *usr); +void lz4_encoder_destroy(Lz4EncoderContext *encoder); + +/* returns the total size of the encoded data. Images must be supplied from the + top line to the bottom */ +int lz4_encode(Lz4EncoderContext *lz4, int height, int stride, + uint8_t *io_ptr, unsigned int num_io_bytes); +#endif diff --git a/server/red_worker.c b/server/red_worker.c index e177b68..0ee10df 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -74,6 +74,9 @@ #include "red_memslots.h" #include "red_parse_qxl.h" #include "jpeg_encoder.h" +#ifdef USE_LZ4 +#include "lz4_encoder.h" +#endif #include "demarshallers.h" #include "zlib_encoder.h" #include "red_channel.h" @@ -237,6 +240,7 @@ static const char *quic_stat_name = "quic"; static const char *jpeg_stat_name = "jpeg"; static const char *zlib_stat_name = "zlib_glz"; static const char *jpeg_alpha_stat_name = "jpeg_alpha"; +static const char *lz4_stat_name = "lz4"; static inline void stat_compress_init(stat_info_t *info, const char *name) { @@ -599,6 +603,13 @@ typedef struct { EncoderData data; } JpegData; +#ifdef USE_LZ4 +typedef struct { + Lz4EncoderUsrContext usr; + EncoderData data; +} Lz4Data; +#endif + typedef struct { ZlibEncoderUsrContext usr; EncoderData data; @@ -740,6 +751,7 @@ struct DisplayChannel { stat_info_t jpeg_stat; stat_info_t zlib_glz_stat; stat_info_t jpeg_alpha_stat; + stat_info_t lz4_stat; #endif }; @@ -998,6 +1010,11 @@ typedef struct RedWorker { JpegData jpeg_data; JpegEncoderContext *jpeg; +#ifdef USE_LZ4 + Lz4Data lz4_data; + Lz4EncoderContext *lz4; +#endif + ZlibData zlib_data; ZlibEncoder *zlib; @@ -1190,27 +1207,37 @@ static void print_compress_stats(DisplayChannel *display_channel) stat_byte_to_mega(display_channel->jpeg_alpha_stat.comp_size), stat_cpu_time_to_sec(display_channel->jpeg_alpha_stat.total) ); + spice_info("LZ4 \t%8d\t%13.2f\t%12.2f\t%12.2f", + display_channel->lz4_stat.count, + stat_byte_to_mega(display_channel->lz4_stat.orig_size), + stat_byte_to_mega(display_channel->lz4_stat.comp_size), + stat_cpu_time_to_sec(display_channel->lz4_stat.total) + ); spice_info("-------------------------------------------------------------------"); spice_info("Total \t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->lz_stat.count + display_channel->glz_stat.count + display_channel->quic_stat.count + display_channel->jpeg_stat.count + + display_channel->lz4_stat.count + display_channel->jpeg_alpha_stat.count, stat_byte_to_mega(display_channel->lz_stat.orig_size + display_channel->glz_stat.orig_size + display_channel->quic_stat.orig_size + display_channel->jpeg_stat.orig_size + + display_channel->lz4_stat.orig_size + display_channel->jpeg_alpha_stat.orig_size), stat_byte_to_mega(display_channel->lz_stat.comp_size + glz_enc_size + display_channel->quic_stat.comp_size + display_channel->jpeg_stat.comp_size + + display_channel->lz4_stat.comp_size + display_channel->jpeg_alpha_stat.comp_size), stat_cpu_time_to_sec(display_channel->lz_stat.total + display_channel->glz_stat.total + display_channel->zlib_glz_stat.total + display_channel->quic_stat.total + display_channel->jpeg_stat.total + + display_channel->lz4_stat.total + display_channel->jpeg_alpha_stat.total) ); } @@ -5723,6 +5750,14 @@ static int jpeg_usr_more_space(JpegEncoderUsrContext *usr, uint8_t **io_ptr) return (encoder_usr_more_space(usr_data, (uint32_t **)io_ptr) << 2); } +#ifdef USE_LZ4 +static int lz4_usr_more_space(Lz4EncoderUsrContext *usr, uint8_t **io_ptr) +{ + EncoderData *usr_data = &(((Lz4Data *)usr)->data); + return (encoder_usr_more_space(usr_data, (uint32_t **)io_ptr) << 2); +} +#endif + static int zlib_usr_more_space(ZlibEncoderUsrContext *usr, uint8_t **io_ptr) { EncoderData *usr_data = &(((ZlibData *)usr)->data); @@ -5783,6 +5818,14 @@ static int jpeg_usr_more_lines(JpegEncoderUsrContext *usr, uint8_t **lines) return encoder_usr_more_lines(usr_data, lines); } +#ifdef USE_LZ4 +static int lz4_usr_more_lines(Lz4EncoderUsrContext *usr, uint8_t **lines) +{ + EncoderData *usr_data = &(((Lz4Data *)usr)->data); + return encoder_usr_more_lines(usr_data, lines); +} +#endif + static int zlib_usr_more_input(ZlibEncoderUsrContext *usr, uint8_t** input) { EncoderData *usr_data = &(((ZlibData *)usr)->data); @@ -5884,6 +5927,20 @@ static inline void red_init_jpeg(RedWorker *worker) } } +#ifdef USE_LZ4 +static inline void red_init_lz4(RedWorker *worker) +{ + worker->lz4_data.usr.more_space = lz4_usr_more_space; + worker->lz4_data.usr.more_lines = lz4_usr_more_lines; + + worker->lz4 = lz4_encoder_create(&worker->lz4_data.usr); + + if (!worker->lz4) { + spice_critical("create lz4 encoder failed"); + } +} +#endif + static inline void red_init_zlib(RedWorker *worker) { worker->zlib_data.usr.more_space = zlib_usr_more_space; @@ -6353,6 +6410,80 @@ static int red_jpeg_compress_image(DisplayChannelClient *dcc, SpiceImage *dest, 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) +{ + DisplayChannel *display_channel = DCC_TO_DC(dcc); + RedWorker *worker = display_channel->common.worker; + Lz4Data *lz4_data = &worker->lz4_data; + Lz4EncoderContext *lz4 = worker->lz4; + int lz4_size = 0; + int stride; + +#ifdef COMPRESS_STAT + stat_time_t start_time = stat_now(); +#endif + + lz4_data->data.bufs_tail = red_display_alloc_compress_buf(dcc); + 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; + red_display_free_compress_buf(dcc, 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->usr.more_lines = lz4_usr_more_lines; + + if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) { + lz4_data->data.u.lines_data.next = 0; + lz4_data->data.u.lines_data.reverse = 0; + stride = src->stride; + } else { + lz4_data->data.u.lines_data.next = src->data->num_chunks - 1; + lz4_data->data.u.lines_data.reverse = 1; + stride = -src->stride; + } + + lz4_size = lz4_encode(lz4, src->y, stride, (uint8_t*)lz4_data->data.bufs_head->buf, + sizeof(lz4_data->data.bufs_head->buf)); + + // 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 + static inline int red_quic_compress_image(DisplayChannelClient *dcc, SpiceImage *dest, SpiceBitmap *src, compress_send_data_t* o_comp_data, uint32_t group_id) @@ -6469,6 +6600,7 @@ static inline int red_compress_image(DisplayChannelClient *dcc, if (_stride_is_extra(src) || (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE)) { if ((image_compression == SPICE_IMAGE_COMPRESS_LZ) || (image_compression == SPICE_IMAGE_COMPRESS_GLZ) || + (image_compression == SPICE_IMAGE_COMPRESS_LZ4) || BITMAP_FMT_IS_PLT[src->format]) { return FALSE; } else { @@ -6520,7 +6652,8 @@ static inline int red_compress_image(DisplayChannelClient *dcc, (src->x * src->y) < glz_enc_dictionary_get_size( dcc->glz_dict->dict)); } else if ((image_compression == SPICE_IMAGE_COMPRESS_AUTO_LZ) || - (image_compression == SPICE_IMAGE_COMPRESS_LZ)) { + (image_compression == SPICE_IMAGE_COMPRESS_LZ) || + (image_compression == SPICE_IMAGE_COMPRESS_LZ4)) { glz = FALSE; } else { spice_error("invalid image compression type %u", image_compression); @@ -6541,8 +6674,16 @@ static inline int red_compress_image(DisplayChannelClient *dcc, } if (!glz) { - ret = red_lz_compress_image(dcc, dest, src, o_comp_data, - drawable->group_id); +#ifdef USE_LZ4 + if (image_compression == SPICE_IMAGE_COMPRESS_LZ4 && + 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 @@ -8773,9 +8914,18 @@ static void red_marshall_image(RedChannelClient *rcc, SpiceMarshaller *m, ImageI &comp_send_data, worker->mem_slots.internal_groupslot_id); } else { - comp_succeeded = red_lz_compress_image(dcc, &red_image, &bitmap, - &comp_send_data, - worker->mem_slots.internal_groupslot_id); +#ifdef USE_LZ4 + if (comp_mode == SPICE_IMAGE_COMPRESS_LZ4 && + 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_send_data, + worker->mem_slots.internal_groupslot_id); + } else +#endif + comp_succeeded = red_lz_compress_image(dcc, &red_image, &bitmap, + &comp_send_data, + worker->mem_slots.internal_groupslot_id); } } @@ -10565,6 +10715,7 @@ static void display_channel_create(RedWorker *worker, int migrate) stat_compress_init(&display_channel->jpeg_stat, jpeg_stat_name); stat_compress_init(&display_channel->zlib_glz_stat, zlib_stat_name); stat_compress_init(&display_channel->jpeg_alpha_stat, jpeg_alpha_stat_name); + stat_compress_init(&display_channel->lz4_stat, lz4_stat_name); } static void guest_set_client_capabilities(RedWorker *worker) @@ -11589,6 +11740,11 @@ void handle_dev_set_compression(void *opaque, void *payload) case SPICE_IMAGE_COMPRESS_QUIC: spice_info("ic quic"); break; +#ifdef USE_LZ4 + case SPICE_IMAGE_COMPRESS_LZ4: + spice_info("ic lz4"); + break; +#endif case SPICE_IMAGE_COMPRESS_LZ: spice_info("ic lz"); break; @@ -11610,6 +11766,7 @@ void handle_dev_set_compression(void *opaque, void *payload) stat_reset(&worker->display_channel->jpeg_stat); stat_reset(&worker->display_channel->zlib_glz_stat); stat_reset(&worker->display_channel->jpeg_alpha_stat); + stat_reset(&worker->display_channel->lz4_stat); } #endif } @@ -12013,6 +12170,9 @@ SPICE_GNUC_NORETURN void *red_worker_main(void *arg) red_init_quic(worker); red_init_lz(worker); red_init_jpeg(worker); +#ifdef USE_LZ4 + red_init_lz4(worker); +#endif red_init_zlib(worker); worker->event_timeout = INF_EVENT_WAIT; for (;;) { diff --git a/server/spice.h b/server/spice.h index 58700d1..b38ca62 100644 --- a/server/spice.h +++ b/server/spice.h @@ -479,6 +479,7 @@ typedef enum { SPICE_IMAGE_COMPRESS_QUIC = 4, SPICE_IMAGE_COMPRESS_GLZ = 5, SPICE_IMAGE_COMPRESS_LZ = 6, + SPICE_IMAGE_COMPRESS_LZ4 = 7, } spice_image_compression_t; int spice_server_set_image_compression(SpiceServer *s, -- 1.9.3
_______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel