summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2013-09-17 01:15:38 +0200
committerFrediano Ziglio <fziglio@redhat.com>2015-11-17 16:35:11 +0000
commit94b51143024c54ac0246bfaeda6d5816c9b26f77 (patch)
tree2cebc59429d395e2406326b55ecb3e0b0fb2cbe7
parent539e588b5b8a3c183bc82cd0e8083fe3c3ffe559 (diff)
worker: move encoders to dcc-encodersupstream-20151117
Author: Marc-André Lureau <marcandre.lureau@gmail.com>
-rw-r--r--server/Makefile.am2
-rw-r--r--server/dcc-encoders.c405
-rw-r--r--server/dcc-encoders.h153
-rw-r--r--server/display-channel.c6
-rw-r--r--server/display-channel.h74
-rw-r--r--server/red_worker.c568
6 files changed, 612 insertions, 596 deletions
diff --git a/server/Makefile.am b/server/Makefile.am
index 52703c98..5907dd2f 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 00000000..42c3364e
--- /dev/null
+++ b/server/dcc-encoders.c
@@ -0,0 +1,405 @@
+/* -*- 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);
+}
+
+/* Allocate more space for compressed buffer.
+ * The pointer returned in io_ptr is garanteed to be aligned to 4 bytes.
+ */
+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.bytes;
+ 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, io_ptr);
+}
+#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 = usr_data->u.compressed_data.next->buf.bytes;
+ 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, comp_buf->buf.bytes, 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 00000000..d265f24e
--- /dev/null
+++ b/server/dcc-encoders.h
@@ -0,0 +1,153 @@
+/* -*- 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);
+
+#define RED_COMPRESS_BUF_SIZE (1024 * 64)
+struct RedCompressBuf {
+ /* This buffer provide space for compression algorithms.
+ * Some algorithms access the buffer as an array of 32 bit words
+ * so is defined to make sure is always aligned that way.
+ */
+ union {
+ uint8_t bytes[RED_COMPRESS_BUF_SIZE];
+ uint32_t words[RED_COMPRESS_BUF_SIZE / 4];
+ } buf;
+ 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 baec460f..fccbb36f 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -159,6 +159,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;
}
@@ -236,7 +240,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 b0af1386..874c2521 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,20 +64,6 @@
#define NUM_STREAMS 50
#define NUM_SURFACES 10000
-#define RED_COMPRESS_BUF_SIZE (1024 * 64)
-typedef struct RedCompressBuf RedCompressBuf;
-struct RedCompressBuf {
- /* This buffer provide space for compression algorithms.
- * Some algorithms access the buffer as an array of 32 bit words
- * so is defined to make sure is always aligned that way.
- */
- union {
- uint8_t bytes[RED_COMPRESS_BUF_SIZE];
- uint32_t words[RED_COMPRESS_BUF_SIZE / 4];
- } buf;
- RedCompressBuf *send_next;
-};
-
typedef struct WaitForChannels {
SpiceMsgWaitForChannels header;
SpiceWaitForChannel buf[MAX_CACHE_CLIENTS];
@@ -96,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;
@@ -175,6 +120,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;
@@ -333,9 +293,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 8e3be511..258dd6f9 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"
@@ -79,7 +78,6 @@
#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
-#define ZLIB_DEFAULT_COMPRESSION_LEVEL 3
#define MIN_GLZ_SIZE_FOR_ZLIB 100
#define VALIDATE_SURFACE_RET(worker, surface_id) \
@@ -136,66 +134,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};
@@ -232,23 +170,6 @@ 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_STATISTICS
StatNodeRef stat;
@@ -289,7 +210,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,
@@ -1307,7 +1228,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);
@@ -2175,32 +2096,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, comp_buf->buf.bytes, 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;
@@ -2290,8 +2185,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;
@@ -2343,7 +2238,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);
}
@@ -2354,14 +2249,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,
@@ -2373,7 +2268,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);
@@ -2398,7 +2293,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);
}
@@ -2434,364 +2329,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);
-}
-
-/* Allocate more space for compressed buffer.
- * The pointer returned in io_ptr is garanteed to be aligned to 4 bytes.
- */
-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.bytes;
- 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, io_ptr);
-}
-#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 = usr_data->u.compressed_data.next->buf.bytes;
- 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;
@@ -2804,7 +2348,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(display_channel->zlib_glz_stat.clock);
#endif
@@ -2819,12 +2362,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);
@@ -2834,7 +2371,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,
@@ -2851,23 +2388,16 @@ static inline int red_glz_compress_image(DisplayChannelClient *dcc,
#ifdef COMPRESS_STAT
start_time = stat_now(display_channel->zlib_glz_stat.clock);
#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,
+ zlib_size = zlib_encode(dcc->zlib, dcc->zlib_level,
glz_size, zlib_data->data.bufs_head->buf.bytes,
sizeof(zlib_data->data.bufs_head->buf));
@@ -2904,10 +2434,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
@@ -2917,12 +2445,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)) {
@@ -2938,7 +2460,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),
@@ -2982,12 +2504,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;
@@ -3020,13 +2540,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)) {
@@ -3044,7 +2557,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;
@@ -3054,7 +2567,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.bytes,
sizeof(jpeg_data->data.bufs_head->buf));
@@ -3090,7 +2603,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),
@@ -3125,14 +2638,12 @@ static int red_lz4_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
SpiceBitmap *src, compress_send_data_t* o_comp_data,
uint32_t group_id)
{
- DisplayChannel *display_channel = DCC_TO_DC(dcc);
- RedWorker *worker = display_channel->common.worker;
- Lz4Data *lz4_data = &worker->lz4_data;
- Lz4EncoderContext *lz4 = worker->lz4;
+ Lz4Data *lz4_data = &dcc->lz4_data;
+ Lz4EncoderContext *lz4 = dcc->lz4;
int lz4_size = 0;
#ifdef COMPRESS_STAT
- stat_time_t start_time = stat_now(worker->clockid);
+ stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->lz4_stat.clock);
#endif
lz4_data->data.bufs_tail = compress_buf_new();
@@ -3163,7 +2674,7 @@ static int red_lz4_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
lz4_data->data.u.lines_data.stride = src->stride;
lz4_data->data.u.lines_data.next = 0;
lz4_data->data.u.lines_data.reverse = 0;
- lz4_data->usr.more_lines = lz4_usr_more_lines;
+ /* fixme remove? lz4_data->usr.more_lines = lz4_usr_more_lines; */
lz4_size = lz4_encode(lz4, src->y, src->stride, lz4_data->data.bufs_head->buf.bytes,
sizeof(lz4_data->data.bufs_head->buf),
@@ -3180,7 +2691,7 @@ static int red_lz4_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
o_comp_data->comp_buf = lz4_data->data.bufs_head;
o_comp_data->comp_buf_size = lz4_size;
- stat_compress_add(&display_channel->lz4_stat, start_time, src->stride * src->y,
+ stat_compress_add(&DCC_TO_DC(dcc)->lz4_stat, start_time, src->stride * src->y,
o_comp_data->comp_buf_size);
return TRUE;
}
@@ -3190,10 +2701,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;
@@ -3220,7 +2729,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)) {
@@ -3238,7 +2746,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;
@@ -7225,8 +6733,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));
@@ -7238,9 +6744,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 {
@@ -7253,8 +6756,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);
}
@@ -8277,13 +7778,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);