mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-05 13:49:26 +00:00
applying zlib compression over glz on WAN connection
This commit is contained in:
parent
cfc1e95bda
commit
25bb38f643
@ -111,6 +111,8 @@ RED_COMMON_SRCS = \
|
||||
threads.h \
|
||||
utils.cpp \
|
||||
utils.h \
|
||||
zlib_decoder.cpp \
|
||||
zlib_decoder.h \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = $(spice_built_sources)
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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=""$(SPICE_LIBS)\lib""
|
||||
@ -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=""$(SPICE_LIBS)\lib""
|
||||
@ -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"
|
||||
|
||||
@ -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
58
client/zlib_decoder.cpp
Normal 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
41
client/zlib_decoder.h
Normal 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
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
104
server/zlib_encoder.c
Normal 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
47
server/zlib_encoder.h
Normal 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
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user