From: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> Author: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> --- server/Makefile.am | 2 + server/dcc-encoders.c | 402 ++++++++++++++++++++++++++++++++++ server/dcc-encoders.h | 145 +++++++++++++ server/display-channel.c | 6 +- server/display-channel.h | 66 ++---- server/red_worker.c | 555 +++-------------------------------------------- 6 files changed, 597 insertions(+), 579 deletions(-) create mode 100644 server/dcc-encoders.c create mode 100644 server/dcc-encoders.h diff --git a/server/Makefile.am b/server/Makefile.am index 52703c9..5907dd2 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -138,6 +138,8 @@ libspice_server_la_SOURCES = \ utils.h \ stream.c \ stream.h \ + dcc-encoders.c \ + dcc-encoders.h \ $(NULL) if HAVE_GL diff --git a/server/dcc-encoders.c b/server/dcc-encoders.c new file mode 100644 index 0000000..9094f99 --- /dev/null +++ b/server/dcc-encoders.c @@ -0,0 +1,402 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2009-2015 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/>. +*/ +#include <glib.h> +#include <setjmp.h> + +#include "dcc-encoders.h" +#include "display-channel.h" + +#define ZLIB_DEFAULT_COMPRESSION_LEVEL 3 + +static SPICE_GNUC_NORETURN SPICE_GNUC_PRINTF(2, 3) void +quic_usr_error(QuicUsrContext *usr, const char *fmt, ...) +{ + EncoderData *usr_data = &(((QuicData *)usr)->data); + va_list ap; + + va_start(ap, fmt); + vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); + va_end(ap); + spice_critical("%s", usr_data->message_buf); + + longjmp(usr_data->jmp_env, 1); +} + +static SPICE_GNUC_NORETURN SPICE_GNUC_PRINTF(2, 3) void +lz_usr_error(LzUsrContext *usr, const char *fmt, ...) +{ + EncoderData *usr_data = &(((LzData *)usr)->data); + va_list ap; + + va_start(ap, fmt); + vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); + va_end(ap); + spice_critical("%s", usr_data->message_buf); + + longjmp(usr_data->jmp_env, 1); +} + +static SPICE_GNUC_PRINTF(2, 3) void +glz_usr_error(GlzEncoderUsrContext *usr, const char *fmt, ...) +{ + EncoderData *usr_data = &(((GlzData *)usr)->data); + va_list ap; + + va_start(ap, fmt); + vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); + va_end(ap); + + spice_critical("%s", usr_data->message_buf); // if global lz fails in the middle + // the consequences are not predictable since the window + // can turn to be unsynchronized between the server and + // and the client +} + +static SPICE_GNUC_PRINTF(2, 3) void +quic_usr_warn(QuicUsrContext *usr, const char *fmt, ...) +{ + EncoderData *usr_data = &(((QuicData *)usr)->data); + va_list ap; + + va_start(ap, fmt); + vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); + va_end(ap); + spice_warning("%s", usr_data->message_buf); +} + +static SPICE_GNUC_PRINTF(2, 3) void +lz_usr_warn(LzUsrContext *usr, const char *fmt, ...) +{ + EncoderData *usr_data = &(((LzData *)usr)->data); + va_list ap; + + va_start(ap, fmt); + vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); + va_end(ap); + spice_warning("%s", usr_data->message_buf); +} + +static SPICE_GNUC_PRINTF(2, 3) void +glz_usr_warn(GlzEncoderUsrContext *usr, const char *fmt, ...) +{ + EncoderData *usr_data = &(((GlzData *)usr)->data); + va_list ap; + + va_start(ap, fmt); + vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); + va_end(ap); + spice_warning("%s", usr_data->message_buf); +} + +static void *quic_usr_malloc(QuicUsrContext *usr, int size) +{ + return spice_malloc(size); +} + +static void *lz_usr_malloc(LzUsrContext *usr, int size) +{ + return spice_malloc(size); +} + +static void *glz_usr_malloc(GlzEncoderUsrContext *usr, int size) +{ + return spice_malloc(size); +} + +static void quic_usr_free(QuicUsrContext *usr, void *ptr) +{ + free(ptr); +} + +static void lz_usr_free(LzUsrContext *usr, void *ptr) +{ + free(ptr); +} + +static void glz_usr_free(GlzEncoderUsrContext *usr, void *ptr) +{ + free(ptr); +} + +RedCompressBuf* compress_buf_new(void) +{ + RedCompressBuf *buf = g_slice_new(RedCompressBuf); + + buf->send_next = NULL; + + return buf; +} + +void compress_buf_free(RedCompressBuf *buf) +{ + g_slice_free(RedCompressBuf, buf); +} + +static int encoder_usr_more_space(EncoderData *enc_data, uint8_t **io_ptr) +{ + RedCompressBuf *buf; + + buf = compress_buf_new(); + enc_data->bufs_tail->send_next = buf; + enc_data->bufs_tail = buf; + buf->send_next = NULL; + *io_ptr = buf->buf; + return sizeof(buf->buf); +} + +static int quic_usr_more_space(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed) +{ + EncoderData *usr_data = &(((QuicData *)usr)->data); + return encoder_usr_more_space(usr_data, (uint8_t **)io_ptr) / sizeof(uint32_t); +} + +static int lz_usr_more_space(LzUsrContext *usr, uint8_t **io_ptr) +{ + EncoderData *usr_data = &(((LzData *)usr)->data); + return encoder_usr_more_space(usr_data, io_ptr); +} + +static int glz_usr_more_space(GlzEncoderUsrContext *usr, uint8_t **io_ptr) +{ + EncoderData *usr_data = &(((GlzData *)usr)->data); + return encoder_usr_more_space(usr_data, io_ptr); +} + +static int jpeg_usr_more_space(JpegEncoderUsrContext *usr, uint8_t **io_ptr) +{ + EncoderData *usr_data = &(((JpegData *)usr)->data); + return encoder_usr_more_space(usr_data, io_ptr); +} + +#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); + return encoder_usr_more_space(usr_data, io_ptr); +} + +static inline int encoder_usr_more_lines(EncoderData *enc_data, uint8_t **lines) +{ + struct SpiceChunk *chunk; + + if (enc_data->u.lines_data.reverse) { + if (!(enc_data->u.lines_data.next >= 0)) { + return 0; + } + } else { + if (!(enc_data->u.lines_data.next < enc_data->u.lines_data.chunks->num_chunks)) { + return 0; + } + } + + chunk = &enc_data->u.lines_data.chunks->chunk[enc_data->u.lines_data.next]; + if (chunk->len % enc_data->u.lines_data.stride) { + return 0; + } + + if (enc_data->u.lines_data.reverse) { + enc_data->u.lines_data.next--; + *lines = chunk->data + chunk->len - enc_data->u.lines_data.stride; + } else { + enc_data->u.lines_data.next++; + *lines = chunk->data; + } + + return chunk->len / enc_data->u.lines_data.stride; +} + +static int quic_usr_more_lines(QuicUsrContext *usr, uint8_t **lines) +{ + EncoderData *usr_data = &(((QuicData *)usr)->data); + return encoder_usr_more_lines(usr_data, lines); +} + +static int lz_usr_more_lines(LzUsrContext *usr, uint8_t **lines) +{ + EncoderData *usr_data = &(((LzData *)usr)->data); + return encoder_usr_more_lines(usr_data, lines); +} + +static int glz_usr_more_lines(GlzEncoderUsrContext *usr, uint8_t **lines) +{ + EncoderData *usr_data = &(((GlzData *)usr)->data); + return encoder_usr_more_lines(usr_data, lines); +} + +static int jpeg_usr_more_lines(JpegEncoderUsrContext *usr, uint8_t **lines) +{ + EncoderData *usr_data = &(((JpegData *)usr)->data); + 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); + int buf_size; + + if (!usr_data->u.compressed_data.next) { + spice_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 dcc_init_quic(DisplayChannelClient *dcc) +{ + dcc->quic_data.usr.error = quic_usr_error; + dcc->quic_data.usr.warn = quic_usr_warn; + dcc->quic_data.usr.info = quic_usr_warn; + dcc->quic_data.usr.malloc = quic_usr_malloc; + dcc->quic_data.usr.free = quic_usr_free; + dcc->quic_data.usr.more_space = quic_usr_more_space; + dcc->quic_data.usr.more_lines = quic_usr_more_lines; + + dcc->quic = quic_create(&dcc->quic_data.usr); + spice_warn_if_fail(dcc->quic); +} + +static void dcc_init_lz(DisplayChannelClient *dcc) +{ + dcc->lz_data.usr.error = lz_usr_error; + dcc->lz_data.usr.warn = lz_usr_warn; + dcc->lz_data.usr.info = lz_usr_warn; + dcc->lz_data.usr.malloc = lz_usr_malloc; + dcc->lz_data.usr.free = lz_usr_free; + dcc->lz_data.usr.more_space = lz_usr_more_space; + dcc->lz_data.usr.more_lines = lz_usr_more_lines; + + dcc->lz = lz_create(&dcc->lz_data.usr); + spice_warn_if_fail(dcc->lz); +} + +static void glz_usr_free_image(GlzEncoderUsrContext *usr, GlzUsrImageContext *image) +{ + GlzData *lz_data = (GlzData *)usr; + GlzDrawableInstanceItem *glz_drawable_instance = (GlzDrawableInstanceItem *)image; + DisplayChannelClient *drawable_cc = glz_drawable_instance->red_glz_drawable->dcc; + DisplayChannelClient *this_cc = SPICE_CONTAINEROF(lz_data, DisplayChannelClient, glz_data); + if (this_cc == drawable_cc) { + dcc_free_glz_drawable_instance(drawable_cc, glz_drawable_instance); + } else { + /* The glz dictionary is shared between all DisplayChannelClient + * instances that belong to the same client, and glz_usr_free_image + * can be called by the dictionary code + * (glz_dictionary_window_remove_head). Thus this function can be + * called from any DisplayChannelClient thread, hence the need for + * this check. + */ + pthread_mutex_lock(&drawable_cc->glz_drawables_inst_to_free_lock); + ring_add_before(&glz_drawable_instance->free_link, + &drawable_cc->glz_drawables_inst_to_free); + pthread_mutex_unlock(&drawable_cc->glz_drawables_inst_to_free_lock); + } +} + +static void dcc_init_glz_data(DisplayChannelClient *dcc) +{ + dcc->glz_data.usr.error = glz_usr_error; + dcc->glz_data.usr.warn = glz_usr_warn; + dcc->glz_data.usr.info = glz_usr_warn; + dcc->glz_data.usr.malloc = glz_usr_malloc; + dcc->glz_data.usr.free = glz_usr_free; + dcc->glz_data.usr.more_space = glz_usr_more_space; + dcc->glz_data.usr.more_lines = glz_usr_more_lines; + dcc->glz_data.usr.free_image = glz_usr_free_image; +} + +static void dcc_init_jpeg(DisplayChannelClient *dcc) +{ + dcc->jpeg_data.usr.more_space = jpeg_usr_more_space; + dcc->jpeg_data.usr.more_lines = jpeg_usr_more_lines; + + dcc->jpeg = jpeg_encoder_create(&dcc->jpeg_data.usr); + spice_warn_if_fail(dcc->jpeg); +} + +#ifdef USE_LZ4 +static inline void dcc_init_lz4(DisplayChannelClient *dcc) +{ + dcc->lz4_data.usr.more_space = lz4_usr_more_space; + dcc->lz4_data.usr.more_lines = lz4_usr_more_lines; + + dcc->lz4 = lz4_encoder_create(&dcc->lz4_data.usr); + + spice_warn_if_fail(dcc->lz4) { +} +#endif + +static void dcc_init_zlib(DisplayChannelClient *dcc) +{ + dcc->zlib_data.usr.more_space = zlib_usr_more_space; + dcc->zlib_data.usr.more_input = zlib_usr_more_input; + + dcc->zlib = zlib_encoder_create(&dcc->zlib_data.usr, ZLIB_DEFAULT_COMPRESSION_LEVEL); + spice_warn_if_fail(dcc->zlib); +} + +void dcc_encoders_init(DisplayChannelClient *dcc) +{ + dcc_init_glz_data(dcc); + dcc_init_quic(dcc); + dcc_init_lz(dcc); + dcc_init_jpeg(dcc); +#ifdef USE_LZ4 + dcc_init_lz4(dcc); +#endif + dcc_init_zlib(dcc); + + // todo: tune level according to bandwidth + dcc->zlib_level = ZLIB_DEFAULT_COMPRESSION_LEVEL; +} + +void marshaller_add_compressed(SpiceMarshaller *m, + RedCompressBuf *comp_buf, size_t size) +{ + size_t max = size; + size_t now; + do { + spice_return_if_fail(comp_buf); + now = MIN(sizeof(comp_buf->buf), max); + max -= now; + spice_marshaller_add_ref_full(m, (uint8_t*)comp_buf->buf, now, + (spice_marshaller_item_free_func)compress_buf_free, NULL); + comp_buf = comp_buf->send_next; + } while (max); +} diff --git a/server/dcc-encoders.h b/server/dcc-encoders.h new file mode 100644 index 0000000..7785b2f --- /dev/null +++ b/server/dcc-encoders.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2009-2015 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 DCC_ENCODERS_H_ +# define DCC_ENCODERS_H_ + +#include "common/marshaller.h" +#include "common/quic.h" +#include "red_channel.h" +#include "red_parse_qxl.h" +#include "spice_image_cache.h" +#include "glz_encoder_dictionary.h" +#include "glz_encoder.h" +#include "jpeg_encoder.h" +#ifdef USE_LZ4 +#include "lz4_encoder.h" +#endif +#include "zlib_encoder.h" + +typedef struct RedCompressBuf RedCompressBuf; +typedef struct GlzDrawableInstanceItem GlzDrawableInstanceItem; + +void dcc_encoders_init (DisplayChannelClient *dcc); +void dcc_free_glz_drawable_instance (DisplayChannelClient *dcc, + GlzDrawableInstanceItem *item); +void marshaller_add_compressed (SpiceMarshaller *m, + RedCompressBuf *comp_buf, + size_t size); + +RedCompressBuf* compress_buf_new (void); +void compress_buf_free (RedCompressBuf *buf); + +struct RedCompressBuf { + uint8_t buf[64 * 1024]; + RedCompressBuf *send_next; +}; + +typedef struct GlzSharedDictionary { + RingItem base; + GlzEncDictContext *dict; + uint32_t refs; + uint8_t id; + pthread_rwlock_t encode_lock; + int migrate_freeze; + RedClient *client; // channel clients of the same client share the dict +} GlzSharedDictionary; + +typedef struct { + DisplayChannelClient *dcc; + RedCompressBuf *bufs_head; + RedCompressBuf *bufs_tail; + jmp_buf jmp_env; + union { + struct { + SpiceChunks *chunks; + int next; + int stride; + int reverse; + } 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; + +typedef struct { + QuicUsrContext usr; + EncoderData data; +} QuicData; + +typedef struct { + LzUsrContext usr; + EncoderData data; +} LzData; + +typedef struct { + JpegEncoderUsrContext usr; + EncoderData data; +} JpegData; + +#ifdef USE_LZ4 +typedef struct { + Lz4EncoderUsrContext usr; + EncoderData data; +} Lz4Data; +#endif + +typedef struct { + ZlibEncoderUsrContext usr; + EncoderData data; +} ZlibData; + +typedef struct { + GlzEncoderUsrContext usr; + EncoderData data; +} GlzData; + +#define MAX_GLZ_DRAWABLE_INSTANCES 2 + +typedef struct RedGlzDrawable RedGlzDrawable; + +/* for each qxl drawable, there may be several instances of lz drawables */ +/* TODO - reuse this stuff for the top level. I just added a second level of multiplicity + * at the Drawable by keeping a ring, so: + * Drawable -> (ring of) RedGlzDrawable -> (up to 2) GlzDrawableInstanceItem + * and it should probably (but need to be sure...) be + * Drawable -> ring of GlzDrawableInstanceItem. + */ +struct GlzDrawableInstanceItem { + RingItem glz_link; + RingItem free_link; + GlzEncDictImageContext *glz_instance; + RedGlzDrawable *red_glz_drawable; +}; + +struct RedGlzDrawable { + RingItem link; // ordered by the time it was encoded + RingItem drawable_link; + RedDrawable *red_drawable; + Drawable *drawable; + uint32_t group_id; + GlzDrawableInstanceItem instances_pool[MAX_GLZ_DRAWABLE_INSTANCES]; + Ring instances; + uint8_t instances_count; + DisplayChannelClient *dcc; +}; + + +#endif /* DCC_ENCODERS_H_ */ diff --git a/server/display-channel.c b/server/display-channel.c index 578721c..eff88cd 100644 --- a/server/display-channel.c +++ b/server/display-channel.c @@ -140,6 +140,10 @@ DisplayChannelClient *dcc_new(DisplayChannel *display, dcc->image_compression = image_compression; dcc->jpeg_state = jpeg_state; dcc->zlib_glz_state = zlib_glz_state; + // todo: tune quality according to bandwidth + dcc->jpeg_quality = 85; + + dcc_encoders_init(dcc); return dcc; } @@ -202,7 +206,7 @@ static MonitorsConfigItem *monitors_config_item_new(RedChannel* channel, return mci; } -static inline void red_monitors_config_item_add(DisplayChannelClient *dcc) +static void red_monitors_config_item_add(DisplayChannelClient *dcc) { DisplayChannel *dc = DCC_TO_DC(dcc); MonitorsConfigItem *mci; diff --git a/server/display-channel.h b/server/display-channel.h index f45860c..9b16718 100644 --- a/server/display-channel.h +++ b/server/display-channel.h @@ -30,20 +30,13 @@ #include "reds_gl_canvas.h" #endif /* USE_OPENGL */ #include "reds_sw_canvas.h" -#include "glz_encoder_dictionary.h" -#include "glz_encoder.h" #include "stat.h" #include "reds.h" #include "mjpeg_encoder.h" #include "red_memslots.h" #include "red_parse_qxl.h" #include "red_record_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" #include "red_dispatcher.h" #include "dispatcher.h" @@ -56,6 +49,7 @@ #include "utils.h" #include "tree.h" #include "stream.h" +#include "dcc-encoders.h" #define PALETTE_CACHE_HASH_SHIFT 8 #define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT) @@ -70,12 +64,6 @@ #define NUM_STREAMS 50 #define NUM_SURFACES 10000 -typedef struct RedCompressBuf RedCompressBuf; -struct RedCompressBuf { - uint8_t buf[64 * 1024]; - RedCompressBuf *send_next; -}; - typedef struct WaitForChannels { SpiceMsgWaitForChannels header; SpiceWaitForChannel buf[MAX_CACHE_CLIENTS]; @@ -88,41 +76,6 @@ typedef struct FreeList { WaitForChannels wait; } FreeList; -typedef struct GlzSharedDictionary { - RingItem base; - GlzEncDictContext *dict; - uint32_t refs; - uint8_t id; - pthread_rwlock_t encode_lock; - int migrate_freeze; - RedClient *client; // channel clients of the same client share the dict -} GlzSharedDictionary; - -typedef struct { - DisplayChannelClient *dcc; - RedCompressBuf *bufs_head; - RedCompressBuf *bufs_tail; - jmp_buf jmp_env; - union { - struct { - SpiceChunks *chunks; - int next; - int stride; - int reverse; - } 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; - -typedef struct { - GlzEncoderUsrContext usr; - EncoderData data; -} GlzData; - typedef struct DependItem { Drawable *drawable; RingItem ring_item; @@ -162,6 +115,21 @@ struct DisplayChannelClient { SpiceImageCompression image_compression; spice_wan_compression_t jpeg_state; spice_wan_compression_t zlib_glz_state; + int jpeg_quality; + int zlib_level; + + QuicData quic_data; + QuicContext *quic; + LzData lz_data; + LzContext *lz; + JpegData jpeg_data; + JpegEncoderContext *jpeg; +#ifdef USE_LZ4 + Lz4Data lz4_data; + Lz4EncoderContext *lz4; +#endif + ZlibData zlib_data; + ZlibEncoder *zlib; int expect_init; @@ -316,9 +284,7 @@ struct DisplayChannel { uint32_t renderers[RED_RENDERER_LAST]; uint32_t renderer; int enable_jpeg; - int jpeg_quality; int enable_zlib_glz_wrap; - int zlib_level; Ring current_list; // of TreeItem uint32_t current_size; diff --git a/server/red_worker.c b/server/red_worker.c index 1c99f01..6becc56 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -51,7 +51,6 @@ #include <spice/qxl_dev.h> #include "common/lz.h" #include "common/marshaller.h" -#include "common/quic.h" #include "common/rect.h" #include "common/region.h" #include "common/ring.h" @@ -83,7 +82,6 @@ #define FPS_TEST_INTERVAL 1 #define MAX_FPS 30 -#define ZLIB_DEFAULT_COMPRESSION_LEVEL 3 #define MIN_GLZ_SIZE_FOR_ZLIB 100 #define VALIDATE_SURFACE_RET(worker, surface_id) \ @@ -238,66 +236,6 @@ typedef struct ImageItem { uint8_t data[0]; } ImageItem; -typedef struct { - QuicUsrContext usr; - EncoderData data; -} QuicData; - -typedef struct { - LzUsrContext usr; - EncoderData data; -} LzData; - -typedef struct { - JpegEncoderUsrContext usr; - EncoderData data; -} JpegData; - -#ifdef USE_LZ4 -typedef struct { - Lz4EncoderUsrContext usr; - EncoderData data; -} Lz4Data; -#endif - -typedef struct { - ZlibEncoderUsrContext usr; - EncoderData data; -} ZlibData; - -/**********************************/ -/* LZ dictionary related entities */ -/**********************************/ -#define MAX_GLZ_DRAWABLE_INSTANCES 2 - -typedef struct RedGlzDrawable RedGlzDrawable; - -/* for each qxl drawable, there may be several instances of lz drawables */ -/* TODO - reuse this stuff for the top level. I just added a second level of multiplicity - * at the Drawable by keeping a ring, so: - * Drawable -> (ring of) RedGlzDrawable -> (up to 2) GlzDrawableInstanceItem - * and it should probably (but need to be sure...) be - * Drawable -> ring of GlzDrawableInstanceItem. - */ -typedef struct GlzDrawableInstanceItem { - RingItem glz_link; - RingItem free_link; - GlzEncDictImageContext *glz_instance; - RedGlzDrawable *red_glz_drawable; -} GlzDrawableInstanceItem; - -struct RedGlzDrawable { - RingItem link; // ordered by the time it was encoded - RingItem drawable_link; - RedDrawable *red_drawable; - Drawable *drawable; - uint32_t group_id; - GlzDrawableInstanceItem instances_pool[MAX_GLZ_DRAWABLE_INSTANCES]; - Ring instances; - uint8_t instances_count; - DisplayChannelClient *dcc; -}; - pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER; Ring glz_dictionary_list = {&glz_dictionary_list, &glz_dictionary_list}; @@ -327,23 +265,6 @@ typedef struct RedWorker { spice_wan_compression_t jpeg_state; spice_wan_compression_t zlib_glz_state; - QuicData quic_data; - QuicContext *quic; - - LzData lz_data; - LzContext *lz; - - JpegData jpeg_data; - JpegEncoderContext *jpeg; - -#ifdef USE_LZ4 - Lz4Data lz4_data; - Lz4EncoderContext *lz4; -#endif - - ZlibData zlib_data; - ZlibEncoder *zlib; - uint32_t process_commands_generation; #ifdef RED_WORKER_STAT stat_info_t add_stat; @@ -401,7 +322,7 @@ static void red_freeze_glz(DisplayChannelClient *dcc); static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type, uint64_t id, uint64_t* sync_data); static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc); -static void red_display_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable); +static void dcc_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable); static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surface_id, SpiceRect *area, PipeItem *pos, int can_lossy); static void display_channel_client_release_item_before_push(DisplayChannelClient *dcc, @@ -2601,7 +2522,7 @@ static bool free_one_drawable(DisplayChannel *display, int force_glz_free) RingItem *glz_item, *next_item; RedGlzDrawable *glz; DRAWABLE_FOREACH_GLZ_SAFE(drawable, glz_item, next_item, glz) { - red_display_free_glz_drawable(glz->dcc, glz); + dcc_free_glz_drawable(glz->dcc, glz); } } red_draw_drawable(display, drawable); @@ -3464,32 +3385,6 @@ static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id) red_channel_client_push(RED_CHANNEL_CLIENT(dcc)); } -static RedCompressBuf *compress_buf_new(void) -{ - return g_slice_new(RedCompressBuf); -} - -static void compress_buf_free(RedCompressBuf *buf) -{ - g_slice_free(RedCompressBuf, buf); -} - -static void marshaller_add_compressed(SpiceMarshaller *m, - RedCompressBuf *comp_buf, size_t size) -{ - size_t max = size; - size_t now; - do { - spice_return_if_fail(comp_buf); - now = MIN(sizeof(comp_buf->buf), max); - max -= now; - spice_marshaller_add_ref_full(m, (uint8_t*)comp_buf->buf, now, - (spice_marshaller_item_free_func)compress_buf_free, NULL); - comp_buf = comp_buf->send_next; - } while (max); -} - - static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable) { SpiceMsgDisplayBase base; @@ -3579,8 +3474,8 @@ static GlzDrawableInstanceItem *red_display_add_glz_drawable_instance(RedGlzDraw it is not used by Drawable). NOTE - 1) can be called only by the display channel that created the drawable 2) it is assumed that the instance was already removed from the dictionary*/ -static void red_display_free_glz_drawable_instance(DisplayChannelClient *dcc, - GlzDrawableInstanceItem *glz_drawable_instance) +void dcc_free_glz_drawable_instance(DisplayChannelClient *dcc, + GlzDrawableInstanceItem *glz_drawable_instance) { DisplayChannel *display_channel = DCC_TO_DC(dcc); RedWorker *worker = display_channel->common.worker; @@ -3632,7 +3527,7 @@ static void red_display_handle_glz_drawables_to_free(DisplayChannelClient* dcc) GlzDrawableInstanceItem *drawable_instance = SPICE_CONTAINEROF(ring_link, GlzDrawableInstanceItem, free_link); - red_display_free_glz_drawable_instance(dcc, drawable_instance); + dcc_free_glz_drawable_instance(dcc, drawable_instance); } pthread_mutex_unlock(&dcc->glz_drawables_inst_to_free_lock); } @@ -3643,14 +3538,14 @@ static void red_display_handle_glz_drawables_to_free(DisplayChannelClient* dcc) * if possible. * NOTE - the caller should prevent encoding using the dictionary during this operation */ -static void red_display_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable) +static void dcc_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable) { RingItem *head_instance = ring_get_head(&drawable->instances); int cont = (head_instance != NULL); while (cont) { if (drawable->instances_count == 1) { - /* Last instance: red_display_free_glz_drawable_instance will free the drawable */ + /* Last instance: dcc_free_glz_drawable_instance will free the drawable */ cont = FALSE; } GlzDrawableInstanceItem *instance = SPICE_CONTAINEROF(head_instance, @@ -3662,7 +3557,7 @@ static void red_display_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawa instance->glz_instance, &dcc->glz_data.usr); } - red_display_free_glz_drawable_instance(dcc, instance); + dcc_free_glz_drawable_instance(dcc, instance); if (cont) { head_instance = ring_get_head(&drawable->instances); @@ -3687,7 +3582,7 @@ static void red_display_client_clear_glz_drawables(DisplayChannelClient *dcc) RedGlzDrawable *drawable = SPICE_CONTAINEROF(ring_link, RedGlzDrawable, link); // no need to lock the to_free list, since we assured no other thread is encoding and // thus not other thread access the to_free list of the channel - red_display_free_glz_drawable(dcc, drawable); + dcc_free_glz_drawable(dcc, drawable); } pthread_rwlock_unlock(&glz_dict->encode_lock); } @@ -3723,361 +3618,13 @@ static int red_display_free_some_independent_glz_drawables(DisplayChannelClient RedGlzDrawable *glz_drawable = SPICE_CONTAINEROF(ring_link, RedGlzDrawable, link); ring_link = ring_next(&dcc->glz_drawables, ring_link); if (!glz_drawable->drawable) { - red_display_free_glz_drawable(dcc, glz_drawable); + dcc_free_glz_drawable(dcc, glz_drawable); n++; } } return n; } -/****************************************************** - * Encoders callbacks -*******************************************************/ -static SPICE_GNUC_NORETURN SPICE_GNUC_PRINTF(2, 3) void -quic_usr_error(QuicUsrContext *usr, const char *fmt, ...) -{ - EncoderData *usr_data = &(((QuicData *)usr)->data); - va_list ap; - - va_start(ap, fmt); - vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); - va_end(ap); - spice_critical("%s", usr_data->message_buf); - - longjmp(usr_data->jmp_env, 1); -} - -static SPICE_GNUC_NORETURN SPICE_GNUC_PRINTF(2, 3) void -lz_usr_error(LzUsrContext *usr, const char *fmt, ...) -{ - EncoderData *usr_data = &(((LzData *)usr)->data); - va_list ap; - - va_start(ap, fmt); - vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); - va_end(ap); - spice_critical("%s", usr_data->message_buf); - - longjmp(usr_data->jmp_env, 1); -} - -static SPICE_GNUC_PRINTF(2, 3) void glz_usr_error(GlzEncoderUsrContext *usr, const char *fmt, ...) -{ - EncoderData *usr_data = &(((GlzData *)usr)->data); - va_list ap; - - va_start(ap, fmt); - vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); - va_end(ap); - - spice_critical("%s", usr_data->message_buf); // if global lz fails in the middle - // the consequences are not predictable since the window - // can turn to be unsynchronized between the server and - // and the client -} - -static SPICE_GNUC_PRINTF(2, 3) void quic_usr_warn(QuicUsrContext *usr, const char *fmt, ...) -{ - EncoderData *usr_data = &(((QuicData *)usr)->data); - va_list ap; - - va_start(ap, fmt); - vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); - va_end(ap); - spice_warning("%s", usr_data->message_buf); -} - -static SPICE_GNUC_PRINTF(2, 3) void lz_usr_warn(LzUsrContext *usr, const char *fmt, ...) -{ - EncoderData *usr_data = &(((LzData *)usr)->data); - va_list ap; - - va_start(ap, fmt); - vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); - va_end(ap); - spice_warning("%s", usr_data->message_buf); -} - -static SPICE_GNUC_PRINTF(2, 3) void glz_usr_warn(GlzEncoderUsrContext *usr, const char *fmt, ...) -{ - EncoderData *usr_data = &(((GlzData *)usr)->data); - va_list ap; - - va_start(ap, fmt); - vsnprintf(usr_data->message_buf, sizeof(usr_data->message_buf), fmt, ap); - va_end(ap); - spice_warning("%s", usr_data->message_buf); -} - -static void *quic_usr_malloc(QuicUsrContext *usr, int size) -{ - return spice_malloc(size); -} - -static void *lz_usr_malloc(LzUsrContext *usr, int size) -{ - return spice_malloc(size); -} - -static void *glz_usr_malloc(GlzEncoderUsrContext *usr, int size) -{ - return spice_malloc(size); -} - -static void quic_usr_free(QuicUsrContext *usr, void *ptr) -{ - free(ptr); -} - -static void lz_usr_free(LzUsrContext *usr, void *ptr) -{ - free(ptr); -} - -static void glz_usr_free(GlzEncoderUsrContext *usr, void *ptr) -{ - free(ptr); -} - -static int encoder_usr_more_space(EncoderData *enc_data, uint8_t **io_ptr) -{ - RedCompressBuf *buf; - - buf = compress_buf_new(); - enc_data->bufs_tail->send_next = buf; - enc_data->bufs_tail = buf; - buf->send_next = NULL; - *io_ptr = buf->buf; - return sizeof(buf->buf); -} - -static int quic_usr_more_space(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed) -{ - EncoderData *usr_data = &(((QuicData *)usr)->data); - return encoder_usr_more_space(usr_data, (uint8_t **)io_ptr) / sizeof(uint32_t); -} - -static int lz_usr_more_space(LzUsrContext *usr, uint8_t **io_ptr) -{ - EncoderData *usr_data = &(((LzData *)usr)->data); - return encoder_usr_more_space(usr_data, io_ptr); -} - -static int glz_usr_more_space(GlzEncoderUsrContext *usr, uint8_t **io_ptr) -{ - EncoderData *usr_data = &(((GlzData *)usr)->data); - return encoder_usr_more_space(usr_data, io_ptr); -} - -static int jpeg_usr_more_space(JpegEncoderUsrContext *usr, uint8_t **io_ptr) -{ - EncoderData *usr_data = &(((JpegData *)usr)->data); - return encoder_usr_more_space(usr_data, io_ptr); -} - -#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); - return encoder_usr_more_space(usr_data, io_ptr); -} - -static inline int encoder_usr_more_lines(EncoderData *enc_data, uint8_t **lines) -{ - struct SpiceChunk *chunk; - - if (enc_data->u.lines_data.reverse) { - if (!(enc_data->u.lines_data.next >= 0)) { - return 0; - } - } else { - if (!(enc_data->u.lines_data.next < enc_data->u.lines_data.chunks->num_chunks)) { - return 0; - } - } - - chunk = &enc_data->u.lines_data.chunks->chunk[enc_data->u.lines_data.next]; - if (chunk->len % enc_data->u.lines_data.stride) { - return 0; - } - - if (enc_data->u.lines_data.reverse) { - enc_data->u.lines_data.next--; - *lines = chunk->data + chunk->len - enc_data->u.lines_data.stride; - } else { - enc_data->u.lines_data.next++; - *lines = chunk->data; - } - - return chunk->len / enc_data->u.lines_data.stride; -} - -static int quic_usr_more_lines(QuicUsrContext *usr, uint8_t **lines) -{ - EncoderData *usr_data = &(((QuicData *)usr)->data); - return encoder_usr_more_lines(usr_data, lines); -} - -static int lz_usr_more_lines(LzUsrContext *usr, uint8_t **lines) -{ - EncoderData *usr_data = &(((LzData *)usr)->data); - return encoder_usr_more_lines(usr_data, lines); -} - -static int glz_usr_more_lines(GlzEncoderUsrContext *usr, uint8_t **lines) -{ - EncoderData *usr_data = &(((GlzData *)usr)->data); - return encoder_usr_more_lines(usr_data, lines); -} - -static int jpeg_usr_more_lines(JpegEncoderUsrContext *usr, uint8_t **lines) -{ - EncoderData *usr_data = &(((JpegData *)usr)->data); - 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); - int buf_size; - - if (!usr_data->u.compressed_data.next) { - spice_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; - GlzDrawableInstanceItem *glz_drawable_instance = (GlzDrawableInstanceItem *)image; - DisplayChannelClient *drawable_cc = glz_drawable_instance->red_glz_drawable->dcc; - DisplayChannelClient *this_cc = SPICE_CONTAINEROF(lz_data, DisplayChannelClient, glz_data); - if (this_cc == drawable_cc) { - red_display_free_glz_drawable_instance(drawable_cc, glz_drawable_instance); - } else { - /* The glz dictionary is shared between all DisplayChannelClient - * instances that belong to the same client, and glz_usr_free_image - * can be called by the dictionary code - * (glz_dictionary_window_remove_head). Thus this function can be - * called from any DisplayChannelClient thread, hence the need for - * this check. - */ - pthread_mutex_lock(&drawable_cc->glz_drawables_inst_to_free_lock); - ring_add_before(&glz_drawable_instance->free_link, - &drawable_cc->glz_drawables_inst_to_free); - pthread_mutex_unlock(&drawable_cc->glz_drawables_inst_to_free_lock); - } -} - -static inline void red_init_quic(RedWorker *worker) -{ - worker->quic_data.usr.error = quic_usr_error; - worker->quic_data.usr.warn = quic_usr_warn; - worker->quic_data.usr.info = quic_usr_warn; - worker->quic_data.usr.malloc = quic_usr_malloc; - worker->quic_data.usr.free = quic_usr_free; - worker->quic_data.usr.more_space = quic_usr_more_space; - worker->quic_data.usr.more_lines = quic_usr_more_lines; - - worker->quic = quic_create(&worker->quic_data.usr); - - if (!worker->quic) { - spice_critical("create quic failed"); - } -} - -static inline void red_init_lz(RedWorker *worker) -{ - worker->lz_data.usr.error = lz_usr_error; - worker->lz_data.usr.warn = lz_usr_warn; - worker->lz_data.usr.info = lz_usr_warn; - worker->lz_data.usr.malloc = lz_usr_malloc; - worker->lz_data.usr.free = lz_usr_free; - worker->lz_data.usr.more_space = lz_usr_more_space; - worker->lz_data.usr.more_lines = lz_usr_more_lines; - - worker->lz = lz_create(&worker->lz_data.usr); - - if (!worker->lz) { - spice_critical("create lz failed"); - } -} - -/* TODO: split off to DisplayChannel? avoid just copying those cb pointers */ -static inline void red_display_init_glz_data(DisplayChannelClient *dcc) -{ - dcc->glz_data.usr.error = glz_usr_error; - dcc->glz_data.usr.warn = glz_usr_warn; - dcc->glz_data.usr.info = glz_usr_warn; - dcc->glz_data.usr.malloc = glz_usr_malloc; - dcc->glz_data.usr.free = glz_usr_free; - dcc->glz_data.usr.more_space = glz_usr_more_space; - dcc->glz_data.usr.more_lines = glz_usr_more_lines; - dcc->glz_data.usr.free_image = glz_usr_free_image; -} - -static inline void red_init_jpeg(RedWorker *worker) -{ - worker->jpeg_data.usr.more_space = jpeg_usr_more_space; - worker->jpeg_data.usr.more_lines = jpeg_usr_more_lines; - - worker->jpeg = jpeg_encoder_create(&worker->jpeg_data.usr); - - if (!worker->jpeg) { - spice_critical("create jpeg encoder failed"); - } -} - -#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; - 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) { - spice_critical("create zlib encoder failed"); - } -} - typedef struct compress_send_data_t { void* comp_buf; uint32_t comp_buf_size; @@ -4090,7 +3637,6 @@ static inline int red_glz_compress_image(DisplayChannelClient *dcc, compress_send_data_t* o_comp_data) { DisplayChannel *display_channel = DCC_TO_DC(dcc); - RedWorker *worker = display_channel->common.worker; #ifdef COMPRESS_STAT stat_time_t start_time = stat_now(worker); #endif @@ -4105,12 +3651,6 @@ static inline int red_glz_compress_image(DisplayChannelClient *dcc, glz_data->data.bufs_tail = compress_buf_new(); glz_data->data.bufs_head = glz_data->data.bufs_tail; - - if (!glz_data->data.bufs_head) { - return FALSE; - } - - glz_data->data.bufs_head->send_next = NULL; glz_data->data.dcc = dcc; glz_drawable = red_display_get_glz_drawable(dcc, drawable); @@ -4120,7 +3660,7 @@ static inline int red_glz_compress_image(DisplayChannelClient *dcc, glz_data->data.u.lines_data.stride = src->stride; glz_data->data.u.lines_data.next = 0; glz_data->data.u.lines_data.reverse = 0; - glz_data->usr.more_lines = glz_usr_more_lines; + /* fixme: remove? glz_data->usr.more_lines = glz_usr_more_lines; */ glz_size = glz_encode(dcc->glz, type, src->x, src->y, (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), NULL, 0, @@ -4137,24 +3677,17 @@ static inline int red_glz_compress_image(DisplayChannelClient *dcc, #ifdef COMPRESS_STAT start_time = stat_now(worker); #endif - zlib_data = &worker->zlib_data; + zlib_data = &dcc->zlib_data; zlib_data->data.bufs_tail = compress_buf_new(); zlib_data->data.bufs_head = zlib_data->data.bufs_tail; - - if (!zlib_data->data.bufs_head) { - spice_warning("failed to allocate zlib compress buffer"); - goto glz; - } - - zlib_data->data.bufs_head->send_next = NULL; zlib_data->data.dcc = dcc; 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, zlib_data->data.bufs_head->buf, + zlib_size = zlib_encode(dcc->zlib, dcc->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 @@ -4190,10 +3723,8 @@ static inline int red_lz_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; - LzData *lz_data = &worker->lz_data; - LzContext *lz = worker->lz; + LzData *lz_data = &dcc->lz_data; + LzContext *lz = dcc->lz; LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format]; int size; // size of the compressed data @@ -4203,12 +3734,6 @@ static inline int red_lz_compress_image(DisplayChannelClient *dcc, lz_data->data.bufs_tail = compress_buf_new(); lz_data->data.bufs_head = lz_data->data.bufs_tail; - - if (!lz_data->data.bufs_head) { - return FALSE; - } - - lz_data->data.bufs_head->send_next = NULL; lz_data->data.dcc = dcc; if (setjmp(lz_data->data.jmp_env)) { @@ -4224,7 +3749,7 @@ static inline int red_lz_compress_image(DisplayChannelClient *dcc, lz_data->data.u.lines_data.stride = src->stride; lz_data->data.u.lines_data.next = 0; lz_data->data.u.lines_data.reverse = 0; - lz_data->usr.more_lines = lz_usr_more_lines; + /* fixme: remove? lz_data->usr.more_lines = lz_usr_more_lines; */ size = lz_encode(lz, type, src->x, src->y, !!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), @@ -4268,12 +3793,10 @@ static int red_jpeg_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; - JpegData *jpeg_data = &worker->jpeg_data; - LzData *lz_data = &worker->lz_data; - JpegEncoderContext *jpeg = worker->jpeg; - LzContext *lz = worker->lz; + JpegData *jpeg_data = &dcc->jpeg_data; + LzData *lz_data = &dcc->lz_data; + JpegEncoderContext *jpeg = dcc->jpeg; + LzContext *lz = dcc->lz; volatile JpegEncoderImageType jpeg_in_type; int jpeg_size = 0; volatile int has_alpha = FALSE; @@ -4306,13 +3829,6 @@ static int red_jpeg_compress_image(DisplayChannelClient *dcc, SpiceImage *dest, jpeg_data->data.bufs_tail = compress_buf_new(); jpeg_data->data.bufs_head = jpeg_data->data.bufs_tail; - - if (!jpeg_data->data.bufs_head) { - spice_warning("failed to allocate compress buffer"); - return FALSE; - } - - jpeg_data->data.bufs_head->send_next = NULL; jpeg_data->data.dcc = dcc; if (setjmp(jpeg_data->data.jmp_env)) { @@ -4330,7 +3846,7 @@ static int red_jpeg_compress_image(DisplayChannelClient *dcc, SpiceImage *dest, jpeg_data->data.u.lines_data.chunks = src->data; jpeg_data->data.u.lines_data.stride = src->stride; - jpeg_data->usr.more_lines = jpeg_usr_more_lines; + /* fixme: remove? jpeg_data->usr.more_lines = jpeg_usr_more_lines; */ if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) { jpeg_data->data.u.lines_data.next = 0; jpeg_data->data.u.lines_data.reverse = 0; @@ -4340,7 +3856,7 @@ static int red_jpeg_compress_image(DisplayChannelClient *dcc, SpiceImage *dest, jpeg_data->data.u.lines_data.reverse = 1; stride = -src->stride; } - jpeg_size = jpeg_encode(jpeg, display_channel->jpeg_quality, jpeg_in_type, + jpeg_size = jpeg_encode(jpeg, dcc->jpeg_quality, jpeg_in_type, src->x, src->y, NULL, 0, stride, jpeg_data->data.bufs_head->buf, sizeof(jpeg_data->data.bufs_head->buf)); @@ -4376,7 +3892,7 @@ static int red_jpeg_compress_image(DisplayChannelClient *dcc, SpiceImage *dest, lz_data->data.u.lines_data.stride = src->stride; lz_data->data.u.lines_data.next = 0; lz_data->data.u.lines_data.reverse = 0; - lz_data->usr.more_lines = lz_usr_more_lines; + /* fixme: remove? lz_data->usr.more_lines = lz_usr_more_lines; */ alpha_lz_size = lz_encode(lz, LZ_IMAGE_TYPE_XXXA, src->x, src->y, !!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), @@ -4476,10 +3992,8 @@ static inline int red_quic_compress_image(DisplayChannelClient *dcc, SpiceImage 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; - QuicData *quic_data = &worker->quic_data; - QuicContext *quic = worker->quic; + QuicData *quic_data = &dcc->quic_data; + QuicContext *quic = dcc->quic; volatile QuicImageType type; int size, stride; @@ -4506,7 +4020,6 @@ static inline int red_quic_compress_image(DisplayChannelClient *dcc, SpiceImage quic_data->data.bufs_tail = compress_buf_new(); quic_data->data.bufs_head = quic_data->data.bufs_tail; - quic_data->data.bufs_head->send_next = NULL; quic_data->data.dcc = dcc; if (setjmp(quic_data->data.jmp_env)) { @@ -4524,7 +4037,7 @@ static inline int red_quic_compress_image(DisplayChannelClient *dcc, SpiceImage quic_data->data.u.lines_data.chunks = src->data; quic_data->data.u.lines_data.stride = src->stride; - quic_data->usr.more_lines = quic_usr_more_lines; + /* fixme: remove? quic_data->usr.more_lines = quic_usr_more_lines; */ if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) { quic_data->data.u.lines_data.next = 0; quic_data->data.u.lines_data.reverse = 0; @@ -8499,8 +8012,6 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red stream_buf_size = 32*1024; dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size); dcc->send_data.stream_outbuf_size = stream_buf_size; - red_display_init_glz_data(dcc); - dcc->send_data.free_list.res = spice_malloc(sizeof(SpiceResourceList) + DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID)); @@ -8512,9 +8023,6 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red display_channel->enable_jpeg = (dcc->jpeg_state == SPICE_WAN_COMPRESSION_ALWAYS); } - // todo: tune quality according to bandwidth - display_channel->jpeg_quality = 85; - if (dcc->zlib_glz_state == SPICE_WAN_COMPRESSION_AUTO) { display_channel->enable_zlib_glz_wrap = dcc->common.is_low_bandwidth; } else { @@ -8527,8 +8035,6 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red guest_set_client_capabilities(worker); - // todo: tune level according to bandwidth - display_channel->zlib_level = ZLIB_DEFAULT_COMPRESSION_LEVEL; dcc_init_stream_agents(dcc); on_new_display_channel_client(dcc); } @@ -9554,13 +9060,6 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher) spice_warn_if(init_info.n_surfaces > NUM_SURFACES); - 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; worker->cursor_channel = cursor_channel_new(worker); -- 2.4.3 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel