applying zlib compression over glz on WAN connection

This commit is contained in:
Yonit Halperin 2010-06-20 15:24:49 +03:00 committed by Alexander Larsson
parent cfc1e95bda
commit 25bb38f643
23 changed files with 504 additions and 31 deletions

View File

@ -111,6 +111,8 @@ RED_COMMON_SRCS = \
threads.h \
utils.cpp \
utils.h \
zlib_decoder.cpp \
zlib_decoder.h \
$(NULL)
MAINTAINERCLEANFILES = $(spice_built_sources)

View File

@ -30,6 +30,7 @@
#include "glz_decoded_image.h"
#include "glz_decoder.h"
#include "jpeg_decoder.h"
#include "zlib_decoder.h"
enum CanvasType {
CANVAS_TYPE_INVALID,
@ -446,6 +447,7 @@ protected:
GlzDecoder& glz_decoder() {return _glz_decoder;}
JpegDecoder& jpeg_decoder() { return _jpeg_decoder;}
ZlibDecoder& zlib_decoder() { return _zlib_decoder;}
private:
void access_test(void* ptr, size_t size);
@ -468,6 +470,7 @@ private:
GlzDecoder _glz_decoder;
JpegDecoder _jpeg_decoder;
ZlibDecoder _zlib_decoder;
CSurfaces& _csurfaces;

View File

@ -38,7 +38,8 @@ GDICanvas::GDICanvas(int width, int height, uint32_t format,
&palette_cache.base,
&csurfaces.base,
&glz_decoder(),
&jpeg_decoder()))) {
&jpeg_decoder(),
&zlib_decoder()))) {
THROW("create canvas failed");
}
}

View File

@ -41,7 +41,8 @@ GCanvas::GCanvas(int width, int height, uint32_t format, RedWindow *win,
&palette_cache.base,
&csurfaces.base,
&glz_decoder(),
&jpeg_decoder()))) {
&jpeg_decoder(),
&zlib_decoder()))) {
THROW("create canvas failed");
}
}

View File

@ -43,14 +43,16 @@ SCanvas::SCanvas(bool onscreen,
&palette_cache.base,
&csurfaces.base,
&glz_decoder(),
&jpeg_decoder());
&jpeg_decoder(),
&zlib_decoder());
} else {
_canvas = canvas_create(width, height, format,
&pixmap_cache.base,
&palette_cache.base,
&csurfaces.base,
&glz_decoder(),
&jpeg_decoder());
&jpeg_decoder(),
&zlib_decoder());
}
if (_canvas == NULL) {
THROW("create canvas failed");

View File

@ -69,7 +69,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="log4cppD.lib pixman-1D.lib libeay32MTd.lib ssleay32MTd.lib ws2_32.lib msimg32.lib winmm.lib libcelt_0_5_1D.lib pthreadVC2d.lib version.lib CEGUIBase_Static_d.lib CEGUITGAImageCodec_Static_d.lib CEGUIExpatParser_Static_d.lib freetype2312MT_D.lib libexpatMT_D.lib pcre_D.lib CEGUIFalagardWRBase_Static_d.lib libjpeg-static-mt-debug.lib"
AdditionalDependencies="log4cppD.lib pixman-1D.lib libeay32MTd.lib ssleay32MTd.lib ws2_32.lib msimg32.lib winmm.lib libcelt_0_5_1D.lib pthreadVC2d.lib version.lib CEGUIBase_Static_d.lib CEGUITGAImageCodec_Static_d.lib CEGUIExpatParser_Static_d.lib freetype2312MT_D.lib libexpatMT_D.lib pcre_D.lib CEGUIFalagardWRBase_Static_d.lib libjpeg-static-mt-debug.lib zlibwapi.lib"
OutputFile="$(OutDir)\spicec.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(SPICE_LIBS)\lib&quot;"
@ -148,7 +148,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="log4cpp.lib pixman-1.lib libeay32MT.lib ssleay32MT.lib ws2_32.lib msimg32.lib winmm.lib libcelt_0_5_1.lib pthreadVC2.lib version.lib CEGUIBase_Static.lib CEGUITGAImageCodec_Static.lib CEGUIExpatParser_Static.lib freetype2312MT.lib libexpatMT.lib pcre.lib CEGUIFalagardWRBase_Static.lib libjpeg-static-mt.lib"
AdditionalDependencies="log4cpp.lib pixman-1.lib libeay32MT.lib ssleay32MT.lib ws2_32.lib msimg32.lib winmm.lib libcelt_0_5_1.lib pthreadVC2.lib version.lib CEGUIBase_Static.lib CEGUITGAImageCodec_Static.lib CEGUIExpatParser_Static.lib freetype2312MT.lib libexpatMT.lib pcre.lib CEGUIFalagardWRBase_Static.lib libjpeg-static-mt.lib zlibwapi.lib"
OutputFile="$(OutDir)\spicec.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;$(SPICE_LIBS)\lib&quot;"
@ -437,6 +437,10 @@
RelativePath="..\utils.cpp"
>
</File>
<File
RelativePath="..\zlib_decoder.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
@ -671,6 +675,10 @@
RelativePath=".\win_platform.h"
>
</File>
<File
RelativePath="..\zlib_decoder.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"

View File

@ -112,6 +112,8 @@ RED_COMMON_SRCS = \
$(CLIENT_DIR)/tunnel_channel.h \
$(CLIENT_DIR)/utils.cpp \
$(CLIENT_DIR)/utils.h \
$(CLIENT_DIR)/zlib_decoder.cpp \
$(CLIENT_DIR)/zlib_decoder.h \
$(CLIENT_DIR)/icon.h \
$(CLIENT_DIR)/gui/softrenderer.h \
$(CLIENT_DIR)/gui/softrenderer.cpp \
@ -174,6 +176,7 @@ spicec_LDFLAGS = \
$(SSL_LIBS) \
$(CEGUI_LIBS) \
$(JPEG_LIBS) \
$(Z_LIBS) \
$(SPICE_NONPKGCONFIG_LIBS)
spicec_LDADD = \

58
client/zlib_decoder.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "common.h"
#include "zlib_decoder.h"
#include "debug.h"
#include "utils.h"
static void op_decode(SpiceZlibDecoder *decoder,
uint8_t *data,
int data_size,
uint8_t *dest,
int dest_size)
{
ZlibDecoder* _decoder = static_cast<ZlibDecoder*>(decoder);
_decoder->decode(data, data_size, dest, dest_size);
}
ZlibDecoder::ZlibDecoder()
{
int z_ret;
_z_strm.zalloc = Z_NULL;
_z_strm.zfree = Z_NULL;
_z_strm.opaque = Z_NULL;
_z_strm.next_in = Z_NULL;
_z_strm.avail_in = 0;
z_ret = inflateInit(&_z_strm);
if (z_ret != Z_OK) {
THROW("zlib decoder init failed, error %d", z_ret);
}
static SpiceZlibDecoderOps decoder_ops = {
op_decode,
};
ops = &decoder_ops;
}
ZlibDecoder::~ZlibDecoder()
{
inflateEnd(&_z_strm);
}
void ZlibDecoder::decode(uint8_t *data, int data_size, uint8_t *dest, int dest_size)
{
int z_ret;
inflateReset(&_z_strm);
_z_strm.next_in = data;
_z_strm.avail_in = data_size;
_z_strm.next_out = dest;
_z_strm.avail_out = dest_size;
z_ret = inflate(&_z_strm, Z_FINISH);
if (z_ret != Z_STREAM_END) {
THROW("zlib inflate failed, error %d", z_ret);
}
}

41
client/zlib_decoder.h Normal file
View File

@ -0,0 +1,41 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
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/>.
*/
#ifndef _H_ZLIB_DECODER
#define _H_ZLIB_DECODER
#include "common.h"
#include "canvas_base.h"
#define ZLIB_WINAPI
#include <zlib.h>
class ZlibDecoder : public SpiceZlibDecoder {
public:
ZlibDecoder();
~ZlibDecoder();
void decode(uint8_t *data, int data_size, uint8_t *dest, int dest_size);
private:
z_stream _z_strm;
};
#endif

View File

@ -186,6 +186,7 @@ typedef struct CanvasBase {
LzData lz_data;
GlzData glz_data;
SpiceJpegDecoder* jpeg;
SpiceZlibDecoder* zlib;
void *usr_data;
spice_destroy_fn_t usr_data_destroy;
@ -817,6 +818,21 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
return lz_data->decode_data.out_surface;
}
static pixman_image_t *canvas_get_glz_rgb_common(CanvasBase *canvas, uint8_t *data,
int want_original)
{
if (canvas->glz_data.decoder == NULL) {
CANVAS_ERROR("glz not supported");
}
canvas->glz_data.decoder->ops->decode(canvas->glz_data.decoder,
data, NULL,
&canvas->glz_data.decode_data);
/* global_decode calls alloc_lz_image, which sets canvas->glz_data.surface */
return (canvas->glz_data.decode_data.out_surface);
}
// don't handle plts since bitmaps with plt can be decoded globally to RGB32 (because
// same byte sequence can be transformed to different RGB pixels by different plts)
static pixman_image_t *canvas_get_glz(CanvasBase *canvas, LZImage *image,
@ -827,15 +843,25 @@ static pixman_image_t *canvas_get_glz(CanvasBase *canvas, LZImage *image,
canvas->glz_data.decode_data.dc = canvas->dc;
#endif
if (canvas->glz_data.decoder == NULL) {
CANVAS_ERROR("glz not supported");
return canvas_get_glz_rgb_common(canvas, image->lz_rgb.data, want_original);
}
static pixman_image_t *canvas_get_zlib_glz_rgb(CanvasBase *canvas, SpiceZlibGlzRGBImage *image,
int want_original)
{
uint8_t *glz_data;
pixman_image_t *surface;
if (canvas->zlib == NULL) {
CANVAS_ERROR("zlib not supported");
}
canvas->glz_data.decoder->ops->decode(canvas->glz_data.decoder,
image->lz_rgb.data, NULL,
&canvas->glz_data.decode_data);
/* global_decode calls alloc_lz_image, which sets canvas->glz_data.surface */
return (canvas->glz_data.decode_data.out_surface);
glz_data = (uint8_t*)spice_malloc(image->zlib_glz.glz_data_size);
canvas->zlib->ops->decode(canvas->zlib, image->zlib_glz.data, image->zlib_glz.data_size,
glz_data, image->zlib_glz.glz_data_size);
surface = canvas_get_glz_rgb_common(canvas, glz_data, want_original);
free(glz_data);
return surface;
}
//#define DEBUG_DUMP_BITMAP
@ -1025,7 +1051,8 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
#ifdef SW_CANVAS_CACHE
!(descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME) &&
#endif
(descriptor->type != SPICE_IMAGE_TYPE_GLZ_RGB)) {
(descriptor->type != SPICE_IMAGE_TYPE_GLZ_RGB) &&
(descriptor->type != SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB)) {
return NULL;
}
@ -1067,8 +1094,12 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
surface = canvas_get_glz(canvas, image, want_original);
break;
}
case SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB: {
SpiceZlibGlzRGBImage *image = (SpiceZlibGlzRGBImage *)descriptor;
surface = canvas_get_zlib_glz_rgb(canvas, image, want_original);
break;
}
#endif
case SPICE_IMAGE_TYPE_FROM_CACHE:
surface = canvas->bits_cache->ops->get(canvas->bits_cache, descriptor->id);
break;
@ -3305,6 +3336,7 @@ static int canvas_base_init(CanvasBase *canvas, SpiceCanvasOps *ops,
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
#endif
@ -3339,6 +3371,7 @@ static int canvas_base_init(CanvasBase *canvas, SpiceCanvasOps *ops,
canvas->surfaces = surfaces;
canvas->glz_data.decoder = glz_decoder;
canvas->jpeg = jpeg_decoder;
canvas->zlib = zlib_decoder;
canvas->format = format;

View File

@ -32,6 +32,7 @@ typedef struct _SpiceImageSurfaces SpiceImageSurfaces;
typedef struct _SpicePaletteCache SpicePaletteCache;
typedef struct _SpiceGlzDecoder SpiceGlzDecoder;
typedef struct _SpiceJpegDecoder SpiceJpegDecoder;
typedef struct _SpiceZlibDecoder SpiceZlibDecoder;
typedef struct _SpiceVirtMapping SpiceVirtMapping;
typedef struct _SpiceCanvas SpiceCanvas;
@ -107,6 +108,18 @@ struct _SpiceJpegDecoder {
SpiceJpegDecoderOps *ops;
};
typedef struct {
void (*decode)(SpiceZlibDecoder *decoder,
uint8_t *data,
int data_size,
uint8_t *dest,
int dest_size);
} SpiceZlibDecoderOps;
struct _SpiceZlibDecoder {
SpiceZlibDecoderOps *ops;
};
typedef struct {
void *(*get_virt)(SpiceVirtMapping *mapping, unsigned long addr, uint32_t add_size);
void (*validate_virt)(SpiceVirtMapping *mapping, unsigned long virt,

View File

@ -1851,6 +1851,7 @@ SpiceCanvas *gdi_canvas_create(int width, int height,
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
)
{
GdiCanvas *canvas;
@ -1870,7 +1871,8 @@ SpiceCanvas *gdi_canvas_create(int width, int height,
#endif
, surfaces
, glz_decoder
, jpeg_decoder);
, jpeg_decoder
, zlib_decoder);
canvas->dc = dc;
canvas->lock = lock;
return (SpiceCanvas *)canvas;

View File

@ -32,7 +32,8 @@ SpiceCanvas *gdi_canvas_create(int width, int height,
SpicePaletteCache *palette_cache,
SpiceImageSurfaces *surfaces,
SpiceGlzDecoder *glz_decoder,
SpiceJpegDecoder *jpeg_decoder);
SpiceJpegDecoder *jpeg_decoder,
SpiceZlibDecoder *zlib_decoder);
void gdi_canvas_init();

View File

@ -817,6 +817,7 @@ SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
#endif
@ -845,6 +846,7 @@ SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, virt_mapping
#endif

View File

@ -31,6 +31,7 @@ SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
#endif

View File

@ -1172,6 +1172,7 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
#endif
@ -1200,6 +1201,7 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, virt_mapping
#endif
@ -1222,6 +1224,7 @@ SpiceCanvas *canvas_create(int width, int height, uint32_t format
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
#endif
@ -1242,6 +1245,7 @@ SpiceCanvas *canvas_create(int width, int height, uint32_t format
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, virt_mapping
#endif
@ -1259,6 +1263,7 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
#endif
@ -1279,6 +1284,7 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, virt_mapping
#endif

View File

@ -36,6 +36,7 @@ SpiceCanvas *canvas_create(int width, int height, uint32_t format
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
#endif
@ -51,6 +52,7 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
#ifndef SW_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
#endif

View File

@ -234,6 +234,9 @@ AC_CHECK_LIB(jpeg, jpeg_destroy_decompress,
AC_MSG_ERROR([libjpeg not found]))
AC_SUBST(JPEG_LIBS)
AC_CHECK_LIB(z, deflate, Z_LIBS='-lz', AC_MSG_ERROR([zlib not found]))
AC_SUBST(Z_LIBS)
dnl ===========================================================================
dnl check compiler flags

View File

@ -61,6 +61,7 @@ libspice_server_la_LIBADD = \
$(CELT051_LIBS) \
$(SLIRP_LIBS) \
$(LIBRT) \
$(Z_LIBS) \
$(NULL)
if SUPPORT_TUNNEL
@ -105,6 +106,8 @@ libspice_server_la_SOURCES = \
generated_demarshallers.c \
generated_marshallers.c \
generated_marshallers.h \
zlib_encoder.c \
zlib_encoder.h \
$(TUNNEL_SRCS) \
$(COMMON_SRCS) \
$(NULL)

View File

@ -53,6 +53,7 @@
#include "marshaller.h"
#include "demarshallers.h"
#include "generated_marshallers.h"
#include "zlib_encoder.h"
//#define COMPRESS_STAT
//#define DUMP_BITMAP
@ -94,6 +95,9 @@
#define RED_COMPRESS_BUF_SIZE (1024 * 64)
#define ZLIB_DEFAULT_COMPRESSION_LEVEL 3
#define MIN_GLZ_SIZE_FOR_ZLIB 100
typedef int64_t red_time_t;
static inline red_time_t timespec_to_red_time(struct timespec *time)
@ -172,6 +176,7 @@ static const char *lz_stat_name = "lz";
static const char *glz_stat_name = "glz";
static const char *quic_stat_name = "quic";
static const char *jpeg_stat_name = "jpeg";
static const char *zlib_stat_name = "zlib_glz";
static inline void stat_compress_init(stat_info_t *info, const char *name)
{
@ -468,6 +473,7 @@ typedef struct __attribute__ ((__packed__)) RedImage {
SpiceLZPLTData lz_plt;
SpiceSurface surface;
SpiceJPEGData jpeg;
SpiceZlibGlzRGBData zlib_glz;
};
} RedImage;
@ -562,6 +568,10 @@ typedef struct {
int input_bufs_pos;
RedCompressBuf *input_bufs[2];
} unstable_lines_data;
struct {
RedCompressBuf* next;
int size_left;
} compressed_data; // for encoding data that was already compressed by another method
} u;
char message_buf[512];
} EncoderData;
@ -586,6 +596,11 @@ typedef struct {
EncoderData data;
} JpegData;
typedef struct {
ZlibEncoderUsrContext usr;
EncoderData data;
} ZlibData;
/**********************************/
/* LZ dictionary related entities */
/**********************************/
@ -671,6 +686,8 @@ struct DisplayChannel {
int enable_jpeg;
int jpeg_quality;
int enable_zlib_glz_wrap;
int zlib_level;
#ifdef RED_STATISTICS
StatNodeRef stat;
uint64_t *cache_hits_counter;
@ -682,6 +699,7 @@ struct DisplayChannel {
stat_info_t glz_stat;
stat_info_t quic_stat;
stat_info_t jpeg_stat;
stat_info_t zlib_glz_stat;
#endif
};
@ -953,6 +971,9 @@ typedef struct RedWorker {
JpegData jpeg_data;
JpegEncoderContext *jpeg;
ZlibData zlib_data;
ZlibEncoder *zlib;
#ifdef PIPE_DEBUG
uint32_t last_id;
@ -1027,9 +1048,16 @@ static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_i
#ifdef COMPRESS_STAT
static void print_compress_stats(DisplayChannel *display_channel)
{
uint64_t glz_enc_size;
if (!display_channel) {
return;
}
glz_enc_size = display_channel->enable_zlib_glz_wrap ?
display_channel->zlib_glz_stat.comp_size :
display_channel->glz_stat.comp_size;
red_printf("==> Compression stats for display %u", display_channel->base.id);
red_printf("Method \t count \torig_size(MB)\tenc_size(MB)\tenc_time(s)");
red_printf("QUIC \t%8d\t%13.2f\t%12.2f\t%12.2f",
@ -1044,6 +1072,12 @@ static void print_compress_stats(DisplayChannel *display_channel)
stat_byte_to_mega(display_channel->glz_stat.comp_size),
stat_cpu_time_to_sec(display_channel->glz_stat.total)
);
red_printf("ZLIB GLZ \t%8d\t%13.2f\t%12.2f\t%12.2f",
display_channel->zlib_glz_stat.count,
stat_byte_to_mega(display_channel->zlib_glz_stat.orig_size),
stat_byte_to_mega(display_channel->zlib_glz_stat.comp_size),
stat_cpu_time_to_sec(display_channel->zlib_glz_stat.total)
);
red_printf("LZ \t%8d\t%13.2f\t%12.2f\t%12.2f",
display_channel->lz_stat.count,
stat_byte_to_mega(display_channel->lz_stat.orig_size),
@ -1066,11 +1100,12 @@ static void print_compress_stats(DisplayChannel *display_channel)
display_channel->quic_stat.orig_size +
display_channel->jpeg_stat.orig_size),
stat_byte_to_mega(display_channel->lz_stat.comp_size +
display_channel->glz_stat.comp_size +
glz_enc_size +
display_channel->quic_stat.comp_size +
display_channel->jpeg_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)
);
@ -5775,6 +5810,12 @@ static int jpeg_usr_more_space(JpegEncoderUsrContext *usr, uint8_t **io_ptr)
return (encoder_usr_more_space(usr_data, (uint32_t **)io_ptr) << 2);
}
static int zlib_usr_more_space(ZlibEncoderUsrContext *usr, uint8_t **io_ptr)
{
EncoderData *usr_data = &(((ZlibData *)usr)->data);
return (encoder_usr_more_space(usr_data, (uint32_t **)io_ptr) << 2);
}
static inline int encoder_usr_more_lines(EncoderData *enc_data, uint8_t **lines)
{
uint32_t data_size;
@ -5927,6 +5968,27 @@ static int jpeg_usr_no_more_lines(JpegEncoderUsrContext *usr, uint8_t **lines)
return 0;
}
static int zlib_usr_more_input(ZlibEncoderUsrContext *usr, uint8_t** input)
{
EncoderData *usr_data = &(((ZlibData *)usr)->data);
int buf_size;
if (!usr_data->u.compressed_data.next) {
ASSERT(usr_data->u.compressed_data.size_left == 0);
return 0;
}
*input = (uint8_t*)usr_data->u.compressed_data.next->buf;
buf_size = MIN(sizeof(usr_data->u.compressed_data.next->buf),
usr_data->u.compressed_data.size_left);
usr_data->u.compressed_data.next = usr_data->u.compressed_data.next->send_next;
usr_data->u.compressed_data.size_left -= buf_size;
return buf_size;
}
static void glz_usr_free_image(GlzEncoderUsrContext *usr, GlzUsrImageContext *image)
{
GlzData *lz_data = (GlzData *)usr;
@ -6001,6 +6063,18 @@ static inline void red_init_jpeg(RedWorker *worker)
}
}
static inline void red_init_zlib(RedWorker *worker)
{
worker->zlib_data.usr.more_space = zlib_usr_more_space;
worker->zlib_data.usr.more_input = zlib_usr_more_input;
worker->zlib = zlib_encoder_create(&worker->zlib_data.usr, ZLIB_DEFAULT_COMPRESSION_LEVEL);
if (!worker->zlib) {
PANIC("create zlib encoder failed");
}
}
#ifdef __GNUC__
#define ATTR_PACKED __attribute__ ((__packed__))
#else
@ -6204,12 +6278,14 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
#endif
ASSERT(BITMAP_FMT_IS_RGB[src->format]);
GlzData *glz_data = &display_channel->glz_data;
ZlibData *zlib_data;
LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
RedGlzDrawable *glz_drawable;
GlzDrawableInstanceItem *glz_drawable_instance;
uint8_t *lines;
unsigned int num_lines;
int size;
int glz_size;
int zlib_size;
glz_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
glz_data->data.bufs_head = glz_data->data.bufs_tail;
@ -6241,21 +6317,67 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
num_lines = 0;
}
size = glz_encode(display_channel->glz, type, src->x, src->y,
(src->flags & QXL_BITMAP_TOP_DOWN), lines, num_lines,
src->stride, (uint8_t*)glz_data->data.bufs_head->buf,
sizeof(glz_data->data.bufs_head->buf),
glz_drawable_instance,
&glz_drawable_instance->glz_instance);
glz_size = glz_encode(display_channel->glz, type, src->x, src->y,
(src->flags & QXL_BITMAP_TOP_DOWN), lines, num_lines,
src->stride, (uint8_t*)glz_data->data.bufs_head->buf,
sizeof(glz_data->data.bufs_head->buf),
glz_drawable_instance,
&glz_drawable_instance->glz_instance);
stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y, glz_size);
if (!display_channel->enable_zlib_glz_wrap || (glz_size < MIN_GLZ_SIZE_FOR_ZLIB)) {
goto glz;
}
#ifdef COMPRESS_STAT
start_time = stat_now();
#endif
zlib_data = &worker->zlib_data;
zlib_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
zlib_data->data.bufs_head = zlib_data->data.bufs_tail;
if (!zlib_data->data.bufs_head) {
red_printf("failed to allocate zlib compress buffer");
goto glz;
}
zlib_data->data.bufs_head->send_next = NULL;
zlib_data->data.display_channel = display_channel;
zlib_data->data.u.compressed_data.next = glz_data->data.bufs_head;
zlib_data->data.u.compressed_data.size_left = glz_size;
zlib_size = zlib_encode(worker->zlib, display_channel->zlib_level,
glz_size, (uint8_t*)zlib_data->data.bufs_head->buf,
sizeof(zlib_data->data.bufs_head->buf));
// the compressed buffer is bigger than the original data
if (zlib_size >= glz_size) {
while (zlib_data->data.bufs_head) {
RedCompressBuf *buf = zlib_data->data.bufs_head;
zlib_data->data.bufs_head = buf->send_next;
red_display_free_compress_buf(display_channel, buf);
}
goto glz;
}
dest->descriptor.type = SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB;
dest->zlib_glz.glz_data_size = glz_size;
dest->zlib_glz.data_size = zlib_size;
o_comp_data->comp_buf = zlib_data->data.bufs_head;
o_comp_data->comp_buf_size = zlib_size;
stat_compress_add(&display_channel->zlib_glz_stat, start_time, glz_size, zlib_size);
return TRUE;
glz:
dest->descriptor.type = SPICE_IMAGE_TYPE_GLZ_RGB;
dest->lz_rgb.data_size = size;
dest->lz_rgb.data_size = glz_size;
o_comp_data->comp_buf = glz_data->data.bufs_head;
o_comp_data->comp_buf_size = size;
o_comp_data->comp_buf_size = glz_size;
stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y,
size);
return TRUE;
}
@ -9592,7 +9714,7 @@ static SpiceCanvas *create_ogl_context_common(RedWorker *worker, OGLCtx *ctx, ui
oglctx_make_current(ctx);
if (!(canvas = gl_canvas_create(width, height, depth, &worker->image_cache.base,
&worker->image_surfaces, NULL, NULL,
&worker->image_surfaces, NULL, NULL, NULL,
&worker->preload_group_virt_mapping))) {
return NULL;
}
@ -9650,7 +9772,7 @@ static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *sur
canvas = canvas_create_for_data(width, height, format,
line_0, stride,
&worker->image_cache.base,
&worker->image_surfaces, NULL, NULL,
&worker->image_surfaces, NULL, NULL, NULL,
&worker->preload_group_virt_mapping);
surface->context.top_down = TRUE;
surface->context.canvas_draws_on_surface = TRUE;
@ -10459,6 +10581,9 @@ static void handle_new_display_channel(RedWorker *worker, RedsStreamContext *pee
display_channel->enable_jpeg = IS_LOW_BANDWIDTH();
display_channel->jpeg_quality = 85;
display_channel->enable_zlib_glz_wrap = IS_LOW_BANDWIDTH();
display_channel->zlib_level = ZLIB_DEFAULT_COMPRESSION_LEVEL;
red_ref_channel((RedChannel*)display_channel);
on_new_display_channel(worker);
red_unref_channel((RedChannel*)display_channel);
@ -10467,6 +10592,7 @@ static void handle_new_display_channel(RedWorker *worker, RedsStreamContext *pee
stat_compress_init(&display_channel->glz_stat, glz_stat_name);
stat_compress_init(&display_channel->quic_stat, quic_stat_name);
stat_compress_init(&display_channel->jpeg_stat, jpeg_stat_name);
stat_compress_init(&display_channel->zlib_glz_stat, zlib_stat_name);
}
static void red_disconnect_cursor(RedChannel *channel)
@ -11017,6 +11143,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
stat_reset(&worker->display_channel->lz_stat);
stat_reset(&worker->display_channel->glz_stat);
stat_reset(&worker->display_channel->jpeg_stat);
stat_reset(&worker->display_channel->zlib_glz_stat);
}
#endif
break;
@ -11180,6 +11307,7 @@ void *red_worker_main(void *arg)
red_init_quic(&worker);
red_init_lz(&worker);
red_init_jpeg(&worker);
red_init_zlib(&worker);
worker.epoll_timeout = INF_EPOLL_WAIT;
for (;;) {
struct epoll_event events[MAX_EPOLL_SOURCES];

104
server/zlib_encoder.c Normal file
View File

@ -0,0 +1,104 @@
#include "red_common.h"
#include "zlib_encoder.h"
#include <zlib.h>
struct ZlibEncoder {
ZlibEncoderUsrContext *usr;
z_stream strm;
int last_level;
};
ZlibEncoder* zlib_encoder_create(ZlibEncoderUsrContext *usr, int level)
{
ZlibEncoder *enc;
int z_ret;
if (!usr->more_space || !usr->more_input) {
return NULL;
}
enc = spice_new0(ZlibEncoder, 1);
enc->usr = usr;
enc->strm.zalloc = Z_NULL;
enc->strm.zfree = Z_NULL;
enc->strm.opaque = Z_NULL;
z_ret = deflateInit(&enc->strm, level);
enc->last_level = level;
if (z_ret != Z_OK) {
red_printf("zlib error");
free(enc);
return NULL;
}
return enc;
}
void zlib_encoder_destroy(ZlibEncoder *encoder)
{
deflateEnd(&encoder->strm);
free(encoder);
}
/* returns the total size of the encoded data */
int zlib_encode(ZlibEncoder *zlib, int level, int input_size,
uint8_t *io_ptr, unsigned int num_io_bytes)
{
int flush;
int enc_size = 0;
int out_size = 0;
int z_ret;
z_ret = deflateReset(&zlib->strm);
if (z_ret != Z_OK) {
red_error("deflateReset failed");
}
zlib->strm.next_out = io_ptr;
zlib->strm.avail_out = num_io_bytes;
if (level != zlib->last_level) {
if (zlib->strm.avail_out == 0) {
zlib->strm.avail_out = zlib->usr->more_space(zlib->usr, &zlib->strm.next_out);
if (zlib->strm.avail_out == 0) {
red_error("not enough space");
}
}
z_ret = deflateParams(&zlib->strm, level, Z_DEFAULT_STRATEGY);
if (z_ret != Z_OK) {
red_error("deflateParams failed");
}
zlib->last_level = level;
}
do {
zlib->strm.avail_in = zlib->usr->more_input(zlib->usr, &zlib->strm.next_in);
if (zlib->strm.avail_in <= 0) {
red_error("more input failed\n");
}
enc_size += zlib->strm.avail_in;
flush = (enc_size == input_size) ? Z_FINISH : Z_NO_FLUSH;
while (1) {
int deflate_size = zlib->strm.avail_out;
z_ret = deflate(&zlib->strm, flush);
ASSERT(z_ret != Z_STREAM_ERROR);
out_size += deflate_size - zlib->strm.avail_out;
if (zlib->strm.avail_out) {
break;
}
zlib->strm.avail_out = zlib->usr->more_space(zlib->usr, &zlib->strm.next_out);
if (zlib->strm.avail_out == 0) {
red_error("not enough space");
}
}
} while (flush != Z_FINISH);
ASSERT(z_ret == Z_STREAM_END);
return out_size;
}

47
server/zlib_encoder.h Normal file
View File

@ -0,0 +1,47 @@
/*
Copyright (C) 2009 Red Hat, Inc.
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_ZLIB_ENCODER
#define _H_ZLIB_ENCODER
typedef struct ZlibEncoder ZlibEncoder;
typedef struct ZlibEncoderUsrContext ZlibEncoderUsrContext;
struct ZlibEncoderUsrContext {
int (*more_space)(ZlibEncoderUsrContext *usr, uint8_t **io_ptr);
int (*more_input)(ZlibEncoderUsrContext *usr, uint8_t **input);
};
ZlibEncoder* zlib_encoder_create(ZlibEncoderUsrContext *usr, int level);
void zlib_encoder_destroy(ZlibEncoder *encoder);
/* returns the total size of the encoded data */
int zlib_encode(ZlibEncoder *zlib, int level, int input_size,
uint8_t *io_ptr, unsigned int num_io_bytes);
#endif

View File

@ -293,6 +293,7 @@ enum8 image_type {
SURFACE,
JPEG,
FROM_CACHE_LOSSLESS,
ZLIB_GLZ_RGB,
};
flags8 image_flags {
@ -470,6 +471,12 @@ struct LZPLTData {
uint8 data[data_size] @end @nomarshal;
};
struct ZlibGlzRGBData {
uint32 glz_data_size;
uint32 data_size;
uint8 data[data_size] @end @nomarshal;
} @ctype(SpiceZlibGlzRGBData);
struct Surface {
uint32 surface_id;
};
@ -491,6 +498,8 @@ struct Image {
BinaryData binary_data @ctype(SpiceQUICData);
case LZ_PLT:
LZPLTData lzplt_data @ctype(SpiceLZPLTData);
case ZLIB_GLZ_RGB:
ZlibGlzRGBData zlib_glz_data @ctype(SpiceZlibGlzRGBData);
case SURFACE:
Surface surface_data;
} u @end;