[Spice-commits] configure.ac server/Makefile.am server/lz4_encoder.c server/lz4_encoder.h server/red_worker.c server/spice-server.h spice-common

Christophe Fergau teuf at kemper.freedesktop.org
Tue Dec 2 10:43:22 PST 2014


 configure.ac          |   15 ++++
 server/Makefile.am    |    4 +
 server/lz4_encoder.c  |  122 +++++++++++++++++++++++++++++++++++
 server/lz4_encoder.h  |   50 ++++++++++++++
 server/red_worker.c   |  172 ++++++++++++++++++++++++++++++++++++++++++++++++--
 server/spice-server.h |    1 
 spice-common          |    2 
 7 files changed, 359 insertions(+), 7 deletions(-)

New commits:
commit b532ef0866cefe260ad0f08550f7c40d3580d0d7
Author: Javier Celaya <javier.celaya at flexvm.es>
Date:   Thu Nov 13 17:00:58 2014 +0100

    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.

diff --git a/configure.ac b/configure.ac
index c9d83e1..7545ba0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -138,6 +138,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"])
@@ -287,6 +293,13 @@ AC_ARG_ENABLE([xinerama],
     [AS_HELP_STRING([--disable-xinerama],
         [disable Xinerama library @<:@default=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)
+
 if test "x$red_target" = "xx11" && test "x$enable_client" = "xyes" ; then
 	if test "$os_linux" = yes; then
 		PKG_CHECK_MODULES(ALSA, alsa)
@@ -549,6 +562,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 f162a18..3cef243 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)							\
@@ -75,6 +77,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 cbb78a2..a18987a 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)
                );
 }
@@ -5725,6 +5752,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);
@@ -5785,6 +5820,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);
@@ -5886,6 +5929,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;
@@ -6355,6 +6412,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)
@@ -6471,6 +6602,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 {
@@ -6522,7 +6654,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);
@@ -6543,8 +6676,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
@@ -8775,9 +8916,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);
         }
     }
 
@@ -10567,6 +10717,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)
@@ -11591,6 +11742,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;
@@ -11612,6 +11768,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
 }
@@ -12015,6 +12172,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-server.h b/server/spice-server.h
index 79daac5..c97b221 100644
--- a/server/spice-server.h
+++ b/server/spice-server.h
@@ -74,6 +74,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,
diff --git a/spice-common b/spice-common
index b3a00f4..5b3cdad 160000
--- a/spice-common
+++ b/spice-common
@@ -1 +1 @@
-Subproject commit b3a00f4411962e0c06c7ad89a9936df388aa0023
+Subproject commit 5b3cdad921d32c9294377efac61243a09f849d08


More information about the Spice-commits mailing list