[Spice-commits] 6 commits - server/dcc.c server/dcc-encoders.c server/dcc-encoders.h server/dcc.h server/display-channel.c server/display-channel.h server/red_parse_qxl.h server/red_worker.c server/red_worker.h
Frediano Ziglio
fziglio at kemper.freedesktop.org
Fri Nov 20 01:53:43 PST 2015
server/dcc-encoders.c | 64 +++
server/dcc-encoders.h | 2
server/dcc.c | 631 ++++++++++++++++++++++++++++++++++++
server/dcc.h | 31 +
server/display-channel.c | 23 +
server/display-channel.h | 8
server/red_parse_qxl.h | 6
server/red_worker.c | 807 +----------------------------------------------
server/red_worker.h | 3
9 files changed, 799 insertions(+), 776 deletions(-)
New commits:
commit 44b2d002460e95a64be22232842d426b0cdf8106
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Sep 24 16:37:15 2013 +0200
worker: few function renames
Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
diff --git a/server/red_worker.c b/server/red_worker.c
index 2759857..747bb9e 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -182,7 +182,7 @@ static void red_update_area(DisplayChannel *display, const SpiceRect *area, int
static void red_update_area_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
Drawable *last);
static inline void display_begin_send_message(RedChannelClient *rcc);
-static void red_release_glz(DisplayChannelClient *dcc);
+static void dcc_release_glz(DisplayChannelClient *dcc);
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);
@@ -2039,7 +2039,7 @@ static void dcc_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *dra
/* Clear all lz drawables - enforce their removal from the global dictionary.
NOTE - prevents encoding using the dictionary during the operation*/
-static void red_display_client_clear_glz_drawables(DisplayChannelClient *dcc)
+static void dcc_free_glz_drawables(DisplayChannelClient *dcc)
{
RingItem *ring_link;
GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
@@ -2059,7 +2059,7 @@ static void red_display_client_clear_glz_drawables(DisplayChannelClient *dcc)
pthread_rwlock_unlock(&glz_dict->encode_lock);
}
-static void red_display_clear_glz_drawables(DisplayChannel *display_channel)
+static void display_channel_free_glz_drawables(DisplayChannel *display_channel)
{
RingItem *link, *next;
DisplayChannelClient *dcc;
@@ -2068,7 +2068,7 @@ static void red_display_clear_glz_drawables(DisplayChannel *display_channel)
return;
}
DCC_FOREACH_SAFE(link, next, dcc, RED_CHANNEL(display_channel)) {
- red_display_client_clear_glz_drawables(dcc);
+ dcc_free_glz_drawables(dcc);
}
}
@@ -4631,7 +4631,7 @@ static void display_channel_client_on_disconnect(RedChannelClient *rcc)
display_channel_compress_stats_print(display);
pixmap_cache_unref(dcc->pixmap_cache);
dcc->pixmap_cache = NULL;
- red_release_glz(dcc);
+ dcc_release_glz(dcc);
dcc_palette_cache_reset(dcc);
free(dcc->send_data.stream_outbuf);
free(dcc->send_data.free_list.res);
@@ -5067,11 +5067,11 @@ static void red_freeze_glz(DisplayChannelClient *dcc)
}
/* destroy encoder, and dictionary if no one uses it*/
-static void red_release_glz(DisplayChannelClient *dcc)
+static void dcc_release_glz(DisplayChannelClient *dcc)
{
GlzSharedDictionary *shared_dict;
- red_display_client_clear_glz_drawables(dcc);
+ dcc_free_glz_drawables(dcc);
glz_encoder_destroy(dcc->glz);
dcc->glz = NULL;
@@ -5993,7 +5993,7 @@ void display_channel_destroy_surfaces(DisplayChannel *display)
red_pipes_add_verb(RED_CHANNEL(display), SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
}
- red_display_clear_glz_drawables(display);
+ display_channel_free_glz_drawables(display);
}
static void handle_dev_destroy_surfaces(void *opaque, void *payload)
@@ -6151,9 +6151,12 @@ static void handle_dev_stop(void *opaque, void *payload)
spice_info("stop");
spice_assert(worker->running);
+
worker->running = FALSE;
- red_display_clear_glz_drawables(worker->display_channel);
+
+ display_channel_free_glz_drawables(worker->display_channel);
display_channel_flush_all_surfaces(worker->display_channel);
+
/* todo: when the waiting is expected to take long (slow connection and
* overloaded pipe), don't wait, and in case of migration,
* purge the pipe, send destroy_all_surfaces
commit 30a963d53a468da28b71dfd88b685423be60d446
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Sep 24 16:15:09 2013 +0200
worker: add display_channel_free_glz_drawables_to_free()
Acked-by: Fabiano Fidêncio <fidencio at redhat.com>
diff --git a/server/dcc-encoders.c b/server/dcc-encoders.c
index 1f98d1a..d8d6617 100644
--- a/server/dcc-encoders.c
+++ b/server/dcc-encoders.c
@@ -472,3 +472,20 @@ void dcc_free_glz_drawable_instance(DisplayChannelClient *dcc,
free(glz_drawable);
}
}
+
+void dcc_free_glz_drawables_to_free(DisplayChannelClient* dcc)
+{
+ RingItem *ring_link;
+
+ if (!dcc->glz_dict) {
+ return;
+ }
+ pthread_mutex_lock(&dcc->glz_drawables_inst_to_free_lock);
+ while ((ring_link = ring_get_head(&dcc->glz_drawables_inst_to_free))) {
+ GlzDrawableInstanceItem *drawable_instance = SPICE_CONTAINEROF(ring_link,
+ GlzDrawableInstanceItem,
+ free_link);
+ dcc_free_glz_drawable_instance(dcc, drawable_instance);
+ }
+ pthread_mutex_unlock(&dcc->glz_drawables_inst_to_free_lock);
+}
diff --git a/server/dcc-encoders.h b/server/dcc-encoders.h
index cdb44ac..811183c 100644
--- a/server/dcc-encoders.h
+++ b/server/dcc-encoders.h
@@ -38,6 +38,8 @@ typedef struct GlzDrawableInstanceItem GlzDrawableInstanceItem;
void dcc_encoders_init (DisplayChannelClient *dcc);
void dcc_free_glz_drawable_instance (DisplayChannelClient *dcc,
GlzDrawableInstanceItem *item);
+void dcc_free_glz_drawables_to_free (DisplayChannelClient* dcc);
+
void marshaller_add_compressed (SpiceMarshaller *m,
RedCompressBuf *comp_buf,
size_t size);
diff --git a/server/display-channel.c b/server/display-channel.c
index 0f801d3..3b7a016 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -849,3 +849,15 @@ void display_channel_flush_all_surfaces(DisplayChannel *display)
}
}
}
+
+static void rcc_free_glz_drawables_to_free(RedChannelClient *rcc)
+{
+ DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+
+ dcc_free_glz_drawables_to_free(dcc);
+}
+
+void display_channel_free_glz_drawables_to_free(DisplayChannel *display)
+{
+ red_channel_apply_clients(RED_CHANNEL(display), rcc_free_glz_drawables_to_free);
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index ac323e3..d47abf7 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -276,6 +276,7 @@ void display_channel_current_flush (DisplayCha
int surface_id);
int display_channel_wait_for_migrate_data (DisplayChannel *display);
void display_channel_flush_all_surfaces (DisplayChannel *display);
+void display_channel_free_glz_drawables_to_free(DisplayChannel *display);
static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
{
diff --git a/server/red_worker.c b/server/red_worker.c
index 633d5d4..2759857 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -2004,23 +2004,6 @@ static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
spice_marshall_DisplayBase(base_marshaller, &base);
}
-static void red_display_handle_glz_drawables_to_free(DisplayChannelClient* dcc)
-{
- RingItem *ring_link;
-
- if (!dcc->glz_dict) {
- return;
- }
- pthread_mutex_lock(&dcc->glz_drawables_inst_to_free_lock);
- while ((ring_link = ring_get_head(&dcc->glz_drawables_inst_to_free))) {
- GlzDrawableInstanceItem *drawable_instance = SPICE_CONTAINEROF(ring_link,
- GlzDrawableInstanceItem,
- free_link);
- dcc_free_glz_drawable_instance(dcc, drawable_instance);
- }
- pthread_mutex_unlock(&dcc->glz_drawables_inst_to_free_lock);
-}
-
/*
* Releases all the instances of the drawable from the dictionary and the display channel client.
* The release of the last instance will also release the drawable itself and the qxl drawable
@@ -6826,13 +6809,6 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher)
return worker;
}
-static void red_display_cc_free_glz_drawables(RedChannelClient *rcc)
-{
- DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
-
- red_display_handle_glz_drawables_to_free(dcc);
-}
-
SPICE_GNUC_NORETURN static void *red_worker_main(void *arg)
{
RedWorker *worker = arg;
@@ -6868,8 +6844,7 @@ SPICE_GNUC_NORETURN static void *red_worker_main(void *arg)
/* during migration, in the dest, the display channel can be initialized
while the global lz data not since migrate data msg hasn't been
received yet */
- red_channel_apply_clients(&worker->display_channel->common.base,
- red_display_cc_free_glz_drawables);
+ display_channel_free_glz_drawables_to_free(worker->display_channel);
}
worker->event_timeout = INF_EVENT_WAIT;
commit aa8f2a1a95e3da3c4e0a55d25c06e1e47dd213a9
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Sep 24 15:40:40 2013 +0200
worker: move dcc_free_glz_drawable_instance
Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
diff --git a/server/dcc-encoders.c b/server/dcc-encoders.c
index 90d0ce0..1f98d1a 100644
--- a/server/dcc-encoders.c
+++ b/server/dcc-encoders.c
@@ -425,3 +425,50 @@ void marshaller_add_compressed(SpiceMarshaller *m,
comp_buf = comp_buf->send_next;
} while (max);
}
+
+/* Remove from the to_free list and the instances_list.
+ When no instance is left - the RedGlzDrawable is released too. (and the qxl drawable too, if
+ 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*/
+void dcc_free_glz_drawable_instance(DisplayChannelClient *dcc,
+ GlzDrawableInstanceItem *instance)
+{
+ DisplayChannel *display_channel = DCC_TO_DC(dcc);
+ RedWorker *worker = display_channel->common.worker;
+ RedGlzDrawable *glz_drawable;
+
+ spice_assert(instance);
+ spice_assert(instance->glz_drawable);
+
+ glz_drawable = instance->glz_drawable;
+
+ spice_assert(glz_drawable->dcc == dcc);
+ spice_assert(glz_drawable->instances_count > 0);
+
+ ring_remove(&instance->glz_link);
+ glz_drawable->instances_count--;
+
+ // when the remove callback is performed from the channel that the
+ // drawable belongs to, the instance is not added to the 'to_free' list
+ if (ring_item_is_linked(&instance->free_link)) {
+ ring_remove(&instance->free_link);
+ }
+
+ if (ring_is_empty(&glz_drawable->instances)) {
+ spice_assert(glz_drawable->instances_count == 0);
+
+ Drawable *drawable = glz_drawable->drawable;
+
+ if (drawable) {
+ ring_remove(&glz_drawable->drawable_link);
+ }
+ red_drawable_unref(worker, glz_drawable->red_drawable,
+ glz_drawable->group_id);
+ display_channel->glz_drawable_count--;
+ if (ring_item_is_linked(&glz_drawable->link)) {
+ ring_remove(&glz_drawable->link);
+ }
+ free(glz_drawable);
+ }
+}
diff --git a/server/red_worker.c b/server/red_worker.c
index 3a21d96..633d5d4 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -571,8 +571,8 @@ static inline void set_surface_release_info(QXLReleaseInfoExt *release_info_ext,
release_info_ext->group_id = group_id;
}
-static void red_drawable_unref(RedWorker *worker, RedDrawable *red_drawable,
- uint32_t group_id)
+void red_drawable_unref(RedWorker *worker, RedDrawable *red_drawable,
+ uint32_t group_id)
{
QXLReleaseInfoExt release_info_ext;
@@ -2004,52 +2004,6 @@ static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
spice_marshall_DisplayBase(base_marshaller, &base);
}
-/* Remove from the to_free list and the instances_list.
- When no instance is left - the RedGlzDrawable is released too. (and the qxl drawable too, if
- 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*/
-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;
- RedGlzDrawable *glz_drawable;
-
- spice_assert(glz_drawable_instance);
- spice_assert(glz_drawable_instance->glz_drawable);
-
- glz_drawable = glz_drawable_instance->glz_drawable;
-
- spice_assert(glz_drawable->dcc == dcc);
- spice_assert(glz_drawable->instances_count);
-
- ring_remove(&glz_drawable_instance->glz_link);
- glz_drawable->instances_count--;
- // when the remove callback is performed from the channel that the
- // drawable belongs to, the instance is not added to the 'to_free' list
- if (ring_item_is_linked(&glz_drawable_instance->free_link)) {
- ring_remove(&glz_drawable_instance->free_link);
- }
-
- if (ring_is_empty(&glz_drawable->instances)) {
- spice_assert(!glz_drawable->instances_count);
-
- Drawable *drawable = glz_drawable->drawable;
-
- if (drawable) {
- ring_remove(&glz_drawable->drawable_link);
- }
- red_drawable_unref(worker, glz_drawable->red_drawable,
- glz_drawable->group_id);
- display_channel->glz_drawable_count--;
- if (ring_item_is_linked(&glz_drawable->link)) {
- ring_remove(&glz_drawable->link);
- }
- free(glz_drawable);
- }
-}
-
static void red_display_handle_glz_drawables_to_free(DisplayChannelClient* dcc)
{
RingItem *ring_link;
diff --git a/server/red_worker.h b/server/red_worker.h
index 729ce2b..cbf91b9 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -22,6 +22,7 @@
#include <errno.h>
#include "red_common.h"
#include "red_dispatcher.h"
+#include "red_parse_qxl.h"
typedef struct RedWorker RedWorker;
@@ -109,6 +110,8 @@ QXLInstance* red_worker_get_qxl(RedWorker *worker);
RedChannel* red_worker_get_cursor_channel(RedWorker *worker);
RedChannel* red_worker_get_display_channel(RedWorker *worker);
clockid_t red_worker_get_clockid(RedWorker *worker);
+void red_drawable_unref(RedWorker *worker, RedDrawable *red_drawable,
+ uint32_t group_id);
RedChannel *red_worker_new_channel(RedWorker *worker, int size,
const char *name,
commit 920f857c2d4ad3e8c238c44756b737169b4c7408
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Sep 24 15:11:21 2013 +0200
worker: move display_channel_flush_all_surfaces
Acked-by: Fabiano Fidêncio <fidencio at redhat.com>
diff --git a/server/display-channel.c b/server/display-channel.c
index 37ba5c3..0f801d3 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -838,3 +838,14 @@ int display_channel_wait_for_migrate_data(DisplayChannel *display)
}
return FALSE;
}
+
+void display_channel_flush_all_surfaces(DisplayChannel *display)
+{
+ int x;
+
+ for (x = 0; x < NUM_SURFACES; ++x) {
+ if (display->surfaces[x].context.canvas) {
+ display_channel_current_flush(display, x);
+ }
+ }
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index 111e014..ac323e3 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -275,6 +275,7 @@ int display_channel_add_drawable (DisplayCha
void display_channel_current_flush (DisplayChannel *display,
int surface_id);
int display_channel_wait_for_migrate_data (DisplayChannel *display);
+void display_channel_flush_all_surfaces (DisplayChannel *display);
static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
{
diff --git a/server/red_worker.c b/server/red_worker.c
index d744f48..3a21d96 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -6200,28 +6200,12 @@ static void handle_dev_destroy_primary_surface_async(void *opaque, void *payload
destroy_primary_surface(worker, surface_id);
}
-static void flush_all_surfaces(DisplayChannel *display)
-{
- int x;
-
- for (x = 0; x < NUM_SURFACES; ++x) {
- if (display->surfaces[x].context.canvas) {
- display_channel_current_flush(display, x);
- }
- }
-}
-
-static void dev_flush_surfaces(RedWorker *worker)
-{
- flush_all_qxl_commands(worker);
- flush_all_surfaces(worker->display_channel);
-}
-
static void handle_dev_flush_surfaces_async(void *opaque, void *payload)
{
RedWorker *worker = opaque;
- dev_flush_surfaces(worker);
+ flush_all_qxl_commands(worker);
+ display_channel_flush_all_surfaces(worker->display_channel);
}
static void handle_dev_stop(void *opaque, void *payload)
@@ -6232,7 +6216,7 @@ static void handle_dev_stop(void *opaque, void *payload)
spice_assert(worker->running);
worker->running = FALSE;
red_display_clear_glz_drawables(worker->display_channel);
- flush_all_surfaces(worker->display_channel);
+ display_channel_flush_all_surfaces(worker->display_channel);
/* todo: when the waiting is expected to take long (slow connection and
* overloaded pipe), don't wait, and in case of migration,
* purge the pipe, send destroy_all_surfaces
commit 422d67dde4bb9d55362dee5db2237ef373448dbd
Author: Frediano Ziglio <fziglio at redhat.com>
Date: Thu Nov 19 13:55:39 2015 +0000
worker: move compress to dcc_compress_image()
Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
diff --git a/server/dcc.c b/server/dcc.c
index a14247c..1e18814 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -309,3 +309,634 @@ void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
destroy = surface_destroy_item_new(channel, surface_id);
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy->pipe_item);
}
+
+/* if already exists, returns it. Otherwise allocates and adds it (1) to the ring tail
+ in the channel (2) to the Drawable*/
+static RedGlzDrawable *get_glz_drawable(DisplayChannelClient *dcc, Drawable *drawable)
+{
+ RedGlzDrawable *ret;
+ RingItem *item, *next;
+
+ // TODO - I don't really understand what's going on here, so doing the technical equivalent
+ // now that we have multiple glz_dicts, so the only way to go from dcc to drawable glz is to go
+ // over the glz_ring (unless adding some better data structure then a ring)
+ DRAWABLE_FOREACH_GLZ_SAFE(drawable, item, next, ret) {
+ if (ret->dcc == dcc) {
+ return ret;
+ }
+ }
+
+ ret = spice_new(RedGlzDrawable, 1);
+
+ ret->dcc = dcc;
+ ret->red_drawable = red_drawable_ref(drawable->red_drawable);
+ ret->drawable = drawable;
+ ret->group_id = drawable->group_id;
+ ret->instances_count = 0;
+ ring_init(&ret->instances);
+
+ ring_item_init(&ret->link);
+ ring_item_init(&ret->drawable_link);
+ ring_add_before(&ret->link, &dcc->glz_drawables);
+ ring_add(&drawable->glz_ring, &ret->drawable_link);
+ DCC_TO_DC(dcc)->glz_drawable_count++;
+ return ret;
+}
+
+/* allocates new instance and adds it to instances in the given drawable.
+ NOTE - the caller should set the glz_instance returned by the encoder by itself.*/
+static GlzDrawableInstanceItem *add_glz_drawable_instance(RedGlzDrawable *glz_drawable)
+{
+ spice_assert(glz_drawable->instances_count < MAX_GLZ_DRAWABLE_INSTANCES);
+ // NOTE: We assume the additions are performed consecutively, without removals in the middle
+ GlzDrawableInstanceItem *ret = glz_drawable->instances_pool + glz_drawable->instances_count;
+ glz_drawable->instances_count++;
+
+ ring_item_init(&ret->free_link);
+ ring_item_init(&ret->glz_link);
+ ring_add(&glz_drawable->instances, &ret->glz_link);
+ ret->context = NULL;
+ ret->glz_drawable = glz_drawable;
+
+ return ret;
+}
+
+#define MIN_GLZ_SIZE_FOR_ZLIB 100
+
+int dcc_compress_image_glz(DisplayChannelClient *dcc,
+ SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
+ compress_send_data_t* o_comp_data)
+{
+ DisplayChannel *display_channel = DCC_TO_DC(dcc);
+#ifdef COMPRESS_STAT
+ stat_time_t start_time = stat_now(display_channel->glz_stat.clock);
+#endif
+ spice_assert(bitmap_fmt_is_rgb(src->format));
+ GlzData *glz_data = &dcc->glz_data;
+ ZlibData *zlib_data;
+ LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
+ RedGlzDrawable *glz_drawable;
+ GlzDrawableInstanceItem *glz_drawable_instance;
+ int glz_size;
+ int zlib_size;
+
+ glz_data->data.bufs_tail = compress_buf_new();
+ glz_data->data.bufs_head = glz_data->data.bufs_tail;
+ glz_data->data.dcc = dcc;
+
+ glz_drawable = get_glz_drawable(dcc, drawable);
+ glz_drawable_instance = add_glz_drawable_instance(glz_drawable);
+
+ glz_data->data.u.lines_data.chunks = src->data;
+ 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_size = glz_encode(dcc->glz, type, src->x, src->y,
+ (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), NULL, 0,
+ src->stride, glz_data->data.bufs_head->buf.bytes,
+ sizeof(glz_data->data.bufs_head->buf),
+ glz_drawable_instance,
+ &glz_drawable_instance->context);
+
+ stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y, glz_size);
+
+ if (!display_channel->enable_zlib_glz_wrap || (glz_size < MIN_GLZ_SIZE_FOR_ZLIB)) {
+ goto glz;
+ }
+#ifdef COMPRESS_STAT
+ start_time = stat_now(display_channel->zlib_glz_stat.clock);
+#endif
+ zlib_data = &dcc->zlib_data;
+
+ zlib_data->data.bufs_tail = compress_buf_new();
+ zlib_data->data.bufs_head = zlib_data->data.bufs_tail;
+ 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(dcc->zlib, dcc->zlib_level,
+ glz_size, zlib_data->data.bufs_head->buf.bytes,
+ sizeof(zlib_data->data.bufs_head->buf));
+
+ // the compressed buffer is bigger than the original data
+ if (zlib_size >= glz_size) {
+ while (zlib_data->data.bufs_head) {
+ RedCompressBuf *buf = zlib_data->data.bufs_head;
+ zlib_data->data.bufs_head = buf->send_next;
+ compress_buf_free(buf);
+ }
+ goto glz;
+ }
+
+ dest->descriptor.type = SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB;
+ dest->u.zlib_glz.glz_data_size = glz_size;
+ dest->u.zlib_glz.data_size = zlib_size;
+
+ o_comp_data->comp_buf = zlib_data->data.bufs_head;
+ o_comp_data->comp_buf_size = zlib_size;
+
+ stat_compress_add(&display_channel->zlib_glz_stat, start_time, glz_size, zlib_size);
+ return TRUE;
+glz:
+ dest->descriptor.type = SPICE_IMAGE_TYPE_GLZ_RGB;
+ dest->u.lz_rgb.data_size = glz_size;
+
+ o_comp_data->comp_buf = glz_data->data.bufs_head;
+ o_comp_data->comp_buf_size = glz_size;
+
+ return TRUE;
+}
+
+int dcc_compress_image_lz(DisplayChannelClient *dcc,
+ SpiceImage *dest, SpiceBitmap *src,
+ compress_send_data_t* o_comp_data, uint32_t group_id)
+{
+ 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
+
+#ifdef COMPRESS_STAT
+ stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->lz_stat.clock);
+#endif
+
+ lz_data->data.bufs_tail = compress_buf_new();
+ lz_data->data.bufs_head = lz_data->data.bufs_tail;
+ lz_data->data.dcc = dcc;
+
+ if (setjmp(lz_data->data.jmp_env)) {
+ while (lz_data->data.bufs_head) {
+ RedCompressBuf *buf = lz_data->data.bufs_head;
+ lz_data->data.bufs_head = buf->send_next;
+ compress_buf_free(buf);
+ }
+ return FALSE;
+ }
+
+ lz_data->data.u.lines_data.chunks = src->data;
+ 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;
+
+ size = lz_encode(lz, type, src->x, src->y,
+ !!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN),
+ NULL, 0, src->stride,
+ lz_data->data.bufs_head->buf.bytes,
+ sizeof(lz_data->data.bufs_head->buf));
+
+ // the compressed buffer is bigger than the original data
+ if (size > (src->y * src->stride)) {
+ longjmp(lz_data->data.jmp_env, 1);
+ }
+
+ if (bitmap_fmt_is_rgb(src->format)) {
+ dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_RGB;
+ dest->u.lz_rgb.data_size = size;
+
+ o_comp_data->comp_buf = lz_data->data.bufs_head;
+ o_comp_data->comp_buf_size = size;
+ } else {
+ /* masks are 1BIT bitmaps without palettes, but they are not compressed
+ * (see fill_mask) */
+ spice_assert(src->palette);
+ dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_PLT;
+ dest->u.lz_plt.data_size = size;
+ dest->u.lz_plt.flags = src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
+ dest->u.lz_plt.palette = src->palette;
+ dest->u.lz_plt.palette_id = src->palette->unique;
+ o_comp_data->comp_buf = lz_data->data.bufs_head;
+ o_comp_data->comp_buf_size = size;
+
+ dcc_palette_cache_palette(dcc, dest->u.lz_plt.palette, &(dest->u.lz_plt.flags));
+ o_comp_data->lzplt_palette = dest->u.lz_plt.palette;
+ }
+
+ stat_compress_add(&DCC_TO_DC(dcc)->lz_stat, start_time, src->stride * src->y,
+ o_comp_data->comp_buf_size);
+ return TRUE;
+}
+
+int dcc_compress_image_jpeg(DisplayChannelClient *dcc, SpiceImage *dest,
+ SpiceBitmap *src, compress_send_data_t* o_comp_data,
+ uint32_t group_id)
+{
+ 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;
+ int alpha_lz_size = 0;
+ int comp_head_filled;
+ int comp_head_left;
+ int stride;
+ uint8_t *lz_out_start_byte;
+
+#ifdef COMPRESS_STAT
+ stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->jpeg_stat.clock);
+#endif
+ switch (src->format) {
+ case SPICE_BITMAP_FMT_16BIT:
+ jpeg_in_type = JPEG_IMAGE_TYPE_RGB16;
+ break;
+ case SPICE_BITMAP_FMT_24BIT:
+ jpeg_in_type = JPEG_IMAGE_TYPE_BGR24;
+ break;
+ case SPICE_BITMAP_FMT_32BIT:
+ jpeg_in_type = JPEG_IMAGE_TYPE_BGRX32;
+ break;
+ case SPICE_BITMAP_FMT_RGBA:
+ jpeg_in_type = JPEG_IMAGE_TYPE_BGRX32;
+ has_alpha = TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+
+ jpeg_data->data.bufs_tail = compress_buf_new();
+ jpeg_data->data.bufs_head = jpeg_data->data.bufs_tail;
+ jpeg_data->data.dcc = dcc;
+
+ if (setjmp(jpeg_data->data.jmp_env)) {
+ while (jpeg_data->data.bufs_head) {
+ RedCompressBuf *buf = jpeg_data->data.bufs_head;
+ jpeg_data->data.bufs_head = buf->send_next;
+ compress_buf_free(buf);
+ }
+ return FALSE;
+ }
+
+ if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
+ spice_chunks_linearize(src->data);
+ }
+
+ jpeg_data->data.u.lines_data.chunks = src->data;
+ jpeg_data->data.u.lines_data.stride = src->stride;
+ if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
+ jpeg_data->data.u.lines_data.next = 0;
+ jpeg_data->data.u.lines_data.reverse = 0;
+ stride = src->stride;
+ } else {
+ jpeg_data->data.u.lines_data.next = src->data->num_chunks - 1;
+ jpeg_data->data.u.lines_data.reverse = 1;
+ stride = -src->stride;
+ }
+ 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));
+
+ // the compressed buffer is bigger than the original data
+ if (jpeg_size > (src->y * src->stride)) {
+ longjmp(jpeg_data->data.jmp_env, 1);
+ }
+
+ if (!has_alpha) {
+ dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG;
+ dest->u.jpeg.data_size = jpeg_size;
+
+ o_comp_data->comp_buf = jpeg_data->data.bufs_head;
+ o_comp_data->comp_buf_size = jpeg_size;
+ o_comp_data->is_lossy = TRUE;
+
+ stat_compress_add(&DCC_TO_DC(dcc)->jpeg_stat, start_time, src->stride * src->y,
+ o_comp_data->comp_buf_size);
+ return TRUE;
+ }
+
+ lz_data->data.bufs_head = jpeg_data->data.bufs_tail;
+ lz_data->data.bufs_tail = lz_data->data.bufs_head;
+
+ comp_head_filled = jpeg_size % sizeof(lz_data->data.bufs_head->buf);
+ comp_head_left = sizeof(lz_data->data.bufs_head->buf) - comp_head_filled;
+ lz_out_start_byte = lz_data->data.bufs_head->buf.bytes + comp_head_filled;
+
+ lz_data->data.dcc = dcc;
+
+ lz_data->data.u.lines_data.chunks = src->data;
+ 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;
+
+ alpha_lz_size = lz_encode(lz, LZ_IMAGE_TYPE_XXXA, src->x, src->y,
+ !!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN),
+ NULL, 0, src->stride,
+ lz_out_start_byte,
+ comp_head_left);
+
+ // the compressed buffer is bigger than the original data
+ if ((jpeg_size + alpha_lz_size) > (src->y * src->stride)) {
+ longjmp(jpeg_data->data.jmp_env, 1);
+ }
+
+ dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG_ALPHA;
+ dest->u.jpeg_alpha.flags = 0;
+ if (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN) {
+ dest->u.jpeg_alpha.flags |= SPICE_JPEG_ALPHA_FLAGS_TOP_DOWN;
+ }
+
+ dest->u.jpeg_alpha.jpeg_size = jpeg_size;
+ dest->u.jpeg_alpha.data_size = jpeg_size + alpha_lz_size;
+
+ o_comp_data->comp_buf = jpeg_data->data.bufs_head;
+ o_comp_data->comp_buf_size = jpeg_size + alpha_lz_size;
+ o_comp_data->is_lossy = TRUE;
+ stat_compress_add(&DCC_TO_DC(dcc)->jpeg_alpha_stat, start_time, src->stride * src->y,
+ o_comp_data->comp_buf_size);
+ return TRUE;
+}
+
+#ifdef USE_LZ4
+int dcc_compress_image_lz4(DisplayChannelClient *dcc, SpiceImage *dest,
+ SpiceBitmap *src, compress_send_data_t* o_comp_data,
+ uint32_t group_id)
+{
+ DisplayChannel *display_channel = DCC_TO_DC(dcc);
+ Lz4Data *lz4_data = &dcc->lz4_data;
+ Lz4EncoderContext *lz4 = dcc->lz4;
+ int lz4_size = 0;
+
+#ifdef COMPRESS_STAT
+ stat_time_t start_time = stat_now(display_channel->lz4_stat.clock);
+#endif
+
+ lz4_data->data.bufs_tail = compress_buf_new();
+ lz4_data->data.bufs_head = lz4_data->data.bufs_tail;
+
+ if (!lz4_data->data.bufs_head) {
+ spice_warning("failed to allocate compress buffer");
+ return FALSE;
+ }
+
+ lz4_data->data.bufs_head->send_next = NULL;
+ lz4_data->data.dcc = dcc;
+
+ if (setjmp(lz4_data->data.jmp_env)) {
+ while (lz4_data->data.bufs_head) {
+ RedCompressBuf *buf = lz4_data->data.bufs_head;
+ lz4_data->data.bufs_head = buf->send_next;
+ compress_buf_free(buf);
+ }
+ return FALSE;
+ }
+
+ if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
+ spice_chunks_linearize(src->data);
+ }
+
+ lz4_data->data.u.lines_data.chunks = src->data;
+ lz4_data->data.u.lines_data.stride = src->stride;
+ lz4_data->data.u.lines_data.next = 0;
+ lz4_data->data.u.lines_data.reverse = 0;
+
+ lz4_size = lz4_encode(lz4, src->y, src->stride, lz4_data->data.bufs_head->buf.bytes,
+ sizeof(lz4_data->data.bufs_head->buf),
+ src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN, src->format);
+
+ // the compressed buffer is bigger than the original data
+ if (lz4_size > (src->y * src->stride)) {
+ longjmp(lz4_data->data.jmp_env, 1);
+ }
+
+ dest->descriptor.type = SPICE_IMAGE_TYPE_LZ4;
+ dest->u.lz4.data_size = lz4_size;
+
+ o_comp_data->comp_buf = lz4_data->data.bufs_head;
+ o_comp_data->comp_buf_size = lz4_size;
+
+ stat_compress_add(&display_channel->lz4_stat, start_time, src->stride * src->y,
+ o_comp_data->comp_buf_size);
+ return TRUE;
+}
+#endif
+
+int dcc_compress_image_quic(DisplayChannelClient *dcc, SpiceImage *dest,
+ SpiceBitmap *src, compress_send_data_t* o_comp_data,
+ uint32_t group_id)
+{
+ QuicData *quic_data = &dcc->quic_data;
+ QuicContext *quic = dcc->quic;
+ volatile QuicImageType type;
+ int size, stride;
+
+#ifdef COMPRESS_STAT
+ stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->quic_stat.clock);
+#endif
+
+ switch (src->format) {
+ case SPICE_BITMAP_FMT_32BIT:
+ type = QUIC_IMAGE_TYPE_RGB32;
+ break;
+ case SPICE_BITMAP_FMT_RGBA:
+ type = QUIC_IMAGE_TYPE_RGBA;
+ break;
+ case SPICE_BITMAP_FMT_16BIT:
+ type = QUIC_IMAGE_TYPE_RGB16;
+ break;
+ case SPICE_BITMAP_FMT_24BIT:
+ type = QUIC_IMAGE_TYPE_RGB24;
+ break;
+ default:
+ return FALSE;
+ }
+
+ quic_data->data.bufs_tail = compress_buf_new();
+ quic_data->data.bufs_head = quic_data->data.bufs_tail;
+ quic_data->data.dcc = dcc;
+
+ if (setjmp(quic_data->data.jmp_env)) {
+ while (quic_data->data.bufs_head) {
+ RedCompressBuf *buf = quic_data->data.bufs_head;
+ quic_data->data.bufs_head = buf->send_next;
+ compress_buf_free(buf);
+ }
+ return FALSE;
+ }
+
+ if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
+ spice_chunks_linearize(src->data);
+ }
+
+ quic_data->data.u.lines_data.chunks = src->data;
+ quic_data->data.u.lines_data.stride = src->stride;
+ if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
+ quic_data->data.u.lines_data.next = 0;
+ quic_data->data.u.lines_data.reverse = 0;
+ stride = src->stride;
+ } else {
+ quic_data->data.u.lines_data.next = src->data->num_chunks - 1;
+ quic_data->data.u.lines_data.reverse = 1;
+ stride = -src->stride;
+ }
+ size = quic_encode(quic, type, src->x, src->y, NULL, 0, stride,
+ quic_data->data.bufs_head->buf.words,
+ G_N_ELEMENTS(quic_data->data.bufs_head->buf.words));
+
+ // the compressed buffer is bigger than the original data
+ if ((size << 2) > (src->y * src->stride)) {
+ longjmp(quic_data->data.jmp_env, 1);
+ }
+
+ dest->descriptor.type = SPICE_IMAGE_TYPE_QUIC;
+ dest->u.quic.data_size = size << 2;
+
+ o_comp_data->comp_buf = quic_data->data.bufs_head;
+ o_comp_data->comp_buf_size = size << 2;
+
+ stat_compress_add(&DCC_TO_DC(dcc)->quic_stat, start_time, src->stride * src->y,
+ o_comp_data->comp_buf_size);
+ return TRUE;
+}
+
+#define MIN_SIZE_TO_COMPRESS 54
+#define MIN_DIMENSION_TO_QUIC 3
+int dcc_compress_image(DisplayChannelClient *dcc,
+ SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
+ int can_lossy,
+ compress_send_data_t* o_comp_data)
+{
+ DisplayChannel *display_channel = DCC_TO_DC(dcc);
+ SpiceImageCompression image_compression = dcc->image_compression;
+ int quic_compress = FALSE;
+
+ if ((image_compression == SPICE_IMAGE_COMPRESSION_OFF) ||
+ ((src->y * src->stride) < MIN_SIZE_TO_COMPRESS)) { // TODO: change the size cond
+ return FALSE;
+ } else if (image_compression == SPICE_IMAGE_COMPRESSION_QUIC) {
+ if (bitmap_fmt_is_plt(src->format)) {
+ return FALSE;
+ } else {
+ quic_compress = TRUE;
+ }
+ } else {
+ /*
+ lz doesn't handle (1) bitmaps with strides that are larger than the width
+ of the image in bytes (2) unstable bitmaps
+ */
+ if (bitmap_has_extra_stride(src) || (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE)) {
+ if ((image_compression == SPICE_IMAGE_COMPRESSION_LZ) ||
+ (image_compression == SPICE_IMAGE_COMPRESSION_GLZ) ||
+ (image_compression == SPICE_IMAGE_COMPRESSION_LZ4) ||
+ bitmap_fmt_is_plt(src->format)) {
+ return FALSE;
+ } else {
+ quic_compress = TRUE;
+ }
+ } else {
+ if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
+ (image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ)) {
+ if ((src->x < MIN_DIMENSION_TO_QUIC) || (src->y < MIN_DIMENSION_TO_QUIC)) {
+ quic_compress = FALSE;
+ } else {
+ if (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_INVALID) {
+ quic_compress = bitmap_fmt_has_graduality(src->format) &&
+ bitmap_get_graduality_level(src) == BITMAP_GRADUAL_HIGH;
+ } else {
+ quic_compress = (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_HIGH);
+ }
+ }
+ } else {
+ quic_compress = FALSE;
+ }
+ }
+ }
+
+ if (quic_compress) {
+#ifdef COMPRESS_DEBUG
+ spice_info("QUIC compress");
+#endif
+ // if bitmaps is picture-like, compress it using jpeg
+ if (can_lossy && display_channel->enable_jpeg &&
+ ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
+ (image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ))) {
+ // if we use lz for alpha, the stride can't be extra
+ if (src->format != SPICE_BITMAP_FMT_RGBA || !bitmap_has_extra_stride(src)) {
+ return dcc_compress_image_jpeg(dcc, dest,
+ src, o_comp_data, drawable->group_id);
+ }
+ }
+ return dcc_compress_image_quic(dcc, dest,
+ src, o_comp_data, drawable->group_id);
+ } else {
+ int glz;
+ int ret;
+ if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ) ||
+ (image_compression == SPICE_IMAGE_COMPRESSION_GLZ)) {
+ glz = bitmap_fmt_has_graduality(src->format) && (
+ (src->x * src->y) < glz_enc_dictionary_get_size(
+ dcc->glz_dict->dict));
+ } else if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
+ (image_compression == SPICE_IMAGE_COMPRESSION_LZ) ||
+ (image_compression == SPICE_IMAGE_COMPRESSION_LZ4)) {
+ glz = FALSE;
+ } else {
+ spice_error("invalid image compression type %u", image_compression);
+ return FALSE;
+ }
+
+ if (glz) {
+ /* using the global dictionary only if it is not frozen */
+ pthread_rwlock_rdlock(&dcc->glz_dict->encode_lock);
+ if (!dcc->glz_dict->migrate_freeze) {
+ ret = dcc_compress_image_glz(dcc,
+ dest, src,
+ drawable, o_comp_data);
+ } else {
+ glz = FALSE;
+ }
+ pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
+ }
+
+ if (!glz) {
+#ifdef USE_LZ4
+ if (image_compression == SPICE_IMAGE_COMPRESSION_LZ4 &&
+ bitmap_fmt_is_rgb(src->format) &&
+ red_channel_client_test_remote_cap(&dcc->common.base,
+ SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) {
+ ret = dcc_compress_image_lz4(dcc, dest, src, o_comp_data,
+ drawable->group_id);
+ } else
+#endif
+ ret = dcc_compress_image_lz(dcc, dest, src, o_comp_data,
+ drawable->group_id);
+#ifdef COMPRESS_DEBUG
+ spice_info("LZ LOCAL compress");
+#endif
+ }
+#ifdef COMPRESS_DEBUG
+ else {
+ spice_info("LZ global compress fmt=%d", src->format);
+ }
+#endif
+ return ret;
+ }
+}
+
+#define CLIENT_PALETTE_CACHE
+#include "cache_item.tmpl.c"
+#undef CLIENT_PALETTE_CACHE
+
+void dcc_palette_cache_palette(DisplayChannelClient *dcc, SpicePalette *palette,
+ uint8_t *flags)
+{
+ if (palette == NULL) {
+ return;
+ }
+ if (palette->unique) {
+ if (red_palette_cache_find(dcc, palette->unique)) {
+ *flags |= SPICE_BITMAP_FLAGS_PAL_FROM_CACHE;
+ return;
+ }
+ if (red_palette_cache_add(dcc, palette->unique, 1)) {
+ *flags |= SPICE_BITMAP_FLAGS_PAL_CACHE_ME;
+ }
+ }
+}
+
+void dcc_palette_cache_reset(DisplayChannelClient *dcc)
+{
+ red_palette_cache_reset(dcc, CLIENT_PALETTE_CACHE_SIZE);
+}
diff --git a/server/dcc.h b/server/dcc.h
index a6ca9be..7827f72 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -163,5 +163,36 @@ ImageItem * dcc_add_surface_area_image (DisplayCha
SpiceRect *area,
PipeItem *pos,
int can_lossy);
+void dcc_palette_cache_reset (DisplayChannelClient *dcc);
+void dcc_palette_cache_palette (DisplayChannelClient *dcc,
+ SpicePalette *palette,
+ uint8_t *flags);
+
+typedef struct compress_send_data_t {
+ void* comp_buf;
+ uint32_t comp_buf_size;
+ SpicePalette *lzplt_palette;
+ int is_lossy;
+} compress_send_data_t;
+
+int dcc_compress_image (DisplayChannelClient *dcc,
+ SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
+ int can_lossy,
+ compress_send_data_t* o_comp_data);
+int dcc_compress_image_glz (DisplayChannelClient *dcc,
+ SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
+ compress_send_data_t* o_comp_data);
+int dcc_compress_image_lz (DisplayChannelClient *dcc,
+ SpiceImage *dest, SpiceBitmap *src,
+ compress_send_data_t* o_comp_data, uint32_t group_id);
+int dcc_compress_image_jpeg (DisplayChannelClient *dcc, SpiceImage *dest,
+ SpiceBitmap *src, compress_send_data_t* o_comp_data,
+ uint32_t group_id);
+int dcc_compress_image_quic (DisplayChannelClient *dcc, SpiceImage *dest,
+ SpiceBitmap *src, compress_send_data_t* o_comp_data,
+ uint32_t group_id);
+int dcc_compress_image_lz4 (DisplayChannelClient *dcc, SpiceImage *dest,
+ SpiceBitmap *src, compress_send_data_t* o_comp_data,
+ uint32_t group_id);
#endif /* DCC_H_ */
diff --git a/server/display-channel.h b/server/display-channel.h
index 7f3949f..111e014 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -91,6 +91,10 @@ struct Drawable {
#define DRAWABLE_FOREACH_DPI_SAFE(drawable, link, next, dpi) \
SAFE_FOREACH(link, next, drawable, &(drawable)->pipes, dpi, LINK_TO_DPI(link))
+#define LINK_TO_GLZ(ptr) SPICE_CONTAINEROF((ptr), RedGlzDrawable, \
+ drawable_link)
+#define DRAWABLE_FOREACH_GLZ_SAFE(drawable, link, next, glz) \
+ SAFE_FOREACH(link, next, drawable, &(drawable)->glz_ring, glz, LINK_TO_GLZ(link))
enum {
PIPE_ITEM_TYPE_DRAW = PIPE_ITEM_TYPE_COMMON_LAST,
diff --git a/server/red_parse_qxl.h b/server/red_parse_qxl.h
index 87862fa..b3b28e1 100644
--- a/server/red_parse_qxl.h
+++ b/server/red_parse_qxl.h
@@ -57,6 +57,12 @@ typedef struct RedDrawable {
} u;
} RedDrawable;
+static inline RedDrawable *red_drawable_ref(RedDrawable *drawable)
+{
+ drawable->refs++;
+ return drawable;
+}
+
typedef struct RedUpdateCmd {
QXLReleaseInfo *release_info;
SpiceRect area;
diff --git a/server/red_worker.c b/server/red_worker.c
index eab00ff..d744f48 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -73,12 +73,6 @@
#define CMD_RING_POLL_RETRIES 200
#define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano
-#define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
-#define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
-
-#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
-
-#define MIN_GLZ_SIZE_FOR_ZLIB 100
#define VALIDATE_SURFACE_RET(worker, surface_id) \
if (!validate_surface(worker, surface_id)) { \
@@ -202,13 +196,6 @@ static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uin
uint32_t height, int32_t stride, uint32_t format,
void *line_0, int data_is_valid, int send_client);
-
-#define LINK_TO_GLZ(ptr) SPICE_CONTAINEROF((ptr), RedGlzDrawable, \
- drawable_link)
-#define DRAWABLE_FOREACH_GLZ_SAFE(drawable, link, next, glz) \
- SAFE_FOREACH(link, next, drawable, &(drawable)->glz_ring, glz, LINK_TO_GLZ(link))
-
-
static void display_stream_clip_unref(DisplayChannel *display, StreamClipItem *item)
{
if (--item->refs != 0)
@@ -545,14 +532,6 @@ static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32
}
}
-#define CLIENT_PALETTE_CACHE
-#include "cache_item.tmpl.c"
-#undef CLIENT_PALETTE_CACHE
-
-static void red_reset_palette_cache(DisplayChannelClient *dcc)
-{
- red_palette_cache_reset(dcc, CLIENT_PALETTE_CACHE_SIZE);
-}
static Drawable* drawable_try_new(DisplayChannel *display)
{
@@ -592,13 +571,6 @@ static inline void set_surface_release_info(QXLReleaseInfoExt *release_info_ext,
release_info_ext->group_id = group_id;
}
-static RedDrawable *red_drawable_ref(RedDrawable *drawable)
-{
- drawable->refs++;
- return drawable;
-}
-
-
static void red_drawable_unref(RedWorker *worker, RedDrawable *red_drawable,
uint32_t group_id)
{
@@ -2032,79 +2004,6 @@ static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
spice_marshall_DisplayBase(base_marshaller, &base);
}
-static inline void fill_palette(DisplayChannelClient *dcc,
- SpicePalette *palette,
- uint8_t *flags)
-{
- if (palette == NULL) {
- return;
- }
- if (palette->unique) {
- if (red_palette_cache_find(dcc, palette->unique)) {
- *flags |= SPICE_BITMAP_FLAGS_PAL_FROM_CACHE;
- return;
- }
- if (red_palette_cache_add(dcc, palette->unique, 1)) {
- *flags |= SPICE_BITMAP_FLAGS_PAL_CACHE_ME;
- }
- }
-}
-
-/******************************************************
- * Global lz red drawables routines
-*******************************************************/
-
-/* if already exists, returns it. Otherwise allocates and adds it (1) to the ring tail
- in the channel (2) to the Drawable*/
-static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannelClient *dcc, Drawable *drawable)
-{
- RedGlzDrawable *ret;
- RingItem *item, *next;
-
- // TODO - I don't really understand what's going on here, so doing the technical equivalent
- // now that we have multiple glz_dicts, so the only way to go from dcc to drawable glz is to go
- // over the glz_ring (unless adding some better data structure then a ring)
- DRAWABLE_FOREACH_GLZ_SAFE(drawable, item, next, ret) {
- if (ret->dcc == dcc) {
- return ret;
- }
- }
-
- ret = spice_new(RedGlzDrawable, 1);
-
- ret->dcc = dcc;
- ret->red_drawable = red_drawable_ref(drawable->red_drawable);
- ret->drawable = drawable;
- ret->group_id = drawable->group_id;
- ret->instances_count = 0;
- ring_init(&ret->instances);
-
- ring_item_init(&ret->link);
- ring_item_init(&ret->drawable_link);
- ring_add_before(&ret->link, &dcc->glz_drawables);
- ring_add(&drawable->glz_ring, &ret->drawable_link);
- DCC_TO_DC(dcc)->glz_drawable_count++;
- return ret;
-}
-
-/* allocates new instance and adds it to instances in the given drawable.
- NOTE - the caller should set the glz_instance returned by the encoder by itself.*/
-static GlzDrawableInstanceItem *red_display_add_glz_drawable_instance(RedGlzDrawable *glz_drawable)
-{
- spice_assert(glz_drawable->instances_count < MAX_GLZ_DRAWABLE_INSTANCES);
- // NOTE: We assume the additions are performed consecutively, without removals in the middle
- GlzDrawableInstanceItem *ret = glz_drawable->instances_pool + glz_drawable->instances_count;
- glz_drawable->instances_count++;
-
- ring_item_init(&ret->free_link);
- ring_item_init(&ret->glz_link);
- ring_add(&glz_drawable->instances, &ret->glz_link);
- ret->context = NULL;
- ret->glz_drawable = glz_drawable;
-
- return ret;
-}
-
/* Remove from the to_free list and the instances_list.
When no instance is left - the RedGlzDrawable is released too. (and the qxl drawable too, if
it is not used by Drawable).
@@ -2261,565 +2160,6 @@ static int red_display_free_some_independent_glz_drawables(DisplayChannelClient
return n;
}
-typedef struct compress_send_data_t {
- void* comp_buf;
- uint32_t comp_buf_size;
- SpicePalette *lzplt_palette;
- int is_lossy;
-} compress_send_data_t;
-
-static inline int red_glz_compress_image(DisplayChannelClient *dcc,
- SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
- compress_send_data_t* o_comp_data)
-{
- DisplayChannel *display_channel = DCC_TO_DC(dcc);
-#ifdef COMPRESS_STAT
- stat_time_t start_time = stat_now(display_channel->zlib_glz_stat.clock);
-#endif
- spice_assert(bitmap_fmt_is_rgb(src->format));
- GlzData *glz_data = &dcc->glz_data;
- ZlibData *zlib_data;
- LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
- RedGlzDrawable *glz_drawable;
- GlzDrawableInstanceItem *glz_drawable_instance;
- int glz_size;
- int zlib_size;
-
- glz_data->data.bufs_tail = compress_buf_new();
- glz_data->data.bufs_head = glz_data->data.bufs_tail;
- glz_data->data.dcc = dcc;
-
- glz_drawable = red_display_get_glz_drawable(dcc, drawable);
- glz_drawable_instance = red_display_add_glz_drawable_instance(glz_drawable);
-
- glz_data->data.u.lines_data.chunks = src->data;
- 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_size = glz_encode(dcc->glz, type, src->x, src->y,
- (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), NULL, 0,
- src->stride, glz_data->data.bufs_head->buf.bytes,
- sizeof(glz_data->data.bufs_head->buf),
- glz_drawable_instance,
- &glz_drawable_instance->context);
-
- stat_compress_add(&display_channel->glz_stat, start_time, src->stride * src->y, glz_size);
-
- if (!display_channel->enable_zlib_glz_wrap || (glz_size < MIN_GLZ_SIZE_FOR_ZLIB)) {
- goto glz;
- }
-#ifdef COMPRESS_STAT
- start_time = stat_now(display_channel->zlib_glz_stat.clock);
-#endif
- zlib_data = &dcc->zlib_data;
-
- zlib_data->data.bufs_tail = compress_buf_new();
- zlib_data->data.bufs_head = zlib_data->data.bufs_tail;
- 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(dcc->zlib, dcc->zlib_level,
- glz_size, zlib_data->data.bufs_head->buf.bytes,
- sizeof(zlib_data->data.bufs_head->buf));
-
- // the compressed buffer is bigger than the original data
- if (zlib_size >= glz_size) {
- while (zlib_data->data.bufs_head) {
- RedCompressBuf *buf = zlib_data->data.bufs_head;
- zlib_data->data.bufs_head = buf->send_next;
- compress_buf_free(buf);
- }
- goto glz;
- }
-
- dest->descriptor.type = SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB;
- dest->u.zlib_glz.glz_data_size = glz_size;
- dest->u.zlib_glz.data_size = zlib_size;
-
- o_comp_data->comp_buf = zlib_data->data.bufs_head;
- o_comp_data->comp_buf_size = zlib_size;
-
- stat_compress_add(&display_channel->zlib_glz_stat, start_time, glz_size, zlib_size);
- return TRUE;
-glz:
- dest->descriptor.type = SPICE_IMAGE_TYPE_GLZ_RGB;
- dest->u.lz_rgb.data_size = glz_size;
-
- o_comp_data->comp_buf = glz_data->data.bufs_head;
- o_comp_data->comp_buf_size = glz_size;
-
- return TRUE;
-}
-
-static inline int red_lz_compress_image(DisplayChannelClient *dcc,
- SpiceImage *dest, SpiceBitmap *src,
- compress_send_data_t* o_comp_data, uint32_t group_id)
-{
- 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
-
-#ifdef COMPRESS_STAT
- stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->lz_stat.clock);
-#endif
-
- lz_data->data.bufs_tail = compress_buf_new();
- lz_data->data.bufs_head = lz_data->data.bufs_tail;
- lz_data->data.dcc = dcc;
-
- if (setjmp(lz_data->data.jmp_env)) {
- while (lz_data->data.bufs_head) {
- RedCompressBuf *buf = lz_data->data.bufs_head;
- lz_data->data.bufs_head = buf->send_next;
- compress_buf_free(buf);
- }
- return FALSE;
- }
-
- lz_data->data.u.lines_data.chunks = src->data;
- 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;
-
- size = lz_encode(lz, type, src->x, src->y,
- !!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN),
- NULL, 0, src->stride,
- lz_data->data.bufs_head->buf.bytes,
- sizeof(lz_data->data.bufs_head->buf));
-
- // the compressed buffer is bigger than the original data
- if (size > (src->y * src->stride)) {
- longjmp(lz_data->data.jmp_env, 1);
- }
-
- if (bitmap_fmt_is_rgb(src->format)) {
- dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_RGB;
- dest->u.lz_rgb.data_size = size;
-
- o_comp_data->comp_buf = lz_data->data.bufs_head;
- o_comp_data->comp_buf_size = size;
- } else {
- /* masks are 1BIT bitmaps without palettes, but they are not compressed
- * (see fill_mask) */
- spice_assert(src->palette);
- dest->descriptor.type = SPICE_IMAGE_TYPE_LZ_PLT;
- dest->u.lz_plt.data_size = size;
- dest->u.lz_plt.flags = src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
- dest->u.lz_plt.palette = src->palette;
- dest->u.lz_plt.palette_id = src->palette->unique;
- o_comp_data->comp_buf = lz_data->data.bufs_head;
- o_comp_data->comp_buf_size = size;
-
- fill_palette(dcc, dest->u.lz_plt.palette, &(dest->u.lz_plt.flags));
- o_comp_data->lzplt_palette = dest->u.lz_plt.palette;
- }
-
- stat_compress_add(&DCC_TO_DC(dcc)->lz_stat, start_time, src->stride * src->y,
- o_comp_data->comp_buf_size);
- return TRUE;
-}
-
-static int red_jpeg_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
- SpiceBitmap *src, compress_send_data_t* o_comp_data,
- uint32_t group_id)
-{
- 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;
- int alpha_lz_size = 0;
- int comp_head_filled;
- int comp_head_left;
- int stride;
- uint8_t *lz_out_start_byte;
-
-#ifdef COMPRESS_STAT
- stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->jpeg_alpha_stat.clock);
-#endif
- switch (src->format) {
- case SPICE_BITMAP_FMT_16BIT:
- jpeg_in_type = JPEG_IMAGE_TYPE_RGB16;
- break;
- case SPICE_BITMAP_FMT_24BIT:
- jpeg_in_type = JPEG_IMAGE_TYPE_BGR24;
- break;
- case SPICE_BITMAP_FMT_32BIT:
- jpeg_in_type = JPEG_IMAGE_TYPE_BGRX32;
- break;
- case SPICE_BITMAP_FMT_RGBA:
- jpeg_in_type = JPEG_IMAGE_TYPE_BGRX32;
- has_alpha = TRUE;
- break;
- default:
- return FALSE;
- }
-
- jpeg_data->data.bufs_tail = compress_buf_new();
- jpeg_data->data.bufs_head = jpeg_data->data.bufs_tail;
- jpeg_data->data.dcc = dcc;
-
- if (setjmp(jpeg_data->data.jmp_env)) {
- while (jpeg_data->data.bufs_head) {
- RedCompressBuf *buf = jpeg_data->data.bufs_head;
- jpeg_data->data.bufs_head = buf->send_next;
- compress_buf_free(buf);
- }
- return FALSE;
- }
-
- if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
- spice_chunks_linearize(src->data);
- }
-
- jpeg_data->data.u.lines_data.chunks = src->data;
- jpeg_data->data.u.lines_data.stride = src->stride;
- if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
- jpeg_data->data.u.lines_data.next = 0;
- jpeg_data->data.u.lines_data.reverse = 0;
- stride = src->stride;
- } else {
- jpeg_data->data.u.lines_data.next = src->data->num_chunks - 1;
- jpeg_data->data.u.lines_data.reverse = 1;
- stride = -src->stride;
- }
- 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));
-
- // the compressed buffer is bigger than the original data
- if (jpeg_size > (src->y * src->stride)) {
- longjmp(jpeg_data->data.jmp_env, 1);
- }
-
- if (!has_alpha) {
- dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG;
- dest->u.jpeg.data_size = jpeg_size;
-
- o_comp_data->comp_buf = jpeg_data->data.bufs_head;
- o_comp_data->comp_buf_size = jpeg_size;
- o_comp_data->is_lossy = TRUE;
-
- stat_compress_add(&DCC_TO_DC(dcc)->jpeg_stat, start_time, src->stride * src->y,
- o_comp_data->comp_buf_size);
- return TRUE;
- }
-
- lz_data->data.bufs_head = jpeg_data->data.bufs_tail;
- lz_data->data.bufs_tail = lz_data->data.bufs_head;
-
- comp_head_filled = jpeg_size % sizeof(lz_data->data.bufs_head->buf);
- comp_head_left = sizeof(lz_data->data.bufs_head->buf) - comp_head_filled;
- lz_out_start_byte = lz_data->data.bufs_head->buf.bytes + comp_head_filled;
-
- lz_data->data.dcc = dcc;
-
- lz_data->data.u.lines_data.chunks = src->data;
- 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;
-
- alpha_lz_size = lz_encode(lz, LZ_IMAGE_TYPE_XXXA, src->x, src->y,
- !!(src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN),
- NULL, 0, src->stride,
- lz_out_start_byte,
- comp_head_left);
-
- // the compressed buffer is bigger than the original data
- if ((jpeg_size + alpha_lz_size) > (src->y * src->stride)) {
- longjmp(jpeg_data->data.jmp_env, 1);
- }
-
- dest->descriptor.type = SPICE_IMAGE_TYPE_JPEG_ALPHA;
- dest->u.jpeg_alpha.flags = 0;
- if (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN) {
- dest->u.jpeg_alpha.flags |= SPICE_JPEG_ALPHA_FLAGS_TOP_DOWN;
- }
-
- dest->u.jpeg_alpha.jpeg_size = jpeg_size;
- dest->u.jpeg_alpha.data_size = jpeg_size + alpha_lz_size;
-
- o_comp_data->comp_buf = jpeg_data->data.bufs_head;
- o_comp_data->comp_buf_size = jpeg_size + alpha_lz_size;
- o_comp_data->is_lossy = TRUE;
- stat_compress_add(&DCC_TO_DC(dcc)->jpeg_alpha_stat, start_time, src->stride * src->y,
- o_comp_data->comp_buf_size);
- return TRUE;
-}
-
-#ifdef USE_LZ4
-static int red_lz4_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
- SpiceBitmap *src, compress_send_data_t* o_comp_data,
- uint32_t group_id)
-{
- Lz4Data *lz4_data = &dcc->lz4_data;
- Lz4EncoderContext *lz4 = dcc->lz4;
- int lz4_size = 0;
-
-#ifdef COMPRESS_STAT
- stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->lz4_stat.clock);
-#endif
-
- lz4_data->data.bufs_tail = compress_buf_new();
- lz4_data->data.bufs_head = lz4_data->data.bufs_tail;
-
- if (!lz4_data->data.bufs_head) {
- spice_warning("failed to allocate compress buffer");
- return FALSE;
- }
-
- lz4_data->data.bufs_head->send_next = NULL;
- lz4_data->data.dcc = dcc;
-
- if (setjmp(lz4_data->data.jmp_env)) {
- while (lz4_data->data.bufs_head) {
- RedCompressBuf *buf = lz4_data->data.bufs_head;
- lz4_data->data.bufs_head = buf->send_next;
- compress_buf_free(buf);
- }
- return FALSE;
- }
-
- if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
- spice_chunks_linearize(src->data);
- }
-
- lz4_data->data.u.lines_data.chunks = src->data;
- lz4_data->data.u.lines_data.stride = src->stride;
- lz4_data->data.u.lines_data.next = 0;
- lz4_data->data.u.lines_data.reverse = 0;
- /* 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),
- src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN, src->format);
-
- // the compressed buffer is bigger than the original data
- if (lz4_size > (src->y * src->stride)) {
- longjmp(lz4_data->data.jmp_env, 1);
- }
-
- dest->descriptor.type = SPICE_IMAGE_TYPE_LZ4;
- dest->u.lz4.data_size = lz4_size;
-
- o_comp_data->comp_buf = lz4_data->data.bufs_head;
- o_comp_data->comp_buf_size = lz4_size;
-
- stat_compress_add(&DCC_TO_DC(dcc)->lz4_stat, start_time, src->stride * src->y,
- o_comp_data->comp_buf_size);
- return TRUE;
-}
-#endif
-
-static inline int red_quic_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
- SpiceBitmap *src, compress_send_data_t* o_comp_data,
- uint32_t group_id)
-{
- QuicData *quic_data = &dcc->quic_data;
- QuicContext *quic = dcc->quic;
- volatile QuicImageType type;
- int size, stride;
-
-#ifdef COMPRESS_STAT
- stat_time_t start_time = stat_now(DCC_TO_DC(dcc)->quic_stat.clock);
-#endif
-
- switch (src->format) {
- case SPICE_BITMAP_FMT_32BIT:
- type = QUIC_IMAGE_TYPE_RGB32;
- break;
- case SPICE_BITMAP_FMT_RGBA:
- type = QUIC_IMAGE_TYPE_RGBA;
- break;
- case SPICE_BITMAP_FMT_16BIT:
- type = QUIC_IMAGE_TYPE_RGB16;
- break;
- case SPICE_BITMAP_FMT_24BIT:
- type = QUIC_IMAGE_TYPE_RGB24;
- break;
- default:
- return FALSE;
- }
-
- quic_data->data.bufs_tail = compress_buf_new();
- quic_data->data.bufs_head = quic_data->data.bufs_tail;
- quic_data->data.dcc = dcc;
-
- if (setjmp(quic_data->data.jmp_env)) {
- while (quic_data->data.bufs_head) {
- RedCompressBuf *buf = quic_data->data.bufs_head;
- quic_data->data.bufs_head = buf->send_next;
- compress_buf_free(buf);
- }
- return FALSE;
- }
-
- if (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE) {
- spice_chunks_linearize(src->data);
- }
-
- quic_data->data.u.lines_data.chunks = src->data;
- quic_data->data.u.lines_data.stride = src->stride;
- if ((src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
- quic_data->data.u.lines_data.next = 0;
- quic_data->data.u.lines_data.reverse = 0;
- stride = src->stride;
- } else {
- quic_data->data.u.lines_data.next = src->data->num_chunks - 1;
- quic_data->data.u.lines_data.reverse = 1;
- stride = -src->stride;
- }
- size = quic_encode(quic, type, src->x, src->y, NULL, 0, stride,
- quic_data->data.bufs_head->buf.words,
- G_N_ELEMENTS(quic_data->data.bufs_head->buf.words));
-
- // the compressed buffer is bigger than the original data
- if ((size << 2) > (src->y * src->stride)) {
- longjmp(quic_data->data.jmp_env, 1);
- }
-
- dest->descriptor.type = SPICE_IMAGE_TYPE_QUIC;
- dest->u.quic.data_size = size << 2;
-
- o_comp_data->comp_buf = quic_data->data.bufs_head;
- o_comp_data->comp_buf_size = size << 2;
-
- stat_compress_add(&DCC_TO_DC(dcc)->quic_stat, start_time, src->stride * src->y,
- o_comp_data->comp_buf_size);
- return TRUE;
-}
-
-#define MIN_SIZE_TO_COMPRESS 54
-#define MIN_DIMENSION_TO_QUIC 3
-static inline int red_compress_image(DisplayChannelClient *dcc,
- SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
- int can_lossy,
- compress_send_data_t* o_comp_data)
-{
- DisplayChannel *display_channel = DCC_TO_DC(dcc);
- SpiceImageCompression image_compression = dcc->image_compression;
- int quic_compress = FALSE;
-
- if ((image_compression == SPICE_IMAGE_COMPRESSION_OFF) ||
- ((src->y * src->stride) < MIN_SIZE_TO_COMPRESS)) { // TODO: change the size cond
- return FALSE;
- } else if (image_compression == SPICE_IMAGE_COMPRESSION_QUIC) {
- if (bitmap_fmt_is_plt(src->format)) {
- return FALSE;
- } else {
- quic_compress = TRUE;
- }
- } else {
- /*
- lz doesn't handle (1) bitmaps with strides that are larger than the width
- of the image in bytes (2) unstable bitmaps
- */
- if (bitmap_has_extra_stride(src) || (src->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE)) {
- if ((image_compression == SPICE_IMAGE_COMPRESSION_LZ) ||
- (image_compression == SPICE_IMAGE_COMPRESSION_GLZ) ||
- (image_compression == SPICE_IMAGE_COMPRESSION_LZ4) ||
- bitmap_fmt_is_plt(src->format)) {
- return FALSE;
- } else {
- quic_compress = TRUE;
- }
- } else {
- if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
- (image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ)) {
- if ((src->x < MIN_DIMENSION_TO_QUIC) || (src->y < MIN_DIMENSION_TO_QUIC)) {
- quic_compress = FALSE;
- } else {
- if (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_INVALID) {
- quic_compress = bitmap_fmt_has_graduality(src->format) &&
- bitmap_get_graduality_level(src) == BITMAP_GRADUAL_HIGH;
- } else {
- quic_compress = (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_HIGH);
- }
- }
- } else {
- quic_compress = FALSE;
- }
- }
- }
-
- if (quic_compress) {
-#ifdef COMPRESS_DEBUG
- spice_info("QUIC compress");
-#endif
- // if bitmaps is picture-like, compress it using jpeg
- if (can_lossy && display_channel->enable_jpeg &&
- ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
- (image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ))) {
- // if we use lz for alpha, the stride can't be extra
- if (src->format != SPICE_BITMAP_FMT_RGBA || !bitmap_has_extra_stride(src)) {
- return red_jpeg_compress_image(dcc, dest,
- src, o_comp_data, drawable->group_id);
- }
- }
- return red_quic_compress_image(dcc, dest,
- src, o_comp_data, drawable->group_id);
- } else {
- int glz;
- int ret;
- if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ) ||
- (image_compression == SPICE_IMAGE_COMPRESSION_GLZ)) {
- glz = bitmap_fmt_has_graduality(src->format) && (
- (src->x * src->y) < glz_enc_dictionary_get_size(
- dcc->glz_dict->dict));
- } else if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) ||
- (image_compression == SPICE_IMAGE_COMPRESSION_LZ) ||
- (image_compression == SPICE_IMAGE_COMPRESSION_LZ4)) {
- glz = FALSE;
- } else {
- spice_error("invalid image compression type %u", image_compression);
- return FALSE;
- }
-
- if (glz) {
- /* using the global dictionary only if it is not frozen */
- pthread_rwlock_rdlock(&dcc->glz_dict->encode_lock);
- if (!dcc->glz_dict->migrate_freeze) {
- ret = red_glz_compress_image(dcc,
- dest, src,
- drawable, o_comp_data);
- } else {
- glz = FALSE;
- }
- pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
- }
-
- if (!glz) {
-#ifdef USE_LZ4
- if (image_compression == SPICE_IMAGE_COMPRESSION_LZ4 &&
- bitmap_fmt_is_rgb(src->format) &&
- red_channel_client_test_remote_cap(&dcc->common.base,
- SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) {
- ret = red_lz4_compress_image(dcc, dest, src, o_comp_data,
- drawable->group_id);
- } else
-#endif
- ret = red_lz_compress_image(dcc, dest, src, o_comp_data,
- drawable->group_id);
-#ifdef COMPRESS_DEBUG
- spice_info("LZ LOCAL compress");
-#endif
- }
-#ifdef COMPRESS_DEBUG
- else {
- spice_info("LZ global compress fmt=%d", src->format);
- }
-#endif
- return ret;
- }
-}
-
int dcc_pixmap_cache_unlocked_add(DisplayChannelClient *dcc, uint64_t id, uint32_t size, int lossy)
{
PixmapCache *cache = dcc->pixmap_cache;
@@ -3043,7 +2383,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
in order to prevent starvation in the client between pixmap_cache and
global dictionary (in cases of multiple monitors) */
if (reds_stream_get_family(rcc->stream) == AF_UNIX ||
- !red_compress_image(dcc, &image, &simage->u.bitmap,
+ !dcc_compress_image(dcc, &image, &simage->u.bitmap,
drawable, can_lossy, &comp_send_data)) {
SpicePalette *palette;
@@ -3053,7 +2393,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
bitmap->flags = bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
palette = bitmap->palette;
- fill_palette(dcc, palette, &bitmap->flags);
+ dcc_palette_cache_palette(dcc, palette, &bitmap->flags);
spice_marshall_Image(m, &image,
&bitmap_palette_out, &lzplt_palette_out);
spice_assert(lzplt_palette_out == NULL);
@@ -5021,11 +4361,11 @@ static void red_marshall_image(RedChannelClient *rcc, SpiceMarshaller *m, ImageI
}
if (lossy_comp) {
- comp_succeeded = red_jpeg_compress_image(dcc, &red_image,
+ comp_succeeded = dcc_compress_image_jpeg(dcc, &red_image,
&bitmap, &comp_send_data,
worker->mem_slots.internal_groupslot_id);
} else if (quic_comp) {
- comp_succeeded = red_quic_compress_image(dcc, &red_image, &bitmap,
+ comp_succeeded = dcc_compress_image_quic(dcc, &red_image, &bitmap,
&comp_send_data,
worker->mem_slots.internal_groupslot_id);
#ifdef USE_LZ4
@@ -5033,12 +4373,12 @@ static void red_marshall_image(RedChannelClient *rcc, SpiceMarshaller *m, ImageI
bitmap_fmt_is_rgb(bitmap.format) &&
red_channel_client_test_remote_cap(&dcc->common.base,
SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) {
- comp_succeeded = red_lz4_compress_image(dcc, &red_image, &bitmap,
+ comp_succeeded = dcc_compress_image_lz4(dcc, &red_image, &bitmap,
&comp_send_data,
worker->mem_slots.internal_groupslot_id);
#endif
} else if (comp_mode != SPICE_IMAGE_COMPRESSION_OFF) {
- comp_succeeded = red_lz_compress_image(dcc, &red_image, &bitmap,
+ comp_succeeded = dcc_compress_image_lz(dcc, &red_image, &bitmap,
&comp_send_data,
worker->mem_slots.internal_groupslot_id);
}
@@ -5286,7 +4626,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
display_channel_marshall_reset_cache(rcc, m);
break;
case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE:
- red_reset_palette_cache(dcc);
+ dcc_palette_cache_reset(dcc);
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES, NULL);
break;
case PIPE_ITEM_TYPE_CREATE_SURFACE: {
@@ -5355,7 +4695,7 @@ static void display_channel_client_on_disconnect(RedChannelClient *rcc)
pixmap_cache_unref(dcc->pixmap_cache);
dcc->pixmap_cache = NULL;
red_release_glz(dcc);
- red_reset_palette_cache(dcc);
+ dcc_palette_cache_reset(dcc);
free(dcc->send_data.stream_outbuf);
free(dcc->send_data.free_list.res);
dcc_destroy_stream_agents(dcc);
@@ -6944,7 +6284,7 @@ static void handle_dev_oom(void *opaque, void *payload)
RedChannel *display_red_channel = &worker->display_channel->common.base;
int ring_is_empty;
- spice_assert(worker->running);
+ spice_return_if_fail(worker->running);
// streams? but without streams also leak
spice_debug("OOM1 #draw=%u, #red_draw=%u, #glz_draw=%u current %u pipes %u",
display->drawable_count,
commit 5229613d515ea8020dac32123bb34af2ab41afe1
Author: Frediano Ziglio <fziglio at redhat.com>
Date: Thu Nov 19 13:42:43 2015 +0000
worker: move glz_drawable_count to DisplayChannel
Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
diff --git a/server/display-channel.h b/server/display-channel.h
index 69ceb3c..7f3949f 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -194,6 +194,8 @@ struct DisplayChannel {
_Drawable drawables[NUM_DRAWABLES];
_Drawable *free_drawables;
+ uint32_t glz_drawable_count;
+
int stream_video;
uint32_t stream_count;
Stream streams_buf[NUM_STREAMS];
diff --git a/server/red_worker.c b/server/red_worker.c
index 32612d5..eab00ff 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -146,7 +146,6 @@ struct RedWorker {
uint32_t cursor_poll_tries;
uint32_t red_drawable_count;
- uint32_t glz_drawable_count;
uint32_t bits_unique;
RedMemSlotInfo mem_slots;
@@ -1925,7 +1924,7 @@ static void red_free_some(RedWorker *worker)
RingItem *item, *next;
spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d", display->drawable_count,
- worker->red_drawable_count, worker->glz_drawable_count);
+ worker->red_drawable_count, display->glz_drawable_count);
FOREACH_DCC(worker->display_channel, item, next, dcc) {
GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
@@ -2084,7 +2083,7 @@ static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannelClient *dcc, D
ring_item_init(&ret->drawable_link);
ring_add_before(&ret->link, &dcc->glz_drawables);
ring_add(&drawable->glz_ring, &ret->drawable_link);
- DCC_TO_WORKER(dcc)->glz_drawable_count++;
+ DCC_TO_DC(dcc)->glz_drawable_count++;
return ret;
}
@@ -2144,7 +2143,7 @@ void dcc_free_glz_drawable_instance(DisplayChannelClient *dcc,
}
red_drawable_unref(worker, glz_drawable->red_drawable,
glz_drawable->group_id);
- worker->glz_drawable_count--;
+ display_channel->glz_drawable_count--;
if (ring_item_is_linked(&glz_drawable->link)) {
ring_remove(&glz_drawable->link);
}
@@ -5364,7 +5363,7 @@ static void display_channel_client_on_disconnect(RedChannelClient *rcc)
// this was the last channel client
spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d",
display->drawable_count, worker->red_drawable_count,
- worker->glz_drawable_count);
+ display->glz_drawable_count);
}
void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
@@ -6950,7 +6949,7 @@ static void handle_dev_oom(void *opaque, void *payload)
spice_debug("OOM1 #draw=%u, #red_draw=%u, #glz_draw=%u current %u pipes %u",
display->drawable_count,
worker->red_drawable_count,
- worker->glz_drawable_count,
+ display->glz_drawable_count,
display->current_size,
worker->display_channel ?
red_channel_sum_pipes_size(display_red_channel) : 0);
@@ -6964,7 +6963,7 @@ static void handle_dev_oom(void *opaque, void *payload)
spice_debug("OOM2 #draw=%u, #red_draw=%u, #glz_draw=%u current %u pipes %u",
display->drawable_count,
worker->red_drawable_count,
- worker->glz_drawable_count,
+ display->glz_drawable_count,
display->current_size,
worker->display_channel ?
red_channel_sum_pipes_size(display_red_channel) : 0);
More information about the Spice-commits
mailing list