Re: Patch to support LZ4 compression algorithm

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]