[Spice-devel] [RFC v4 29/62] server/red_worker: split display and cursor channels
Alon Levy
alevy at redhat.com
Thu May 5 06:01:39 PDT 2011
On Tue, May 03, 2011 at 01:56:25AM +0200, Marc-André Lureau wrote:
> On Tue, Apr 26, 2011 at 12:54 PM, Alon Levy <alevy at redhat.com> wrote:
> > Introduce DisplayChannelClient, CursorChannelClient, CommonChannelClient.
> > don't disconnect channel on client disconnect.
> > Move all caches to the ChannelClient's.
> >
> > Remove reference counting of the channel - need to split this to a separate
> > patch. The rationalization for this:
> > /* TODO: Why do we reference count the listener?
> > * really - what's the lifecycle of a listener? isn't it from peer connection
> > * until removal? the drawable's etc. have a valid lifetime outside of this, but
> > * isn't the listener's lifetime exactly this?
> > * This was meant to allow deletion of the display_channel itself - but now
> > * we don't actually ever delete that.
> > * */
> >
> > No new functionality introduced.
> >
> > TODO: fix crash:
> > Still have the possibility of crashing if too many disconnections happen at
> > once. Noticed that this happens if we call disconnect with two different channel
> > clients pointing to the same channel. should make sure the channel destruction
> > happens from a single thread? should only happen from main thread. check
> > by printing pthread_self.
> > ---
> > server/red_channel.c | 12 -
> > server/red_channel.h | 2 -
> > server/red_client_cache.h | 54 +-
> > server/red_client_shared_cache.h | 50 +-
> > server/red_worker.c | 1709 +++++++++++++++++++++-----------------
> > 5 files changed, 1019 insertions(+), 808 deletions(-)
> >
> > diff --git a/server/red_channel.c b/server/red_channel.c
> > index b2d0cdb..4625158 100644
> > --- a/server/red_channel.c
> > +++ b/server/red_channel.c
> > @@ -840,23 +840,11 @@ void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc)
> > rcc->ack_data.messages_window = 0;
> > }
> >
> > -void red_channel_ack_zero_messages_window(RedChannel *channel)
> > -{
> > - red_channel_client_ack_zero_messages_window(channel->rcc);
> > -}
> > -
> > void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window)
> > {
> > rcc->ack_data.client_window = client_window;
> > }
> >
> > -void red_channel_ack_set_client_window(RedChannel* channel, int client_window)
> > -{
> > - if (channel->rcc) {
> > - red_channel_client_ack_set_client_window(channel->rcc, client_window);
> > - }
> > -}
> > -
> > static void red_channel_client_unlink(RedChannelClient *rcc)
> > {
> > ring_remove(&rcc->client_link);
> > diff --git a/server/red_channel.h b/server/red_channel.h
> > index 44a40f0..261aa60 100644
> > --- a/server/red_channel.h
> > +++ b/server/red_channel.h
> > @@ -296,8 +296,6 @@ void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type);
> > void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc);
> > void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window);
> > void red_channel_client_push_set_ack(RedChannelClient *rcc);
> > -void red_channel_ack_zero_messages_window(RedChannel *channel);
> > -void red_channel_ack_set_client_window(RedChannel *channel, int client_window);
> > void red_channel_push_set_ack(RedChannel *channel);
> >
> > /* TODO: This sets all clients to shut state - probably we want to close per channel */
> > diff --git a/server/red_client_cache.h b/server/red_client_cache.h
> > index 18ff47e..ea90b97 100644
> > --- a/server/red_client_cache.h
> > +++ b/server/red_client_cache.h
> > @@ -24,7 +24,7 @@
> > #define FUNC_NAME(name) red_cursor_cache_##name
> > #define VAR_NAME(name) cursor_cache_##name
> > #define CHANNEL CursorChannel
> > -#define CHANNELCLIENT RedChannelClient
> > +#define CHANNELCLIENT CursorChannelClient
> >
> > #elif defined(CLIENT_PALETTE_CACHE)
> >
> > @@ -35,7 +35,7 @@
> > #define FUNC_NAME(name) red_palette_cache_##name
> > #define VAR_NAME(name) palette_cache_##name
> > #define CHANNEL DisplayChannel
> > -#define CHANNELCLIENT RedChannelClient
> > +#define CHANNELCLIENT DisplayChannelClient
> > #else
> >
> > #error "no cache type."
> > @@ -44,14 +44,14 @@
> >
> > #define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
> >
> > -static CacheItem *FUNC_NAME(find)(CHANNEL *channel, uint64_t id)
> > +static CacheItem *FUNC_NAME(find)(CHANNELCLIENT *channel_client, uint64_t id)
> > {
> > - CacheItem *item = channel->CACHE_NAME[CACHE_HASH_KEY(id)];
> > + CacheItem *item = channel_client->CACHE_NAME[CACHE_HASH_KEY(id)];
> >
> > while (item) {
> > if (item->id == id) {
> > ring_remove(&item->u.cache_data.lru_link);
> > - ring_add(&channel->VAR_NAME(lru), &item->u.cache_data.lru_link);
> > + ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link);
> > break;
> > }
> > item = item->u.cache_data.next;
> > @@ -62,10 +62,10 @@ static CacheItem *FUNC_NAME(find)(CHANNEL *channel, uint64_t id)
> > static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, CacheItem *item)
> > {
> > CacheItem **now;
> > - CHANNEL *channel = CHANNEL_FROM_RCC(channel_client);
> > + CHANNEL *channel = CHANNEL_FROM_RCC(&channel_client->common.base);
> > ASSERT(item);
> >
> > - now = &channel->CACHE_NAME[CACHE_HASH_KEY(item->id)];
> > + now = &channel_client->CACHE_NAME[CACHE_HASH_KEY(item->id)];
> > for (;;) {
> > ASSERT(*now);
> > if (*now == item) {
> > @@ -75,56 +75,55 @@ static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, CacheItem *item)
> > now = &(*now)->u.cache_data.next;
> > }
> > ring_remove(&item->u.cache_data.lru_link);
> > - channel->VAR_NAME(items)--;
> > - channel->VAR_NAME(available) += item->size;
> > + channel_client->VAR_NAME(items)--;
> > + channel_client->VAR_NAME(available) += item->size;
> >
> > red_channel_pipe_item_init(&channel->common.base, &item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE);
> > - red_channel_client_pipe_add_tail(channel_client, &item->u.pipe_data); // for now
> > + red_channel_client_pipe_add_tail(&channel_client->common.base, &item->u.pipe_data); // for now
> > }
> >
> > static int FUNC_NAME(add)(CHANNELCLIENT *channel_client, uint64_t id, size_t size)
> > {
> > - CHANNEL *channel = CHANNEL_FROM_RCC(channel_client);
> > CacheItem *item;
> > int key;
> >
> > item = spice_new(CacheItem, 1);
> >
> > - channel->VAR_NAME(available) -= size;
> > - while (channel->VAR_NAME(available) < 0) {
> > - CacheItem *tail = (CacheItem *)ring_get_tail(&channel->VAR_NAME(lru));
> > + channel_client->VAR_NAME(available) -= size;
> > + while (channel_client->VAR_NAME(available) < 0) {
> > + CacheItem *tail = (CacheItem *)ring_get_tail(&channel_client->VAR_NAME(lru));
> > if (!tail) {
> > - channel->VAR_NAME(available) += size;
> > + channel_client->VAR_NAME(available) += size;
> > free(item);
> > return FALSE;
> > }
> > FUNC_NAME(remove)(channel_client, tail);
> > }
> > - ++channel->VAR_NAME(items);
> > - item->u.cache_data.next = channel->CACHE_NAME[(key = CACHE_HASH_KEY(id))];
> > - channel->CACHE_NAME[key] = item;
> > + ++channel_client->VAR_NAME(items);
> > + item->u.cache_data.next = channel_client->CACHE_NAME[(key = CACHE_HASH_KEY(id))];
> > + channel_client->CACHE_NAME[key] = item;
> > ring_item_init(&item->u.cache_data.lru_link);
> > - ring_add(&channel->VAR_NAME(lru), &item->u.cache_data.lru_link);
> > + ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link);
> > item->id = id;
> > item->size = size;
> > item->inval_type = CACHE_INVAL_TYPE;
> > return TRUE;
> > }
> >
> > -static void FUNC_NAME(reset)(CHANNEL *channel, long size)
> > +static void FUNC_NAME(reset)(CHANNELCLIENT *channel_client, long size)
> > {
> > int i;
> >
> > for (i = 0; i < CACHE_HASH_SIZE; i++) {
> > - while (channel->CACHE_NAME[i]) {
> > - CacheItem *item = channel->CACHE_NAME[i];
> > - channel->CACHE_NAME[i] = item->u.cache_data.next;
> > + while (channel_client->CACHE_NAME[i]) {
> > + CacheItem *item = channel_client->CACHE_NAME[i];
> > + channel_client->CACHE_NAME[i] = item->u.cache_data.next;
> > free(item);
> > }
> > }
> > - ring_init(&channel->VAR_NAME(lru));
> > - channel->VAR_NAME(available) = size;
> > - channel->VAR_NAME(items) = 0;
> > + ring_init(&channel_client->VAR_NAME(lru));
> > + channel_client->VAR_NAME(available) = size;
> > + channel_client->VAR_NAME(items) = 0;
> > }
> >
> >
> > @@ -136,4 +135,5 @@ static void FUNC_NAME(reset)(CHANNEL *channel, long size)
> > #undef FUNC_NAME
> > #undef VAR_NAME
> > #undef CHANNEL
> > -
> > +#undef CHANNELCLIENT
> > +#undef CHANNEL_FROM_RCC
>
> Last line should be with 05/62: move pipe from RedChannel
done.
>
> > \ No newline at end of file
> > diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
> > index 9b4b01c..533fb67 100644
> > --- a/server/red_client_shared_cache.h
> > +++ b/server/red_client_shared_cache.h
> > @@ -26,7 +26,6 @@
> > #define FUNC_NAME(name) pixmap_cache_##name
> > #define PRIVATE_FUNC_NAME(name) __pixmap_cache_##name
> > #define CHANNEL DisplayChannel
> > -#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF(rcc->channel, CHANNEL, common.base);
> > #define CACH_GENERATION pixmap_cache_generation
> > #define INVAL_ALL_VERB SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS
> > #else
> > @@ -35,14 +34,14 @@
> >
> > #endif
> >
> > +#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
> >
> > -static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, RedChannelClient *rcc)
> > +static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, DisplayChannelClient *dcc)
> > {
> > - CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
> > NewCacheItem *item;
> > uint64_t serial;
> >
> > - serial = red_channel_client_get_message_serial(rcc);
> > + serial = red_channel_client_get_message_serial(&dcc->common.base);
> > pthread_mutex_lock(&cache->lock);
> > item = cache->hash_table[CACHE_HASH_KEY(id)];
> >
> > @@ -50,9 +49,9 @@ static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, RedChannelClien
> > if (item->id == id) {
> > ring_remove(&item->lru_link);
> > ring_add(&cache->lru, &item->lru_link);
> > - ASSERT(channel->common.id < MAX_CACHE_CLIENTS)
> > - item->sync[channel->common.id] = serial;
> > - cache->sync[channel->common.id] = serial;
> > + ASSERT(dcc->common.id < MAX_CACHE_CLIENTS)
> > + item->sync[dcc->common.id] = serial;
> > + cache->sync[dcc->common.id] = serial;
> > *lossy = item->lossy;
> > break;
> > }
> > @@ -81,9 +80,8 @@ static int FUNC_NAME(set_lossy)(CACHE *cache, uint64_t id, int lossy)
> > return !!item;
> > }
> >
> > -static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, RedChannelClient *rcc)
> > +static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, DisplayChannelClient *dcc)
> > {
> > - CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
> > NewCacheItem *item;
> > uint64_t serial;
> > int key;
> > @@ -91,14 +89,15 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
> > ASSERT(size > 0);
> >
> > item = spice_new(NewCacheItem, 1);
> > - serial = red_channel_client_get_message_serial(rcc);
> > + serial = red_channel_client_get_message_serial(&dcc->common.base);
> >
> > pthread_mutex_lock(&cache->lock);
> >
> > - if (cache->generation != channel->CACH_GENERATION) {
> > - if (!channel->pending_pixmaps_sync) {
> > - red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_PIXMAP_SYNC);
> > - channel->pending_pixmaps_sync = TRUE;
> > + if (cache->generation != dcc->CACH_GENERATION) {
> > + if (!dcc->pending_pixmaps_sync) {
> > + red_channel_client_pipe_add_type(
> > + &dcc->common.base, PIPE_ITEM_TYPE_PIXMAP_SYNC);
> > + dcc->pending_pixmaps_sync = TRUE;
> > }
> > pthread_mutex_unlock(&cache->lock);
> > free(item);
> > @@ -111,7 +110,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
> > NewCacheItem **now;
> >
> > if (!(tail = (NewCacheItem *)ring_get_tail(&cache->lru)) ||
> > - tail->sync[channel->common.id] == serial) {
> > + tail->sync[dcc->common.id] == serial) {
> > cache->available += size;
> > pthread_mutex_unlock(&cache->lock);
> > free(item);
> > @@ -130,8 +129,8 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
> > ring_remove(&tail->lru_link);
> > cache->items--;
> > cache->available += tail->size;
> > - cache->sync[channel->common.id] = serial;
> > - display_channel_push_release(channel, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync);
> > + cache->sync[dcc->common.id] = serial;
> > + display_channel_push_release(dcc, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync);
> > free(tail);
> > }
> > ++cache->items;
> > @@ -143,8 +142,8 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
> > item->size = size;
> > item->lossy = lossy;
> > memset(item->sync, 0, sizeof(item->sync));
> > - item->sync[channel->common.id] = serial;
> > - cache->sync[channel->common.id] = serial;
> > + item->sync[dcc->common.id] = serial;
> > + cache->sync[dcc->common.id] = serial;
> > pthread_mutex_unlock(&cache->lock);
> > return TRUE;
> > }
> > @@ -169,25 +168,24 @@ static void PRIVATE_FUNC_NAME(clear)(CACHE *cache)
> > cache->items = 0;
> > }
> >
> > -static void FUNC_NAME(reset)(CACHE *cache, RedChannelClient *rcc, SpiceMsgWaitForChannels* sync_data)
> > +static void FUNC_NAME(reset)(CACHE *cache, DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data)
> > {
> > - CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
> > uint8_t wait_count;
> > uint64_t serial;
> > uint32_t i;
> >
> > - serial = red_channel_client_get_message_serial(rcc);
> > + serial = red_channel_client_get_message_serial(&dcc->common.base);
> > pthread_mutex_lock(&cache->lock);
> > PRIVATE_FUNC_NAME(clear)(cache);
> >
> > - channel->CACH_GENERATION = ++cache->generation;
> > - cache->generation_initiator.client = channel->common.id;
> > + dcc->CACH_GENERATION = ++cache->generation;
> > + cache->generation_initiator.client = dcc->common.id;
> > cache->generation_initiator.message = serial;
> > - cache->sync[channel->common.id] = serial;
> > + cache->sync[dcc->common.id] = serial;
> >
> > wait_count = 0;
> > for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
> > - if (cache->sync[i] && i != channel->common.id) {
> > + if (cache->sync[i] && i != dcc->common.id) {
> > sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY;
> > sync_data->wait_list[wait_count].channel_id = i;
> > sync_data->wait_list[wait_count++].message_serial = cache->sync[i];
> > diff --git a/server/red_worker.c b/server/red_worker.c
> > index 1c9bf1c..683df38 100644
> > --- a/server/red_worker.c
> > +++ b/server/red_worker.c
> > @@ -16,6 +16,16 @@
> > License along with this library; if not, see <http://www.gnu.org/licenses/>.
> > */
> >
> > +/* Common variable abberiviations:
> > + *
> > + * rcc - RedChannelClient
> > + * ccc - CursorChannelClient (not to be confused with common_cc)
> > + * common_cc - CommonChannelClient
> > + * dcc - DisplayChannelClient
> > + * cursor_red_channel - downcast of CursorChannel to RedChannel
> > + * display_red_channel - downcast of DisplayChannel to RedChannel
> > + */
> > +
> > #include <stdio.h>
> > #include <stdarg.h>
> > #include <sys/epoll.h>
> > @@ -467,9 +477,10 @@ typedef struct FreeList {
> > } FreeList;
> >
> > typedef struct DisplayChannel DisplayChannel;
> > +typedef struct DisplayChannelClient DisplayChannelClient;
> >
> > typedef struct {
> > - DisplayChannel *display_channel;
> > + DisplayChannelClient *dcc;
> > RedCompressBuf *bufs_head;
> > RedCompressBuf *bufs_tail;
> > jmp_buf jmp_env;
> > @@ -537,7 +548,7 @@ struct RedGlzDrawable {
> > GlzDrawableInstanceItem instances_pool[MAX_GLZ_DRAWABLE_INSTANCES];
> > Ring instances;
> > uint8_t instances_count;
> > - DisplayChannel *display_channel;
> > + DisplayChannelClient *dcc;
> > };
> >
> > pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER;
> > @@ -556,16 +567,23 @@ typedef struct GlzSharedDictionary {
> >
> > typedef struct CommonChannel {
> > RedChannel base; // Must be the first thing
> > - EventListener listener;
> > - uint32_t id;
> > + event_listener_action_proc listener_action;
> > struct RedWorker *worker;
> > uint8_t recv_buf[RECIVE_BUF_SIZE];
> > + uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme.
> > } CommonChannel;
> >
> > typedef struct Surfaces Surfaces;
> >
> > -struct DisplayChannel {
> > - CommonChannel common; // Must be the first thing
> > +typedef struct CommonChannelClient {
> > + RedChannelClient base;
> > + EventListener listener;
> > + uint32_t id;
> > + Surfaces *surfaces;
> > +} CommonChannelClient;
> > +
> > +struct DisplayChannelClient {
> > + CommonChannelClient common;
> >
> > int expect_init;
> > int expect_migrate_mark;
> > @@ -580,7 +598,15 @@ struct DisplayChannel {
> > long palette_cache_available;
> > uint32_t palette_cache_items;
> >
> > - StreamAgent stream_agents[NUM_STREAMS];
> > + struct {
> > + uint32_t stream_outbuf_size;
> > + uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
> > +
> > + RedCompressBuf *free_compress_bufs;
> > + RedCompressBuf *used_compress_bufs;
> > +
> > + FreeList free_list;
> > + } send_data;
> >
> > /* global lz encoding entities */
> > GlzSharedDictionary *glz_dict;
> > @@ -594,15 +620,16 @@ struct DisplayChannel {
> > uint8_t surface_client_created[NUM_SURFACES];
> > QRegion surface_client_lossy_region[NUM_SURFACES];
> >
> > - struct {
> > - uint32_t stream_outbuf_size;
> > - uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
> > + StreamAgent stream_agents[NUM_STREAMS];
> > +};
> >
> > - RedCompressBuf *free_compress_bufs;
> > - RedCompressBuf *used_compress_bufs;
> > +struct DisplayChannel {
> > + CommonChannel common; // Must be the first thing
> >
> > - FreeList free_list;
> > - } send_data;
> > + // only required for one client, can be the first (or choose it by speed
> > + // and keep a pointer to it here?)
> > + int expect_migrate_mark;
> > + int expect_migrate_data;
> >
> > int enable_jpeg;
> > int jpeg_quality;
> > @@ -624,13 +651,17 @@ struct DisplayChannel {
> > #endif
> > };
> >
> > -typedef struct CursorChannel {
> > - CommonChannel common; // Must be the first thing
> > +typedef struct CursorChannelClient {
> > + CommonChannelClient common;
> >
> > CacheItem *cursor_cache[CURSOR_CACHE_HASH_SIZE];
> > Ring cursor_cache_lru;
> > long cursor_cache_available;
> > uint32_t cursor_cache_items;
> > +} CursorChannelClient;
> > +
> > +typedef struct CursorChannel {
> > + CommonChannel common; // Must be the first thing
> >
> > #ifdef RED_STATISTICS
> > StatNodeRef stat;
> > @@ -820,6 +851,8 @@ struct Surfaces {
> > uint32_t n_surfaces;
> > SpiceImageSurfaces image_surfaces;
> >
> > + DisplayChannelClient *dcc; // NULL possible (iff no clients)
> > +
> > Stream streams_buf[NUM_STREAMS];
> > Stream *free_streams;
> > Ring streams;
> > @@ -932,25 +965,26 @@ static void red_update_area_surfaces(RedWorker *worker, Surfaces *surfaces,
> > #endif
> > static void red_release_cursor(RedWorker *worker, CursorItem *cursor);
> > static inline void release_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *item);
> > -static void red_display_release_stream(DisplayChannel *display, StreamAgent *agent);
> > +static void red_display_release_stream(Surfaces *surfaces, StreamAgent *agent);
> > static inline void red_detach_stream(Surfaces *surfaces, Stream *stream);
> > -static void red_stop_stream(RedWorker *worker, Surfaces *surfaces, Stream *stream);
> > +static void red_stop_stream(Surfaces *surfaces, Stream *stream);
> > static inline void red_stream_maintenance(RedWorker *worker,
> > Surfaces *surfaces, Drawable *candidate, Drawable *sect);
> > static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarshaller *base_marshaller);
> > -static void red_release_pixmap_cache(DisplayChannel *channel);
> > -static void red_release_glz(DisplayChannel *channel);
> > -static void red_freeze_glz(DisplayChannel *channel);
> > -static void display_channel_push_release(DisplayChannel *channel, uint8_t type, uint64_t id,
> > +static void red_release_pixmap_cache(DisplayChannelClient *dcc);
> > +static void red_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);
> > -static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipItem *item);
> > -static int red_display_free_some_independent_glz_drawables(DisplayChannel *channel);
> > -static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawable *drawable);
> > -static void reset_rate(RedWorker *worker, StreamAgent *stream_agent);
> > +static void red_display_release_stream_clip(Surfaces* surfaces, StreamClipItem *item);
> > +static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc);
> > +static void red_display_free_glz_drawable(DisplayChannelClient *dcc,
> > + RedGlzDrawable *drawable);
> > +static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent);
> > static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
> > static inline int _stride_is_extra(SpiceBitmap *bitmap);
> > static void red_disconnect_cursor(RedChannel *channel);
> > -static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item);
> > +static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item);
> >
> > #ifdef DUMP_BITMAP
> > static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
> > @@ -1154,11 +1188,32 @@ static void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb)
> > red_channel_client_pipe_add(rcc, &item->base);
> > }
> >
> > -static inline void red_create_surface_item(RedWorker *worker, int surface_id);
> > +static inline void red_create_surface_item(RedWorker *worker,
> > + DisplayChannelClient *dcc, int surface_id);
> > static void red_add_surface_image(RedWorker *worker, int surface_id);
> > +static void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
> > +{
> > + RedChannelClient *rcc = channel->rcc;
> > +
> > + if (!rcc) {
> > + return;
> > + }
> > + red_pipe_add_verb(rcc, verb);
> > +}
> >
> > -static inline void red_handle_drawable_surfaces_client_synced(RedWorker *worker, Drawable *drawable)
> > +#define DCC_TO_WORKER(dcc) \
> > + (SPICE_CONTAINEROF((dcc)->common.base.channel, CommonChannel, base)->worker)
> > +
> > +#define DCC_TO_DC(dcc) SPICE_CONTAINEROF((dcc)->common.base.channel,\
> > + DisplayChannel, common.base)
> > +
> > +#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
> > +#define RCC_TO_CCC(rcc) SPICE_CONTAINEROF((rcc), CursorChannelClient, common.base)
> > +
> > +static inline void red_handle_drawable_surfaces_client_synced(
> > + DisplayChannelClient *dcc, Drawable *drawable)
> > {
> > + RedWorker *worker = DCC_TO_WORKER(dcc);
> > int x;
> >
> > for (x = 0; x < 3; ++x) {
> > @@ -1166,20 +1221,20 @@ static inline void red_handle_drawable_surfaces_client_synced(RedWorker *worker,
> >
> > surface_id = drawable->surfaces_dest[x];
> > if (surface_id != -1) {
> > - if (worker->display_channel->surface_client_created[surface_id] == TRUE) {
> > + if (dcc->surface_client_created[surface_id] == TRUE) {
> > continue;
> > }
> > - red_create_surface_item(worker, surface_id);
> > + red_create_surface_item(worker, dcc, surface_id);
> > red_current_flush(worker, &worker->surfaces, surface_id);
> > red_add_surface_image(worker, surface_id);
> > }
> > }
> >
> > - if (worker->display_channel->surface_client_created[drawable->surface_id] == TRUE) {
> > + if (dcc->surface_client_created[drawable->surface_id] == TRUE) {
> > return;
> > }
> >
> > - red_create_surface_item(worker, drawable->surface_id);
> > + red_create_surface_item(worker, dcc, drawable->surface_id);
> > red_current_flush(worker, &worker->surfaces, drawable->surface_id);
> > red_add_surface_image(worker, drawable->surface_id);
> > }
> > @@ -1196,16 +1251,16 @@ static int cursor_connected(RedWorker *worker)
> > &worker->cursor_channel->common.base));
> > }
> >
> > -static inline void red_pipe_add_drawable(RedWorker *worker, Drawable *drawable)
> > +static inline void red_pipe_add_drawable(DisplayChannelClient *dcc, Drawable *drawable)
> > {
> > - if (!display_connected(worker)) {
> > + if (!dcc) {
> > return;
> > }
> >
> > - red_handle_drawable_surfaces_client_synced(worker, drawable);
> > + red_handle_drawable_surfaces_client_synced(dcc, drawable);
> >
> > drawable->refs++;
> > - red_channel_client_pipe_add(worker->display_channel->common.base.rcc, &drawable->pipe_item);
> > + red_channel_client_pipe_add(&dcc->common.base, &drawable->pipe_item);
> > }
> >
> > static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *drawable)
> > @@ -1217,19 +1272,19 @@ static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *dr
> > red_channel_client_pipe_add_tail(worker->display_channel->common.base.rcc, &drawable->pipe_item);
> > }
> >
> > -static inline void red_pipe_add_drawable_after(RedWorker *worker, Drawable *drawable,
> > +static inline void red_pipe_add_drawable_after(DisplayChannelClient *dcc, Drawable *drawable,
> > Drawable *pos_after)
> > {
> > - if (!display_connected(worker)) {
> > + if (!dcc) {
> > return;
> > }
> >
> > if (!pos_after || !pipe_item_is_linked(&pos_after->pipe_item)) {
> > - red_pipe_add_drawable(worker, drawable);
> > + red_pipe_add_drawable(dcc, drawable);
> > return;
> > }
> > drawable->refs++;
> > - red_channel_client_pipe_add_after(worker->display_channel->common.base.rcc, &drawable->pipe_item, &pos_after->pipe_item);
> > + red_channel_client_pipe_add_after(&dcc->common.base, &drawable->pipe_item, &pos_after->pipe_item);
> > }
> >
> > static inline PipeItem *red_pipe_get_tail(RedWorker *worker)
> > @@ -1310,14 +1365,14 @@ static void common_release_recv_buf(RedChannelClient *rcc,
> > #include "red_client_cache.h"
> > #undef CLIENT_PALETTE_CACHE
> >
> > -static void red_reset_palette_cache(DisplayChannel *display_channel)
> > +static void red_reset_palette_cache(DisplayChannelClient *dcc)
> > {
> > - red_palette_cache_reset(display_channel, CLIENT_PALETTE_CACHE_SIZE);
> > + red_palette_cache_reset(dcc, CLIENT_PALETTE_CACHE_SIZE);
> > }
> >
> > -static void red_reset_cursor_cache(CursorChannel *channel)
> > +static void red_reset_cursor_cache(RedChannelClient *rcc)
> > {
> > - red_cursor_cache_reset(channel, CLIENT_CURSOR_CACHE_SIZE);
> > + red_cursor_cache_reset(RCC_TO_CCC(rcc), CLIENT_CURSOR_CACHE_SIZE);
> > }
> >
> > static inline Drawable *alloc_drawable(RedWorker *worker)
> > @@ -1366,18 +1421,19 @@ static SurfaceDestroyItem *get_surface_destroy_item(RedChannel *channel,
> > return destroy;
> > }
> >
> > -static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_id)
> > +static inline void red_destroy_surface_item(RedWorker *worker,
> > + DisplayChannelClient *dcc, uint32_t surface_id)
> > {
> > SurfaceDestroyItem *destroy;
> > RedChannel *channel;
> >
> > - if (!display_connected(worker)) {
> > + if (!dcc || !dcc->surface_client_created[surface_id]) {
> > return;
> > }
> > - worker->display_channel->surface_client_created[surface_id] = FALSE;
> > + dcc->surface_client_created[surface_id] = FALSE;
> > channel = &worker->display_channel->common.base;
> > destroy = get_surface_destroy_item(channel, surface_id);
> > - red_channel_client_pipe_add(channel->rcc, &destroy->pipe_item);
> > + red_channel_client_pipe_add(&dcc->common.base, &destroy->pipe_item);
> > }
> >
> > static inline void red_destroy_surface(RedWorker *worker, Surfaces *surfaces,
> > @@ -1402,7 +1458,7 @@ static inline void red_destroy_surface(RedWorker *worker, Surfaces *surfaces,
> >
> > region_destroy(&surface->draw_dirty_region);
> > surface->context.canvas = NULL;
> > - red_destroy_surface_item(worker, surface_id);
> > + red_destroy_surface_item(worker, surfaces->dcc, surface_id);
> >
> > PANIC_ON(!ring_is_empty(&surface->depend_on_me));
> > }
> > @@ -1684,20 +1740,22 @@ static void red_current_clear(RedWorker *worker, Surfaces *surfaces, int surface
> > }
> > }
> >
> > -static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface_id, int force)
> > +static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id, int force)
> > {
> > Ring *ring;
> > PipeItem *item;
> > int x;
> > + RedChannelClient *rcc;
> >
> > - if (!display_connected(worker)) {
> > + if (!dcc) {
> > return;
> > }
> >
> > /* removing the newest drawables that their destination is surface_id and
> > no other drawable depends on them */
> >
> > - ring = &worker->display_channel->common.base.rcc->pipe;
> > + rcc = &dcc->common.base;
> > + ring = &dcc->common.base.pipe;
> > item = (PipeItem *) ring;
> > while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) {
> > Drawable *drawable;
> > @@ -1713,11 +1771,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
> > if (drawable->surface_id == surface_id) {
> > PipeItem *tmp_item = item;
> > item = (PipeItem *)ring_prev(ring, (RingItem *)item);
> > - ring_remove(&tmp_item->link);
> > - worker->display_channel->common.base.release_item(
> > - worker->display_channel->common.base.rcc, tmp_item, FALSE);
> > - worker->display_channel->common.base.rcc->pipe_size--;
> > -
> > + red_channel_client_pipe_remove_and_release(rcc, tmp_item);
> > if (!item) {
> > item = (PipeItem *)ring;
> > }
> > @@ -1741,7 +1795,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
> > }
> >
> > if (item) {
> > - red_wait_pipe_item_sent(&worker->display_channel->common.base, item);
> > + red_wait_pipe_item_sent(&dcc->common.base, item);
> > }
> > }
> >
> > @@ -2145,10 +2199,10 @@ static inline void red_detach_stream(Surfaces *surfaces, Stream *stream)
> > stream->current = NULL;
> > }
> >
> > -static StreamClipItem *__new_stream_clip(DisplayChannel* channel, StreamAgent *agent)
> > +static StreamClipItem *__new_stream_clip(DisplayChannelClient* dcc, StreamAgent *agent)
> > {
> > StreamClipItem *item = spice_new(StreamClipItem, 1);
> > - red_channel_pipe_item_init(&channel->common.base,
> > + red_channel_pipe_item_init(dcc->common.base.channel,
> > (PipeItem *)item, PIPE_ITEM_TYPE_STREAM_CLIP);
> >
> > item->stream_agent = agent;
> > @@ -2157,10 +2211,10 @@ static StreamClipItem *__new_stream_clip(DisplayChannel* channel, StreamAgent *a
> > return item;
> > }
> >
> > -static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *agent,
> > +static void push_stream_clip_by_drawable(DisplayChannelClient* dcc, StreamAgent *agent,
> > Drawable *drawable)
> > {
> > - StreamClipItem *item = __new_stream_clip(channel, agent);
> > + StreamClipItem *item = __new_stream_clip(dcc, agent);
> > int n_rects;
> >
> > if (!item) {
> > @@ -2179,12 +2233,12 @@ static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *a
> > item->rects->num_rects = n_rects;
> > region_ret_rects(&drawable->tree_item.base.rgn, item->rects->rects, n_rects);
> > }
> > - red_channel_client_pipe_add(channel->common.base.rcc, (PipeItem *)item);
> > + red_channel_client_pipe_add(&dcc->common.base, (PipeItem *)item);
> > }
> >
> > -static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
> > +static void push_stream_clip(DisplayChannelClient* dcc, StreamAgent *agent)
> > {
> > - StreamClipItem *item = __new_stream_clip(channel, agent);
> > + StreamClipItem *item = __new_stream_clip(dcc, agent);
> > int n_rects;
> >
> > if (!item) {
> > @@ -2197,13 +2251,13 @@ static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
> > item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
> > item->rects->num_rects = n_rects;
> > region_ret_rects(&agent->vis_region, item->rects->rects, n_rects);
> > - red_channel_client_pipe_add(channel->common.base.rcc, (PipeItem *)item);
> > + red_channel_client_pipe_add(&dcc->common.base, (PipeItem *)item);
> > }
> >
> > -static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipItem *item)
> > +static void red_display_release_stream_clip(Surfaces* surfaces, StreamClipItem *item)
> > {
> > if (!--item->refs) {
> > - red_display_release_stream(channel, item->stream_agent);
> > + red_display_release_stream(surfaces, item->stream_agent);
> > if (item->rects) {
> > free(item->rects);
> > }
> > @@ -2211,55 +2265,61 @@ static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipI
> > }
> > }
> >
> > -static void red_attach_stream(RedWorker *worker, Surfaces *surfaces, Drawable *drawable, Stream *stream)
> > +static void red_attach_stream(Surfaces *surfaces, Drawable *drawable, Stream *stream)
> > {
> > - DisplayChannel *channel;
> > + DisplayChannelClient *dcc;
> > + StreamAgent *agent;
> > +
> > ASSERT(!drawable->stream && !stream->current);
> > ASSERT(drawable && stream);
> > stream->current = drawable;
> > drawable->stream = stream;
> > stream->last_time = drawable->creation_time;
> >
> > - if ((channel = worker->display_channel)) {
> > - StreamAgent *agent = &channel->stream_agents[stream - surfaces->streams_buf];
> > + if (surfaces->dcc) {
> > + dcc = surfaces->dcc;
> > + agent = &dcc->stream_agents[stream - surfaces->streams_buf];
> > if (!region_is_equal(&agent->vis_region, &drawable->tree_item.base.rgn)) {
> > region_destroy(&agent->vis_region);
> > region_clone(&agent->vis_region, &drawable->tree_item.base.rgn);
> > - push_stream_clip_by_drawable(channel, agent, drawable);
> > + push_stream_clip_by_drawable(dcc, agent, drawable);
> > }
> > }
> > }
> >
> > -static void red_stop_stream(RedWorker *worker, Surfaces *surfaces, Stream *stream)
> > +static void red_stop_stream(Surfaces *surfaces, Stream *stream)
> > {
> > - DisplayChannel *channel;
> > + DisplayChannelClient *dcc = surfaces->dcc;
> > ASSERT(ring_item_is_linked(&stream->link));
> > ASSERT(!stream->current);
> >
> > - if ((channel = worker->display_channel)) {
> > + if (surfaces->dcc) {
> > StreamAgent *stream_agent;
> > - stream_agent = &channel->stream_agents[stream - surfaces->streams_buf];
> > + stream_agent = &dcc->stream_agents[stream - surfaces->streams_buf];
> > region_clear(&stream_agent->vis_region);
> > ASSERT(!pipe_item_is_linked(&stream_agent->destroy_item));
> > stream->refs++;
> > - red_channel_client_pipe_add(channel->common.base.rcc, &stream_agent->destroy_item);
> > + red_channel_client_pipe_add(&dcc->common.base, &stream_agent->destroy_item);
> > }
> > ring_remove(&stream->link);
> > red_release_stream(surfaces, stream);
> > }
> >
> > -static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *stream)
> > +static inline void red_detach_stream_gracefully(Surfaces *surfaces, Stream *stream)
> > {
> > - DisplayChannel *channel;
> > - ASSERT(stream->current);
> > + RedChannel *channel;
> > + RedChannelClient *rcc;
> >
> > - if ((channel = worker->display_channel) && !pipe_item_is_linked(&stream->current->pipe_item)) {
> > + ASSERT(stream->current);
> > + if (surfaces->dcc && !pipe_item_is_linked(&stream->current->pipe_item)) {
> > UpgradeItem *upgrade_item;
> > int n_rects;
> > + rcc = &surfaces->dcc->common.base;
> > + channel = rcc->channel;
> >
> > upgrade_item = spice_new(UpgradeItem, 1);
> > upgrade_item->refs = 1;
> > - red_channel_pipe_item_init(&channel->common.base,
> > + red_channel_pipe_item_init(channel,
> > &upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
> > upgrade_item->drawable = stream->current;
> > upgrade_item->drawable->refs++;
> > @@ -2267,30 +2327,29 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
> > upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
> > upgrade_item->rects->num_rects = n_rects;
> > region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn, upgrade_item->rects->rects, n_rects);
> > - red_channel_client_pipe_add(channel->common.base.rcc, &upgrade_item->base);
> > + red_channel_client_pipe_add(rcc, &upgrade_item->base);
> > }
> > - red_detach_stream(&worker->surfaces, stream);
> > + red_detach_stream(surfaces, stream);
> > }
> >
> > // region should be a primary surface region
> > -static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
> > +static void red_detach_streams_behind(Surfaces *surfaces, QRegion *region)
> > {
> > - Surfaces *surfaces = &worker->surfaces;
> > Ring *ring = &surfaces->streams;
> > RingItem *item = ring_get_head(ring);
> > - DisplayChannel *channel = worker->display_channel;
> > + DisplayChannelClient *dcc = surfaces->dcc;
> >
> > while (item) {
> > Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> > item = ring_next(ring, item);
> >
> > - if (channel) {
> > - StreamAgent *agent = &channel->stream_agents[stream - surfaces->streams_buf];
> > + if (dcc) {
> > + StreamAgent *agent = &dcc->stream_agents[stream - surfaces->streams_buf];
> > if (region_intersects(&agent->vis_region, region)) {
> > region_clear(&agent->vis_region);
> > - push_stream_clip(channel, agent);
> > + push_stream_clip(dcc, agent);
> > if (stream->current) {
> > - red_detach_stream_gracefully(worker, stream);
> > + red_detach_stream_gracefully(surfaces, stream);
> > }
> > }
> > } else if (stream->current && region_intersects(&stream->current->tree_item.base.rgn,
> > @@ -2300,14 +2359,13 @@ static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
> > }
> > }
> >
> > -static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
> > +static void red_streams_update_clip(RedWorker *worker, Surfaces *surfaces, Drawable *drawable)
> > {
> > - DisplayChannel *channel = worker->display_channel;
> > - Surfaces *surfaces = &worker->surfaces;
> > Ring *ring;
> > RingItem *item;
> > + DisplayChannelClient *dcc = surfaces->dcc;
> >
> > - if (!display_connected(worker)) {
> > + if (!surfaces->dcc) {
> > return;
> > }
> >
> > @@ -2325,7 +2383,7 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
> >
> > item = ring_next(ring, item);
> >
> > - agent = &channel->stream_agents[stream - surfaces->streams_buf];
> > + agent = &dcc->stream_agents[stream - surfaces->streams_buf];
> >
> > if (stream->current == drawable) {
> > continue;
> > @@ -2333,7 +2391,7 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
> >
> > if (region_intersects(&agent->vis_region, &drawable->tree_item.base.rgn)) {
> > region_exclude(&agent->vis_region, &drawable->tree_item.base.rgn);
> > - push_stream_clip(channel, agent);
> > + push_stream_clip(dcc, agent);
> > }
> > }
> > }
> > @@ -2375,17 +2433,17 @@ static inline void red_handle_streams_timout(RedWorker *worker, Surfaces *surfac
> > item = ring_next(ring, item);
> > if (now >= (stream->last_time + RED_STREAM_TIMOUT)) {
> > if (stream->current) {
> > - red_detach_stream_gracefully(worker, stream);
> > + red_detach_stream_gracefully(surfaces, stream);
> > }
> > - red_stop_stream(worker, &worker->surfaces, stream);
> > + red_stop_stream(surfaces, stream);
> > }
> > }
> > }
> >
> > -static void red_display_release_stream(DisplayChannel *display, StreamAgent *agent)
> > +static void red_display_release_stream(Surfaces *surfaces, StreamAgent *agent)
> > {
> > ASSERT(agent->stream);
> > - red_release_stream(&display->common.worker->surfaces, agent->stream);
> > + red_release_stream(surfaces, agent->stream);
> > }
> >
> > static inline Stream *red_alloc_stream(Surfaces *surfaces)
> > @@ -2399,15 +2457,15 @@ static inline Stream *red_alloc_stream(Surfaces *surfaces)
> > return stream;
> > }
> >
> > -static int get_bit_rate(RedWorker *worker,
> > +static int get_bit_rate(DisplayChannelClient *dcc,
> > int width, int height)
> > {
> > uint64_t bit_rate = width * height * BEST_BIT_RATE_PER_PIXEL;
> > MainChannelClient *mcc;
> > int is_low_bandwidth = 0;
> >
> > - if (display_connected(worker)) {
> > - mcc = red_client_get_main(worker->display_channel->common.base.rcc->client);
> > + if (dcc) {
> > + mcc = red_client_get_main(dcc->common.base.client);
> > is_low_bandwidth = main_channel_client_is_low_bandwidth(mcc);
> > }
> >
> > @@ -2418,9 +2476,9 @@ static int get_bit_rate(RedWorker *worker,
> > return bit_rate;
> > }
> >
> > -static void red_display_create_stream(DisplayChannel *display, Stream *stream)
> > +static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
> > {
> > - StreamAgent *agent = &display->stream_agents[stream - display->common.worker->surfaces.streams_buf];
> > + StreamAgent *agent = &dcc->stream_agents[stream - dcc->common.surfaces->streams_buf];
> > stream->refs++;
> > ASSERT(region_is_empty(&agent->vis_region));
> > if (stream->current) {
> > @@ -2431,13 +2489,15 @@ static void red_display_create_stream(DisplayChannel *display, Stream *stream)
> > }
> > agent->drops = 0;
> > agent->fps = MAX_FPS;
> > - reset_rate(display->common.worker, agent);
> > - red_channel_client_pipe_add(display->common.base.rcc, &agent->create_item);
> > + reset_rate(dcc, agent);
> > + red_channel_client_pipe_add(&dcc->common.base, &agent->create_item);
> > }
> >
> > -static void red_create_stream(RedWorker *worker, Drawable *drawable)
> > +/* TODO: we create the stream even if dcc is NULL, i.e. no client - or
> > + * maybe we can't reach this function in that case? question: do we want to? */
> > +static void red_create_stream(Surfaces *surfaces, Drawable *drawable)
> > {
> > - Surfaces *surfaces = &worker->surfaces;
> > + DisplayChannelClient *dcc = surfaces->dcc;
> > Stream *stream;
> > SpiceRect* src_rect;
> > int stream_width;
> > @@ -2463,48 +2523,49 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
> > stream->height = src_rect->bottom - src_rect->top;
> > stream->dest_area = drawable->red_drawable->bbox;
> > stream->refs = 1;
> > - stream->bit_rate = get_bit_rate(worker, stream_width, stream_height);
> > + stream->bit_rate = get_bit_rate(dcc, stream_width, stream_height);
> > SpiceBitmap *bitmap = &drawable->red_drawable->u.copy.src_bitmap->u.bitmap;
> > stream->top_down = !!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN);
> > drawable->stream = stream;
> >
> > - if (worker->display_channel) {
> > - red_display_create_stream(worker->display_channel, stream);
> > + if (dcc) {
> > + red_display_create_stream(dcc, stream);
> > }
> >
> > return;
> > }
> >
> > -static void red_disply_start_streams(DisplayChannel *display_channel)
> > +static void red_disply_start_streams(DisplayChannelClient *dcc)
> > {
> > - Ring *ring = &display_channel->common.worker->surfaces.streams;
> > + Ring *ring = &dcc->common.surfaces->streams;
> > RingItem *item = ring;
> >
> > while ((item = ring_next(ring, item))) {
> > Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> > - red_display_create_stream(display_channel, stream);
> > + red_display_create_stream(dcc, stream);
> > }
> > }
> >
> > -static void red_display_init_streams(DisplayChannel *display)
> > +static void red_display_client_init_streams(DisplayChannelClient *dcc)
> > {
> > int i;
> > + Surfaces *surfaces = dcc->common.surfaces;
> > + RedChannel *channel = dcc->common.base.channel;
> > +
> > for (i = 0; i < NUM_STREAMS; i++) {
> > - StreamAgent *agent = &display->stream_agents[i];
> > - agent->stream = &display->common.worker->surfaces.streams_buf[i];
> > + StreamAgent *agent = &dcc->stream_agents[i];
> > + agent->stream = &surfaces->streams_buf[i];
> > region_init(&agent->vis_region);
> > - red_channel_pipe_item_init(&display->common.base,
> > - &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
> > - red_channel_pipe_item_init(&display->common.base,
> > - &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
> > + red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
> > + red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
> > }
> > }
> >
> > -static void red_display_destroy_streams(DisplayChannel *display)
> > +static void red_display_destroy_streams(DisplayChannelClient *dcc)
> > {
> > int i;
> > for (i = 0; i < NUM_STREAMS; i++) {
> > - StreamAgent *agent = &display->stream_agents[i];
> > + StreamAgent *agent = &dcc->stream_agents[i];
> > region_destroy(&agent->vis_region);
> > }
> > }
> > @@ -2572,12 +2633,12 @@ static inline int red_is_next_stream_frame(RedWorker *worker, const Drawable *ca
> > prev->stream);
> > }
> >
> > -static void reset_rate(RedWorker *worker, StreamAgent *stream_agent)
> > +static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent)
> > {
> > Stream *stream = stream_agent->stream;
> > int rate;
> >
> > - rate = get_bit_rate(worker, stream->width, stream->height);
> > + rate = get_bit_rate(dcc, stream->width, stream->height);
> > if (rate == stream->bit_rate) {
> > return;
> > }
> > @@ -2598,14 +2659,16 @@ static int display_channel_is_low_bandwidth(DisplayChannel *display_channel)
> >
> > static inline void pre_stream_item_swap(RedWorker *worker, Surfaces *surfaces, Stream *stream)
> > {
> > + DisplayChannelClient *dcc = surfaces->dcc;
> > +
> > ASSERT(stream->current);
> >
> > - if (!display_connected(worker) || !display_channel_is_low_bandwidth(worker->display_channel)) {
> > + if (!dcc || !display_channel_is_low_bandwidth(worker->display_channel)) {
> > return;
> > }
> >
> > int index = stream - surfaces->streams_buf;
> > - StreamAgent *agent = &worker->display_channel->stream_agents[index];
> > + StreamAgent *agent = &dcc->stream_agents[index];
> >
> > if (pipe_item_is_linked(&stream->current->pipe_item)) {
> > ++agent->drops;
> > @@ -2663,10 +2726,11 @@ static inline int red_is_stream_start(Drawable *drawable)
> > }
> >
> > // returns whether a stream was created
> > -static int red_stream_add_frame(RedWorker* worker, Drawable *frame_drawable,
> > - int frames_count,
> > - int gradual_frames_count,
> > - int last_gradual_frame)
> > +static int red_stream_add_frame(RedWorker* worker, Surfaces *surfaces,
> > + Drawable *frame_drawable,
> > + int frames_count,
> > + int gradual_frames_count,
> > + int last_gradual_frame)
> > {
> > red_update_copy_graduality(worker, frame_drawable);
> > frame_drawable->frames_count = frames_count + 1;
> > @@ -2687,7 +2751,7 @@ static int red_stream_add_frame(RedWorker* worker, Drawable *frame_drawable,
> > }
> >
> > if (red_is_stream_start(frame_drawable)) {
> > - red_create_stream(worker, frame_drawable);
> > + red_create_stream(surfaces, frame_drawable);
> > return TRUE;
> > }
> > return FALSE;
> > @@ -2710,9 +2774,9 @@ static inline void red_stream_maintenance(RedWorker *worker,
> > pre_stream_item_swap(worker, surfaces, stream);
> > red_detach_stream(surfaces, stream);
> > prev->streamable = FALSE; //prevent item trace
> > - red_attach_stream(worker, surfaces, candidate, stream);
> > + red_attach_stream(surfaces, candidate, stream);
> > } else {
> > - red_stream_add_frame(worker, candidate,
> > + red_stream_add_frame(worker, surfaces, candidate,
> > prev->frames_count,
> > prev->gradual_frames_count,
> > prev->last_gradual_frame);
> > @@ -2737,6 +2801,7 @@ static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
> > DrawItem *other_draw_item;
> > Drawable *drawable;
> > Drawable *other_drawable;
> > + DisplayChannelClient *dcc = surfaces->dcc;
> >
> > if (other->type != TREE_ITEM_TYPE_DRAWABLE) {
> > return FALSE;
> > @@ -2755,9 +2820,9 @@ static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
> > red_stream_maintenance(worker, surfaces, drawable, other_drawable);
> > __current_add_drawable(worker, surfaces, drawable, &other->siblings_link);
> > if (add_after) {
> > - red_pipe_add_drawable_after(worker, drawable, other_drawable);
> > + red_pipe_add_drawable_after(dcc, drawable, other_drawable);
> > } else {
> > - red_pipe_add_drawable(worker, drawable);
> > + red_pipe_add_drawable(dcc, drawable);
> > }
> > remove_drawable(worker, surfaces, other_drawable);
> > return TRUE;
> > @@ -2767,7 +2832,7 @@ static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
> > case QXL_EFFECT_REVERT_ON_DUP:
> > if (is_same_drawable(worker, drawable, other_drawable)) {
> > if (!ring_item_is_linked(&other_drawable->pipe_item.link)) {
> > - red_pipe_add_drawable(worker, drawable);
> > + red_pipe_add_drawable(dcc, drawable);
> > }
> > remove_drawable(worker, surfaces, other_drawable);
> > return TRUE;
> > @@ -2777,7 +2842,7 @@ static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
> > if (is_same_geometry(worker, drawable, other_drawable)) {
> > __current_add_drawable(worker, surfaces, drawable, &other->siblings_link);
> > remove_drawable(worker, surfaces, other_drawable);
> > - red_pipe_add_drawable(worker, drawable);
> > + red_pipe_add_drawable(dcc, drawable);
> > return TRUE;
> > }
> > break;
> > @@ -2813,7 +2878,7 @@ static inline void red_use_stream_trace(RedWorker *worker, Surfaces *surfaces, D
> > &stream->dest_area,
> > stream->last_time,
> > stream)) {
> > - red_attach_stream(worker, surfaces, drawable, stream);
> > + red_attach_stream(surfaces, drawable, stream);
> > return;
> > }
> > item = ring_next(ring, item);
> > @@ -2824,7 +2889,7 @@ static inline void red_use_stream_trace(RedWorker *worker, Surfaces *surfaces, D
> > for (; trace < trace_end; trace++) {
> > if (__red_is_next_stream_frame(worker, drawable, trace->width, trace->height,
> > &trace->dest_area, trace->time, NULL)) {
> > - if (red_stream_add_frame(worker, drawable,
> > + if (red_stream_add_frame(worker, surfaces, drawable,
> > trace->frames_count,
> > trace->gradual_frames_count,
> > trace->last_gradual_frame)) {
> > @@ -2843,7 +2908,7 @@ static void red_reset_stream_trace(RedWorker *worker, Surfaces *surfaces)
> > Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> > item = ring_next(ring, item);
> > if (!stream->current) {
> > - red_stop_stream(worker, surfaces, stream);
> > + red_stop_stream(surfaces, stream);
> > } else {
> > red_printf("attached stream");
> > }
> > @@ -2957,10 +3022,10 @@ static inline int red_current_add(RedWorker *worker, Surfaces *surfaces,
> > region_or(&exclude_rgn, &item->base.rgn);
> > exclude_region(worker, surfaces, ring, exclude_base, &exclude_rgn, NULL, drawable);
> > red_use_stream_trace(worker, surfaces, drawable);
> > - red_streams_update_clip(worker, drawable);
> > + red_streams_update_clip(worker, surfaces, drawable);
> > } else {
> > if (drawable->surface_id == 0) {
> > - red_detach_streams_behind(worker, &drawable->tree_item.base.rgn);
> > + red_detach_streams_behind(surfaces, &drawable->tree_item.base.rgn);
> > }
> > }
> > region_destroy(&exclude_rgn);
> > @@ -3019,7 +3084,7 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Surfaces *surfa
> >
> > // only primary surface streams are supported
> > if (item->surface_id == 0) {
> > - red_detach_streams_behind(worker, &shadow->base.rgn);
> > + red_detach_streams_behind(surfaces, &shadow->base.rgn);
> > }
> > ring_add(ring, &shadow->base.siblings_link);
> > __current_add_drawable(worker, surfaces, item, ring);
> > @@ -3028,10 +3093,10 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Surfaces *surfa
> > region_clone(&exclude_rgn, &item->tree_item.base.rgn);
> > exclude_region(worker, surfaces, ring, &shadow->base.siblings_link, &exclude_rgn, NULL, NULL);
> > region_destroy(&exclude_rgn);
> > - red_streams_update_clip(worker, item);
> > + red_streams_update_clip(worker, surfaces, item);
> > } else {
> > if (item->surface_id == 0) {
> > - red_detach_streams_behind(worker, &item->tree_item.base.rgn);
> > + red_detach_streams_behind(surfaces, &item->tree_item.base.rgn);
> > }
> > }
> > stat_add(&worker->add_stat, start_time);
> > @@ -3252,12 +3317,13 @@ static void free_one_drawable(RedWorker *worker, Surfaces *surfaces, int force_g
> > RingItem *ring_item = ring_get_tail(&surfaces->current_list);
> > Drawable *drawable;
> > Container *container;
> > + DisplayChannelClient *dcc = surfaces->dcc;
> >
> > ASSERT(ring_item);
> > drawable = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
> > if (drawable->red_glz_drawable && force_glz_free) {
> > ASSERT(worker->display_channel);
> > - red_display_free_glz_drawable(worker->display_channel, drawable->red_glz_drawable);
> > + red_display_free_glz_drawable(dcc, drawable->red_glz_drawable);
> > }
> > red_draw_drawable(worker, surfaces, drawable);
> > container = drawable->tree_item.base.container;
> > @@ -3358,7 +3424,7 @@ static inline int red_handle_surfaces_dependencies(RedWorker *worker,
> > QRegion depend_region;
> > region_init(&depend_region);
> > region_add(&depend_region, &drawable->red_drawable->surfaces_rects[x]);
> > - red_detach_streams_behind(worker, &depend_region);
> > + red_detach_streams_behind(surfaces, &depend_region);
> > }
> > }
> > }
> > @@ -3387,6 +3453,7 @@ static inline void red_process_drawable_surfaces(RedWorker *worker,
> > {
> > int surface_id;
> > Drawable *item = get_drawable(worker, surfaces, drawable->effect, drawable, group_id);
> > + DisplayChannelClient *dcc = surfaces->dcc;
> >
> > ASSERT(item);
> >
> > @@ -3445,7 +3512,7 @@ static inline void red_process_drawable_surfaces(RedWorker *worker,
> > if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
> > surfaces->transparent_count++;
> > }
> > - red_pipe_add_drawable(worker, item);
> > + red_pipe_add_drawable(dcc, item);
> > #ifdef DRAW_ALL
> > red_draw_qxl_drawable(worker, surfaces, item);
> > #endif
> > @@ -3498,7 +3565,7 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
> > otherwise "current" will hold items that other drawables may depend on, and then
> > red_current_clear will remove them from the pipe. */
> > red_current_clear(worker, surfaces, surface_id);
> > - red_clear_surface_drawables_from_pipe(worker, surface_id, FALSE);
> > + red_clear_surface_drawables_from_pipe(surfaces->dcc, surface_id, FALSE);
> > red_destroy_surface(worker, surfaces, surface_id);
> > break;
> > default:
> > @@ -4386,20 +4453,22 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
> > static void red_free_some(RedWorker *worker)
> > {
> > int n = 0;
> > + DisplayChannelClient *dcc = worker->surfaces.dcc;
> > + GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
> >
> > - if (worker->display_channel && worker->display_channel->glz_dict) {
> > + if (glz_dict) {
> > // encoding using the dictionary is prevented since the following operations might
> > // change the dictionary
> > - pthread_rwlock_wrlock(&worker->display_channel->glz_dict->encode_lock);
> > - n = red_display_free_some_independent_glz_drawables(worker->display_channel);
> > + pthread_rwlock_wrlock(&glz_dict->encode_lock);
> > + n = red_display_free_some_independent_glz_drawables(dcc);
> > }
> >
> > while (!ring_is_empty(&worker->surfaces.current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
> > free_one_drawable(worker, &worker->surfaces, TRUE);
> > }
> >
> > - if (worker->display_channel && worker->display_channel->glz_dict) {
> > - pthread_rwlock_unlock(&worker->display_channel->glz_dict->encode_lock);
> > + if (glz_dict) {
> > + pthread_rwlock_unlock(&glz_dict->encode_lock);
> > }
> > }
> >
> > @@ -4501,7 +4570,7 @@ typedef struct {
> > uint32_t size;
> > } AddBufInfo;
> >
> > -static void marshaller_add_compressed(RedWorker *worker, SpiceMarshaller *m,
> > +static void marshaller_add_compressed(SpiceMarshaller *m,
> > RedCompressBuf *comp_buf, size_t size)
> > {
> > size_t max = size;
> > @@ -4549,7 +4618,7 @@ static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
> > spice_marshall_DisplayBase(base_marshaller, &base);
> > }
> >
> > -static inline void fill_palette(DisplayChannel *display_channel,
> > +static inline void fill_palette(DisplayChannelClient *dcc,
> > SpicePalette *palette,
> > uint8_t *flags)
> > {
> > @@ -4557,43 +4626,43 @@ static inline void fill_palette(DisplayChannel *display_channel,
> > return;
> > }
> > if (palette->unique) {
> > - if (red_palette_cache_find(display_channel, palette->unique)) {
> > + if (red_palette_cache_find(dcc, palette->unique)) {
> > *flags |= SPICE_BITMAP_FLAGS_PAL_FROM_CACHE;
> > return;
> > }
> > - if (red_palette_cache_add(display_channel->common.base.rcc, palette->unique, 1)) {
> > + if (red_palette_cache_add(dcc, palette->unique, 1)) {
> > *flags |= SPICE_BITMAP_FLAGS_PAL_CACHE_ME;
> > }
> > }
> > }
> >
> > -static inline RedCompressBuf *red_display_alloc_compress_buf(DisplayChannel *display_channel)
> > +static inline RedCompressBuf *red_display_alloc_compress_buf(DisplayChannelClient *dcc)
> > {
> > RedCompressBuf *ret;
> >
> > - if (display_channel->send_data.free_compress_bufs) {
> > - ret = display_channel->send_data.free_compress_bufs;
> > - display_channel->send_data.free_compress_bufs = ret->next;
> > + if (dcc->send_data.free_compress_bufs) {
> > + ret = dcc->send_data.free_compress_bufs;
> > + dcc->send_data.free_compress_bufs = ret->next;
> > } else {
> > ret = spice_new(RedCompressBuf, 1);
> > }
> >
> > - ret->next = display_channel->send_data.used_compress_bufs;
> > - display_channel->send_data.used_compress_bufs = ret;
> > + ret->next = dcc->send_data.used_compress_bufs;
> > + dcc->send_data.used_compress_bufs = ret;
> > return ret;
> > }
> >
> > -static inline void __red_display_free_compress_buf(DisplayChannel *display_channel,
> > +static inline void __red_display_free_compress_buf(DisplayChannelClient *dcc,
> > RedCompressBuf *buf)
> > {
> > - buf->next = display_channel->send_data.free_compress_bufs;
> > - display_channel->send_data.free_compress_bufs = buf;
> > + buf->next = dcc->send_data.free_compress_bufs;
> > + dcc->send_data.free_compress_bufs = buf;
> > }
> >
> > -static void red_display_free_compress_buf(DisplayChannel *display_channel,
> > +static void red_display_free_compress_buf(DisplayChannelClient *dcc,
> > RedCompressBuf *buf)
> > {
> > - RedCompressBuf **curr_used = &display_channel->send_data.used_compress_bufs;
> > + RedCompressBuf **curr_used = &dcc->send_data.used_compress_bufs;
> >
> > for (;;) {
> > ASSERT(*curr_used);
> > @@ -4603,15 +4672,15 @@ static void red_display_free_compress_buf(DisplayChannel *display_channel,
> > }
> > curr_used = &(*curr_used)->next;
> > }
> > - __red_display_free_compress_buf(display_channel, buf);
> > + __red_display_free_compress_buf(dcc, buf);
> > }
> >
> > -static void red_display_reset_compress_buf(DisplayChannel *display_channel)
> > +static void red_display_reset_compress_buf(DisplayChannelClient *dcc)
> > {
> > - while (display_channel->send_data.used_compress_bufs) {
> > - RedCompressBuf *buf = display_channel->send_data.used_compress_bufs;
> > - display_channel->send_data.used_compress_bufs = buf->next;
> > - __red_display_free_compress_buf(display_channel, buf);
> > + while (dcc->send_data.used_compress_bufs) {
> > + RedCompressBuf *buf = dcc->send_data.used_compress_bufs;
> > + dcc->send_data.used_compress_bufs = buf->next;
> > + __red_display_free_compress_buf(dcc, buf);
> > }
> > }
> >
> > @@ -4621,7 +4690,7 @@ static void red_display_reset_compress_buf(DisplayChannel *display_channel)
> >
> > /* 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(DisplayChannel *channel, Drawable *drawable)
> > +static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannelClient *dcc, Drawable *drawable)
> > {
> > RedGlzDrawable *ret;
> >
> > @@ -4631,7 +4700,7 @@ static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannel *channel, Dra
> >
> > ret = spice_new(RedGlzDrawable, 1);
> >
> > - ret->display_channel = channel;
> > + ret->dcc = dcc;
> > ret->red_drawable = drawable->red_drawable;
> > ret->drawable = drawable;
> > ret->group_id = drawable->group_id;
> > @@ -4640,7 +4709,7 @@ static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannel *channel, Dra
> > ring_init(&ret->instances);
> >
> > ring_item_init(&ret->link);
> > - ring_add_before(&ret->link, &channel->glz_drawables);
> > + ring_add_before(&ret->link, &dcc->glz_drawables);
> > drawable->red_glz_drawable = ret;
> >
> > return ret;
> > @@ -4669,9 +4738,11 @@ 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(DisplayChannel *channel,
> > +static void red_display_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;
> >
> > ASSERT(glz_drawable_instance);
> > @@ -4679,7 +4750,7 @@ static void red_display_free_glz_drawable_instance(DisplayChannel *channel,
> >
> > glz_drawable = glz_drawable_instance->red_glz_drawable;
> >
> > - ASSERT(glz_drawable->display_channel == channel);
> > + ASSERT(glz_drawable->dcc == dcc);
> > ASSERT(glz_drawable->instances_count);
> >
> > ring_remove(&glz_drawable_instance->glz_link);
> > @@ -4698,7 +4769,7 @@ static void red_display_free_glz_drawable_instance(DisplayChannel *channel,
> > if (drawable) {
> > drawable->red_glz_drawable = NULL;
> > } else { // no reference to the qxl drawable left
> > - free_red_drawable(channel->common.worker, glz_drawable->red_drawable,
> > + free_red_drawable(worker, glz_drawable->red_drawable,
> > glz_drawable->group_id, glz_drawable->self_bitmap);
> > }
> >
> > @@ -4709,26 +4780,30 @@ static void red_display_free_glz_drawable_instance(DisplayChannel *channel,
> > }
> > }
> >
> > -static void red_display_handle_glz_drawables_to_free(DisplayChannel* channel)
> > +static void red_display_handle_glz_drawables_to_free(DisplayChannelClient* dcc)
> > {
> > RingItem *ring_link;
> > - pthread_mutex_lock(&channel->glz_drawables_inst_to_free_lock);
> >
> > - while ((ring_link = ring_get_head(&channel->glz_drawables_inst_to_free))) {
> > + 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);
> > - red_display_free_glz_drawable_instance(channel, drawable_instance);
> > + red_display_free_glz_drawable_instance(dcc, drawable_instance);
> > }
> > -
> > - pthread_mutex_unlock(&channel->glz_drawables_inst_to_free_lock);
> > + pthread_mutex_unlock(&dcc->glz_drawables_inst_to_free_lock);
> > }
> >
> > -/* releases all the instances of the drawable from the dictionary and the display channel.
> > - The release of the last instance will also release the drawable itself and the qxl drawable
> > - if possible.
> > - NOTE - the caller should prevent encoding using the dictionary during this operation*/
> > -static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawable *drawable)
> > +/*
> > + * 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
> > + * 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)
> > {
> > RingItem *head_instance = ring_get_head(&drawable->instances);
> > int cont = (head_instance != NULL);
> > @@ -4743,11 +4818,11 @@ static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawabl
> > glz_link);
> > if (!ring_item_is_linked(&instance->free_link)) {
> > // the instance didn't get out from window yet
> > - glz_enc_dictionary_remove_image(channel->glz_dict->dict,
> > + glz_enc_dictionary_remove_image(dcc->glz_dict->dict,
> > instance->glz_instance,
> > - &channel->glz_data.usr);
> > + &dcc->glz_data.usr);
> > }
> > - red_display_free_glz_drawable_instance(channel, instance);
> > + red_display_free_glz_drawable_instance(dcc, instance);
> >
> > if (cont) {
> > head_instance = ring_get_head(&drawable->instances);
> > @@ -4757,45 +4832,56 @@ static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawabl
> >
> > /* Clear all lz drawables - enforce their removal from the global dictionary.
> > NOTE - prevents encoding using the dictionary during the operation*/
> > -static void red_display_clear_glz_drawables(DisplayChannel *channel)
> > +static void red_display_client_clear_glz_drawables(DisplayChannelClient *dcc)
> > {
> > RingItem *ring_link;
> > + GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
> >
> > - if (!channel || !channel->glz_dict) {
> > + if (!glz_dict) {
> > return;
> > }
> >
> > // assure no display channel is during global lz encoding
> > - pthread_rwlock_wrlock(&channel->glz_dict->encode_lock);
> > -
> > - while ((ring_link = ring_get_head(&channel->glz_drawables))) {
> > + pthread_rwlock_wrlock(&glz_dict->encode_lock);
> > + while ((ring_link = ring_get_head(&dcc->glz_drawables))) {
> > 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(channel, drawable);
> > + red_display_free_glz_drawable(dcc, drawable);
> > }
> > + pthread_rwlock_unlock(&glz_dict->encode_lock);
> > +}
> > +
> > +static void red_display_clear_glz_drawables(DisplayChannel *display_channel)
> > +{
> > + DisplayChannelClient *dcc = display_channel ?
> > + RCC_TO_DCC(display_channel->common.base.rcc) : NULL;
> >
> > - pthread_rwlock_unlock(&channel->glz_dict->encode_lock);
> > + if (!dcc) {
> > + return;
> > + }
> > + red_display_client_clear_glz_drawables(dcc);
> > }
> >
> > -/* Remove from the global lz dictionary some glz_drawables that have no reference to
> > - Drawable (their qxl drawables are released too).
> > - NOTE - the caller should prevent encoding using the dictionary during the operation*/
> > -static int red_display_free_some_independent_glz_drawables(DisplayChannel *channel)
> > +/*
> > + * Remove from the global lz dictionary some glz_drawables that have no reference to
> > + * Drawable (their qxl drawables are released too).
> > + * NOTE - the caller should prevent encoding using the dictionary during the operation
> > + */
> > +static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc)
> > {
> > + RingItem *ring_link;
> > int n = 0;
> >
> > - if (!channel) {
> > + if (!dcc) {
> > return 0;
> > }
> > -
> > - RingItem *ring_link = ring_get_head(&channel->glz_drawables);
> > -
> > + ring_link = ring_get_head(&dcc->glz_drawables);
> > while ((n < RED_RELEASE_BUNCH_SIZE) && (ring_link != NULL)) {
> > RedGlzDrawable *glz_drawable = SPICE_CONTAINEROF(ring_link, RedGlzDrawable, link);
> > - ring_link = ring_next(&channel->glz_drawables, ring_link);
> > + ring_link = ring_next(&dcc->glz_drawables, ring_link);
> > if (!glz_drawable->drawable) {
> > - red_display_free_glz_drawable(channel, glz_drawable);
> > + red_display_free_glz_drawable(dcc, glz_drawable);
> > n++;
> > }
> > }
> > @@ -4913,7 +4999,7 @@ static inline int encoder_usr_more_space(EncoderData *enc_data, uint32_t **io_pt
> > {
> > RedCompressBuf *buf;
> >
> > - if (!(buf = red_display_alloc_compress_buf(enc_data->display_channel))) {
> > + if (!(buf = red_display_alloc_compress_buf(enc_data->dcc))) {
> > return 0;
> > }
> > enc_data->bufs_tail->send_next = buf;
> > @@ -5023,24 +5109,22 @@ static int zlib_usr_more_input(ZlibEncoderUsrContext *usr, uint8_t** input)
> >
> > 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;
> > - DisplayChannel *drawable_channel = glz_drawable_instance->red_glz_drawable->display_channel;
> > - DisplayChannel *this_channel = SPICE_CONTAINEROF(lz_data, DisplayChannel, glz_data);
> > - if (this_channel == drawable_channel) {
> > - red_display_free_glz_drawable_instance(drawable_channel, glz_drawable_instance);
> > + 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 {
> > - pthread_mutex_lock(&drawable_channel->glz_drawables_inst_to_free_lock);
> > + pthread_mutex_lock(&drawable_cc->glz_drawables_inst_to_free_lock);
> > ring_add_before(&glz_drawable_instance->free_link,
> > - &drawable_channel->glz_drawables_inst_to_free);
> > - pthread_mutex_unlock(&drawable_channel->glz_drawables_inst_to_free_lock);
> > + &drawable_cc->glz_drawables_inst_to_free);
> > + pthread_mutex_unlock(&drawable_cc->glz_drawables_inst_to_free_lock);
> > }
> > }
> >
> > @@ -5078,16 +5162,17 @@ static inline void red_init_lz(RedWorker *worker)
> > }
> > }
> >
> > -static inline void red_display_init_glz_data(DisplayChannel *display)
> > +/* TODO: split off to DisplayChannel? avoid just copying those cb pointers */
> > +static inline void red_display_init_glz_data(DisplayChannelClient *dcc)
> > {
> > - display->glz_data.usr.error = glz_usr_error;
> > - display->glz_data.usr.warn = glz_usr_warn;
> > - display->glz_data.usr.info = glz_usr_warn;
> > - display->glz_data.usr.malloc = glz_usr_malloc;
> > - display->glz_data.usr.free = glz_usr_free;
> > - display->glz_data.usr.more_space = glz_usr_more_space;
> > - display->glz_data.usr.more_lines = glz_usr_more_lines;
> > - display->glz_data.usr.free_image = glz_usr_free_image;
> > + 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)
> > @@ -5261,16 +5346,17 @@ typedef struct compress_send_data_t {
> > } compress_send_data_t;
> >
> >
> > -static inline int red_glz_compress_image(DisplayChannel *display_channel,
> > +static inline int red_glz_compress_image(DisplayChannelClient *dcc,
> > SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
> > compress_send_data_t* o_comp_data)
> > {
> > - RedWorker *worker = (RedWorker *)display_channel->common.worker;
> > + DisplayChannel *display_channel = DCC_TO_DC(dcc);
> > + RedWorker *worker = display_channel->common.worker;
> > #ifdef COMPRESS_STAT
> > stat_time_t start_time = stat_now();
> > #endif
> > ASSERT(BITMAP_FMT_IS_RGB[src->format]);
> > - GlzData *glz_data = &display_channel->glz_data;
> > + GlzData *glz_data = &dcc->glz_data;
> > ZlibData *zlib_data;
> > LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
> > RedGlzDrawable *glz_drawable;
> > @@ -5278,7 +5364,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
> > int glz_size;
> > int zlib_size;
> >
> > - glz_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
> > + glz_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
> > glz_data->data.bufs_head = glz_data->data.bufs_tail;
> >
> > if (!glz_data->data.bufs_head) {
> > @@ -5286,9 +5372,9 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
> > }
> >
> > glz_data->data.bufs_head->send_next = NULL;
> > - glz_data->data.display_channel = display_channel;
> > + glz_data->data.dcc = dcc;
> >
> > - glz_drawable = red_display_get_glz_drawable(display_channel, drawable);
> > + 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;
> > @@ -5297,7 +5383,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
> > glz_data->data.u.lines_data.reverse = 0;
> > glz_data->usr.more_lines = glz_usr_more_lines;
> >
> > - glz_size = glz_encode(display_channel->glz, type, src->x, src->y,
> > + glz_size = glz_encode(dcc->glz, type, src->x, src->y,
> > (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), NULL, 0,
> > src->stride, (uint8_t*)glz_data->data.bufs_head->buf,
> > sizeof(glz_data->data.bufs_head->buf),
> > @@ -5314,7 +5400,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
> > #endif
> > zlib_data = &worker->zlib_data;
> >
> > - zlib_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
> > + zlib_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
> > zlib_data->data.bufs_head = zlib_data->data.bufs_tail;
> >
> > if (!zlib_data->data.bufs_head) {
> > @@ -5323,7 +5409,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
> > }
> >
> > zlib_data->data.bufs_head->send_next = NULL;
> > - zlib_data->data.display_channel = display_channel;
> > + 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;
> > @@ -5337,7 +5423,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
> > while (zlib_data->data.bufs_head) {
> > RedCompressBuf *buf = zlib_data->data.bufs_head;
> > zlib_data->data.bufs_head = buf->send_next;
> > - red_display_free_compress_buf(display_channel, buf);
> > + red_display_free_compress_buf(dcc, buf);
> > }
> > goto glz;
> > }
> > @@ -5361,10 +5447,11 @@ glz:
> > return TRUE;
> > }
> >
> > -static inline int red_lz_compress_image(DisplayChannel *display_channel,
> > +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;
> > @@ -5375,7 +5462,7 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
> > stat_time_t start_time = stat_now();
> > #endif
> >
> > - lz_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
> > + lz_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
> > lz_data->data.bufs_head = lz_data->data.bufs_tail;
> >
> > if (!lz_data->data.bufs_head) {
> > @@ -5383,13 +5470,13 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
> > }
> >
> > lz_data->data.bufs_head->send_next = NULL;
> > - lz_data->data.display_channel = display_channel;
> > + 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;
> > - red_display_free_compress_buf(display_channel, buf);
> > + red_display_free_compress_buf(dcc, buf);
> > }
> > return FALSE;
> > }
> > @@ -5427,7 +5514,7 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
> > o_comp_data->comp_buf = lz_data->data.bufs_head;
> > o_comp_data->comp_buf_size = size;
> >
> > - fill_palette(display_channel, dest->u.lz_plt.palette, &(dest->u.lz_plt.flags));
> > + fill_palette(dcc, dest->u.lz_plt.palette, &(dest->u.lz_plt.flags));
> > o_comp_data->lzplt_palette = dest->u.lz_plt.palette;
> > }
> >
> > @@ -5436,10 +5523,11 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
> > return TRUE;
> > }
> >
> > -static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *dest,
> > +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;
> > @@ -5475,7 +5563,7 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
> > return FALSE;
> > }
> >
> > - jpeg_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
> > + jpeg_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
> > jpeg_data->data.bufs_head = jpeg_data->data.bufs_tail;
> >
> > if (!jpeg_data->data.bufs_head) {
> > @@ -5484,13 +5572,13 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
> > }
> >
> > jpeg_data->data.bufs_head->send_next = NULL;
> > - jpeg_data->data.display_channel = display_channel;
> > + 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;
> > - red_display_free_compress_buf(display_channel, buf);
> > + red_display_free_compress_buf(dcc, buf);
> > }
> > return FALSE;
> > }
> > @@ -5541,7 +5629,7 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
> > comp_head_left = sizeof(lz_data->data.bufs_head->buf) - comp_head_filled;
> > lz_out_start_byte = ((uint8_t *)lz_data->data.bufs_head->buf) + comp_head_filled;
> >
> > - lz_data->data.display_channel = display_channel;
> > + lz_data->data.dcc = dcc;
> >
> > lz_data->data.u.lines_data.chunks = src->data;
> > lz_data->data.u.lines_data.stride = src->stride;
> > @@ -5577,10 +5665,11 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
> > return TRUE;
> > }
> >
> > -static inline int red_quic_compress_image(DisplayChannel *display_channel, SpiceImage *dest,
> > +static inline int red_quic_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;
> > QuicData *quic_data = &worker->quic_data;
> > QuicContext *quic = worker->quic;
> > @@ -5608,7 +5697,7 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, Spice
> > return FALSE;
> > }
> >
> > - quic_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
> > + quic_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
> > quic_data->data.bufs_head = quic_data->data.bufs_tail;
> >
> > if (!quic_data->data.bufs_head) {
> > @@ -5616,13 +5705,13 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, Spice
> > }
> >
> > quic_data->data.bufs_head->send_next = NULL;
> > - quic_data->data.display_channel = display_channel;
> > + 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;
> > - red_display_free_compress_buf(display_channel, buf);
> > + red_display_free_compress_buf(dcc, buf);
> > }
> > return FALSE;
> > }
> > @@ -5665,11 +5754,12 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, Spice
> >
> > #define MIN_SIZE_TO_COMPRESS 54
> > #define MIN_DIMENSION_TO_QUIC 3
> > -static inline int red_compress_image(DisplayChannel *display_channel,
> > +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);
> > spice_image_compression_t image_compression =
> > display_channel->common.worker->image_compression;
> > int quic_compress = FALSE;
> > @@ -5726,11 +5816,11 @@ static inline int red_compress_image(DisplayChannel *display_channel,
> > (image_compression == SPICE_IMAGE_COMPRESS_AUTO_GLZ))) {
> > // if we use lz for alpha, the stride can't be extra
> > if (src->format != SPICE_BITMAP_FMT_RGBA || !_stride_is_extra(src)) {
> > - return red_jpeg_compress_image(display_channel, dest,
> > + return red_jpeg_compress_image(dcc, dest,
> > src, o_comp_data, drawable->group_id);
> > }
> > }
> > - return red_quic_compress_image(display_channel, dest,
> > + return red_quic_compress_image(dcc, dest,
> > src, o_comp_data, drawable->group_id);
> > } else {
> > int glz;
> > @@ -5739,7 +5829,7 @@ static inline int red_compress_image(DisplayChannel *display_channel,
> > (image_compression == SPICE_IMAGE_COMPRESS_GLZ)) {
> > glz = BITMAP_FMT_IS_RGB[src->format] && (
> > (src->x * src->y) < glz_enc_dictionary_get_size(
> > - display_channel->glz_dict->dict));
> > + dcc->glz_dict->dict));
> > } else if ((image_compression == SPICE_IMAGE_COMPRESS_AUTO_LZ) ||
> > (image_compression == SPICE_IMAGE_COMPRESS_LZ)) {
> > glz = FALSE;
> > @@ -5748,20 +5838,20 @@ static inline int red_compress_image(DisplayChannel *display_channel,
> > }
> >
> > if (glz) {
> > - /* using the global dictionary only if it is not freezed */
> > - pthread_rwlock_rdlock(&display_channel->glz_dict->encode_lock);
> > - if (!display_channel->glz_dict->migrate_freeze) {
> > - ret = red_glz_compress_image(display_channel,
> > + /* 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(&display_channel->glz_dict->encode_lock);
> > + pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
> > }
> >
> > if (!glz) {
> > - ret = red_lz_compress_image(display_channel, dest, src, o_comp_data,
> > + ret = red_lz_compress_image(dcc, dest, src, o_comp_data,
> > drawable->group_id);
> > #ifdef COMPRESS_DEBUG
> > red_printf("LZ LOCAL compress");
> > @@ -5781,13 +5871,14 @@ static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
> > int is_lossy)
> > {
> > DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> >
> > if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
> > ASSERT(image->descriptor.width * image->descriptor.height > 0);
> > if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME)) {
> > - if (pixmap_cache_add(display_channel->pixmap_cache, image->descriptor.id,
> > + if (pixmap_cache_add(dcc->pixmap_cache, image->descriptor.id,
> > image->descriptor.width * image->descriptor.height, is_lossy,
> > - rcc)) {
> > + dcc)) {
> > io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
> > stat_inc_counter(display_channel->add_to_cache_counter, 1);
> > }
> > @@ -5810,11 +5901,12 @@ typedef enum {
> >
> > /* if the number of times fill_bits can be called per one qxl_drawable increases -
> > MAX_LZ_DRAWABLE_INSTANCES must be increased as well */
> > -static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
> > +static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
> > SpiceImage *simage, Drawable *drawable, int can_lossy)
> > {
> > + RedChannelClient *rcc = &dcc->common.base;
> > DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > - RedWorker *worker = display_channel->common.worker;
> > + Surfaces *surfaces = dcc->common.surfaces;
> > SpiceImage image;
> > compress_send_data_t comp_send_data = {0};
> > SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out;
> > @@ -5828,8 +5920,8 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
> >
> > if ((simage->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
> > int lossy_cache_item;
> > - if (pixmap_cache_hit(display_channel->pixmap_cache, image.descriptor.id,
> > - &lossy_cache_item, rcc)) {
> > + if (pixmap_cache_hit(dcc->pixmap_cache, image.descriptor.id,
> > + &lossy_cache_item, dcc)) {
> > if (can_lossy || !lossy_cache_item) {
> > if (!display_channel->enable_jpeg || lossy_cache_item) {
> > image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
> > @@ -5846,7 +5938,7 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
> > stat_inc_counter(display_channel->cache_hits_counter, 1);
> > return FILL_BITS_TYPE_CACHE;
> > } else {
> > - pixmap_cache_set_lossy(display_channel->pixmap_cache, simage->descriptor.id,
> > + pixmap_cache_set_lossy(dcc->pixmap_cache, simage->descriptor.id,
> > FALSE);
> > image.descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME;
> > }
> > @@ -5859,9 +5951,9 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
> > RedSurface *surface;
> >
> > surface_id = simage->u.surface.surface_id;
> > - validate_surface(&worker->surfaces, surface_id);
> > + validate_surface(surfaces, surface_id);
> >
> > - surface = &worker->surfaces.surfaces[surface_id];
> > + surface = &surfaces->surfaces[surface_id];
> > image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
> > image.descriptor.flags = 0;
> > image.descriptor.width = surface->context.width;
> > @@ -5882,7 +5974,7 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
> > /* Images must be added to the cache only after they are compressed
> > in order to prevent starvation in the client between pixmap_cache and
> > global dictionary (in cases of multiple monitors) */
> > - if (!red_compress_image(display_channel, &image, &simage->u.bitmap,
> > + if (!red_compress_image(dcc, &image, &simage->u.bitmap,
> > drawable, can_lossy, &comp_send_data)) {
> > SpicePalette *palette;
> >
> > @@ -5892,7 +5984,7 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
> > bitmap->flags = bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
> >
> > palette = bitmap->palette;
> > - fill_palette(display_channel, palette, &bitmap->flags);
> > + fill_palette(dcc, palette, &bitmap->flags);
> > spice_marshall_Image(m, &image,
> > &bitmap_palette_out, &lzplt_palette_out);
> > ASSERT(lzplt_palette_out == NULL);
> > @@ -5911,7 +6003,7 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
> > &bitmap_palette_out, &lzplt_palette_out);
> > ASSERT(bitmap_palette_out == NULL);
> >
> > - marshaller_add_compressed(worker, m, comp_send_data.comp_buf,
> > + marshaller_add_compressed(m, comp_send_data.comp_buf,
> > comp_send_data.comp_buf_size);
> >
> > if (lzplt_palette_out && comp_send_data.lzplt_palette) {
> > @@ -5942,16 +6034,17 @@ static void fill_mask(RedChannelClient *rcc, SpiceMarshaller *m,
> > SpiceImage *mask_bitmap, Drawable *drawable)
> > {
> > DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> >
> > if (mask_bitmap && m) {
> > if (display_channel->common.worker->image_compression != SPICE_IMAGE_COMPRESS_OFF) {
> > spice_image_compression_t save_img_comp =
> > display_channel->common.worker->image_compression;
> > display_channel->common.worker->image_compression = SPICE_IMAGE_COMPRESS_OFF;
> > - fill_bits(rcc, m, mask_bitmap, drawable, FALSE);
> > + fill_bits(dcc, m, mask_bitmap, drawable, FALSE);
> > display_channel->common.worker->image_compression = save_img_comp;
> > } else {
> > - fill_bits(rcc, m, mask_bitmap, drawable, FALSE);
> > + fill_bits(dcc, m, mask_bitmap, drawable, FALSE);
> > }
> > }
> > }
> > @@ -5967,7 +6060,7 @@ static void fill_attr(SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id
> > }
> > }
> >
> > -static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor, CursorItem *cursor, AddBufInfo *addbuf)
> > +static void fill_cursor(CursorChannelClient *ccc, SpiceCursor *red_cursor, CursorItem *cursor, AddBufInfo *addbuf)
> > {
> > addbuf->data = NULL;
> >
> > @@ -5983,11 +6076,11 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
> > *red_cursor = cursor_cmd->u.set.shape;
> >
> > if (red_cursor->header.unique) {
> > - if (red_cursor_cache_find(cursor_channel, red_cursor->header.unique)) {
> > + if (red_cursor_cache_find(ccc, red_cursor->header.unique)) {
> > red_cursor->flags |= SPICE_CURSOR_FLAGS_FROM_CACHE;
> > return;
> > }
> > - if (red_cursor_cache_add(cursor_channel->common.base.rcc, red_cursor->header.unique, 1)) {
> > + if (red_cursor_cache_add(ccc, red_cursor->header.unique, 1)) {
> > red_cursor->flags |= SPICE_CURSOR_FLAGS_CACHE_ME;
> > }
> > }
> > @@ -6008,24 +6101,25 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
> > }
> > }
> >
> > -static inline void red_display_reset_send_data(DisplayChannel *channel)
> > +static inline void red_display_reset_send_data(DisplayChannelClient *dcc)
> > {
> > - red_display_reset_compress_buf(channel);
> > - channel->send_data.free_list.res->count = 0;
> > - memset(channel->send_data.free_list.sync, 0, sizeof(channel->send_data.free_list.sync));
> > + red_display_reset_compress_buf(dcc);
> > + dcc->send_data.free_list.res->count = 0;
> > + memset(dcc->send_data.free_list.sync, 0, sizeof(dcc->send_data.free_list.sync));
> > }
> >
> > /* set area=NULL for testing the whole surface */
> > -static int is_surface_area_lossy(DisplayChannel *display_channel, uint32_t surface_id,
> > +static int is_surface_area_lossy(DisplayChannelClient *dcc, uint32_t surface_id,
> > const SpiceRect *area, SpiceRect *out_lossy_area)
> > {
> > RedSurface *surface;
> > QRegion *surface_lossy_region;
> > QRegion lossy_region;
> > + Surfaces *surfaces = dcc->common.surfaces;
> >
> > - validate_surface(&display_channel->common.worker->surfaces, surface_id);
> > - surface = &display_channel->common.worker->surfaces.surfaces[surface_id];
> > - surface_lossy_region = &display_channel->surface_client_lossy_region[surface_id];
> > + validate_surface(surfaces, surface_id);
> > + surface = &surfaces->surfaces[surface_id];
> > + surface_lossy_region = &dcc->surface_client_lossy_region[surface_id];
> >
> > if (!area) {
> > if (region_is_empty(surface_lossy_region)) {
> > @@ -6060,7 +6154,7 @@ static int is_surface_area_lossy(DisplayChannel *display_channel, uint32_t surfa
> > static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *area,
> > Drawable *drawable, BitmapData *out_data)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> >
> > if (image == NULL) {
> > // self bitmap
> > @@ -6072,8 +6166,8 @@ static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *
> > int is_hit_lossy;
> >
> > out_data->id = image->descriptor.id;
> > - if (pixmap_cache_hit(display_channel->pixmap_cache, image->descriptor.id,
> > - &is_hit_lossy, rcc)) {
> > + if (pixmap_cache_hit(dcc->pixmap_cache, image->descriptor.id,
> > + &is_hit_lossy, dcc)) {
> > out_data->type = BITMAP_DATA_TYPE_CACHE;
> > if (is_hit_lossy) {
> > return TRUE;
> > @@ -6094,7 +6188,7 @@ static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *
> > out_data->type = BITMAP_DATA_TYPE_SURFACE;
> > out_data->id = image->u.surface.surface_id;
> >
> > - if (is_surface_area_lossy(display_channel, out_data->id,
> > + if (is_surface_area_lossy(dcc, out_data->id,
> > area, &out_data->lossy_rect))
> > {
> > return TRUE;
> > @@ -6115,7 +6209,7 @@ static int is_brush_lossy(RedChannelClient *rcc, SpiceBrush *brush,
> > }
> > }
> >
> > -static void surface_lossy_region_update(RedWorker *worker, DisplayChannel *display_channel,
> > +static void surface_lossy_region_update(RedWorker *worker, DisplayChannelClient *dcc,
> > Drawable *item, int has_mask, int lossy)
> > {
> > QRegion *surface_lossy_region;
> > @@ -6125,7 +6219,7 @@ static void surface_lossy_region_update(RedWorker *worker, DisplayChannel *displ
> > return;
> > }
> >
> > - surface_lossy_region = &display_channel->surface_client_lossy_region[item->surface_id];
> > + surface_lossy_region = &dcc->surface_client_lossy_region[item->surface_id];
> > drawable = item->red_drawable;
> >
> > if (drawable->clip.type == SPICE_CLIP_TYPE_RECTS ) {
> > @@ -6155,8 +6249,8 @@ static void surface_lossy_region_update(RedWorker *worker, DisplayChannel *displ
> >
> > static inline int drawable_intersects_with_areas(Drawable *drawable, int surface_ids[],
> > SpiceRect *surface_areas[],
> > - int num_surfaces)
> > -{
> > + int num_surfaces)
> > +{
> > int i;
> > for (i = 0; i < num_surfaces; i++) {
> > if (surface_ids[i] == drawable->red_drawable->surface_id) {
> > @@ -6172,7 +6266,7 @@ static inline int drawable_depends_on_areas(Drawable *drawable,
> > int surface_ids[],
> > SpiceRect surface_areas[],
> > int num_surfaces)
> > -{
> > +{
> > int i;
> > RedDrawable *red_drawable;
> > int drawable_has_shadow;
> > @@ -6227,7 +6321,7 @@ static inline int drawable_depends_on_areas(Drawable *drawable,
> >
> >
> > static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
> > - DisplayChannel *display_channel,
> > + DisplayChannelClient *dcc,
> > int surface_ids[],
> > SpiceRect *surface_areas[],
> > int num_surfaces)
> > @@ -6236,7 +6330,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
> > Ring *pipe;
> >
> > ASSERT(num_surfaces);
> > - pipe = &display_channel->common.base.rcc->pipe;
> > + pipe = &dcc->common.base.pipe;
> >
> > for (pipe_item = (PipeItem *)ring_get_head(pipe);
> > pipe_item;
> > @@ -6247,7 +6341,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
> > if (pipe_item->type != PIPE_ITEM_TYPE_DRAW)
> > continue;
> > drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
> > -
> > +
> > if (ring_item_is_linked(&drawable->list_link))
> > continue; // item hasn't been rendered
> >
> > @@ -6260,7 +6354,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
> > }
> >
> > static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
> > - DisplayChannel *display_channel,
> > + DisplayChannelClient *dcc,
> > int first_surface_id,
> > SpiceRect *first_area)
> > {
> > @@ -6274,7 +6368,7 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
> > resent_areas[0] = *first_area;
> > num_resent = 1;
> >
> > - pipe = &display_channel->common.base.rcc->pipe;
> > + pipe = &dcc->common.base.pipe;
> >
> > // going from the oldest to the newest
> > for (pipe_item = (PipeItem *)ring_get_tail(pipe);
> > @@ -6312,17 +6406,18 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
> > }
> >
> > static void red_add_lossless_drawable_dependencies(RedWorker *worker,
> > - DisplayChannel *display_channel,
> > + RedChannelClient *rcc,
> > Drawable *item,
> > int deps_surfaces_ids[],
> > SpiceRect *deps_areas[],
> > int num_deps)
> > {
> > RedDrawable *drawable = item->red_drawable;
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > + Surfaces *surfaces = dcc->common.surfaces;
> > int sync_rendered = FALSE;
> > int i;
> >
> > -
> > if (!ring_item_is_linked(&item->list_link)) {
> > /* drawable was already rendered, we may not be able to retrieve the lossless data
> > for the lossy areas */
> > @@ -6332,7 +6427,7 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
> > // that were rendered, affected the areas that need to be resent
> > if (!drawable_intersects_with_areas(item, deps_surfaces_ids,
> > deps_areas, num_deps)) {
> > - if (pipe_rendered_drawables_intersect_with_areas(worker, display_channel,
> > + if (pipe_rendered_drawables_intersect_with_areas(worker, dcc,
> > deps_surfaces_ids,
> > deps_areas,
> > num_deps)) {
> > @@ -6344,7 +6439,7 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
> > } else {
> > sync_rendered = FALSE;
> > for (i = 0; i < num_deps; i++) {
> > - red_update_area_till(worker, &worker->surfaces, deps_areas[i],
> > + red_update_area_till(worker, surfaces, deps_areas[i],
> > deps_surfaces_ids[i], item);
> > }
> > }
> > @@ -6367,11 +6462,11 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
> > drawable_bbox[0] = &drawable->bbox;
> >
> > // check if the other rendered images in the pipe have updated the drawable bbox
> > - if (pipe_rendered_drawables_intersect_with_areas(worker, display_channel,
> > + if (pipe_rendered_drawables_intersect_with_areas(worker, dcc,
> > drawable_surface_id,
> > drawable_bbox,
> > 1)) {
> > - red_pipe_replace_rendered_drawables_with_images(worker, display_channel,
> > + red_pipe_replace_rendered_drawables_with_images(worker, dcc,
> > drawable->surface_id,
> > &drawable->bbox);
> > }
> > @@ -6388,6 +6483,7 @@ static void red_marshall_qxl_draw_fill(RedWorker *worker,
> > Drawable *item)
> > {
> > RedDrawable *drawable = item->red_drawable;
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > SpiceMarshaller *brush_pat_out;
> > SpiceMarshaller *mask_bitmap_out;
> > SpiceFill fill;
> > @@ -6401,7 +6497,7 @@ static void red_marshall_qxl_draw_fill(RedWorker *worker,
> > &mask_bitmap_out);
> >
> > if (brush_pat_out) {
> > - fill_bits(rcc, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE);
> > + fill_bits(dcc, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE);
> > }
> >
> > fill_mask(rcc, mask_bitmap_out, fill.mask.bitmap, item);
> > @@ -6413,7 +6509,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
> > SpiceMarshaller *m,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> >
> > int dest_allowed_lossy = FALSE;
> > @@ -6432,7 +6528,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
> > brush_is_lossy = is_brush_lossy(rcc, &drawable->u.fill.brush, item,
> > &brush_bitmap_data);
> > if (!dest_allowed_lossy) {
> > - dest_is_lossy = is_surface_area_lossy(display_channel, item->surface_id, &drawable->bbox,
> > + dest_is_lossy = is_surface_area_lossy(dcc, item->surface_id, &drawable->bbox,
> > &dest_lossy_area);
> > }
> >
> > @@ -6442,7 +6538,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
> >
> > red_marshall_qxl_draw_fill(worker, rcc, m, item);
> > // either the brush operation is opaque, or the dest is not lossy
> > - surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
> > + surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
> > } else {
> > int resend_surface_ids[2];
> > SpiceRect *resend_areas[2];
> > @@ -6460,7 +6556,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
> > num_resend++;
> > }
> >
> > - red_add_lossless_drawable_dependencies(worker, display_channel, item,
> > + red_add_lossless_drawable_dependencies(worker, rcc, item,
> > resend_surface_ids, resend_areas, num_resend);
> > }
> > }
> > @@ -6470,6 +6566,7 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item, int src_allowed_lossy)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > SpiceMarshaller *brush_pat_out;
> > SpiceMarshaller *src_bitmap_out;
> > @@ -6486,11 +6583,11 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
> > &brush_pat_out,
> > &mask_bitmap_out);
> >
> > - src_send_type = fill_bits(rcc, src_bitmap_out, opaque.src_bitmap, item,
> > + src_send_type = fill_bits(dcc, src_bitmap_out, opaque.src_bitmap, item,
> > src_allowed_lossy);
> >
> > if (brush_pat_out) {
> > - fill_bits(rcc, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE);
> > + fill_bits(dcc, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE);
> > }
> > fill_mask(rcc, mask_bitmap_out, opaque.mask.bitmap, item);
> >
> > @@ -6502,7 +6599,7 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
> > SpiceMarshaller *m,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> >
> > int src_allowed_lossy;
> > @@ -6539,11 +6636,11 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
> > src_is_lossy = FALSE;
> > }
> >
> > - surface_lossy_region_update(worker, display_channel, item, has_mask, src_is_lossy);
> > + surface_lossy_region_update(worker, dcc, item, has_mask, src_is_lossy);
> > } else {
> > int resend_surface_ids[2];
> > SpiceRect *resend_areas[2];
> > - int num_resend = 0;
> > + int num_resend = 0;
> >
> > if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) {
> > resend_surface_ids[num_resend] = src_bitmap_data.id;
> > @@ -6557,7 +6654,7 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
> > num_resend++;
> > }
> >
> > - red_add_lossless_drawable_dependencies(worker, display_channel, item,
> > + red_add_lossless_drawable_dependencies(worker, rcc, item,
> > resend_surface_ids, resend_areas, num_resend);
> > }
> > }
> > @@ -6568,6 +6665,7 @@ static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
> > Drawable *item, int src_allowed_lossy)
> > {
> > RedDrawable *drawable = item->red_drawable;
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > SpiceMarshaller *src_bitmap_out;
> > SpiceMarshaller *mask_bitmap_out;
> > SpiceCopy copy;
> > @@ -6581,7 +6679,7 @@ static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
> > &src_bitmap_out,
> > &mask_bitmap_out);
> >
> > - src_send_type = fill_bits(rcc, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy);
> > + src_send_type = fill_bits(dcc, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy);
> > fill_mask(rcc, mask_bitmap_out, copy.mask.bitmap, item);
> >
> > return src_send_type;
> > @@ -6592,7 +6690,7 @@ static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > int has_mask = !!drawable->u.copy.mask.bitmap;
> > int src_is_lossy;
> > @@ -6610,7 +6708,7 @@ static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
> > src_is_lossy = FALSE;
> > }
> >
> > - surface_lossy_region_update(worker, display_channel, item, has_mask,
> > + surface_lossy_region_update(worker, dcc, item, has_mask,
> > src_is_lossy);
> > }
> >
> > @@ -6619,6 +6717,7 @@ static void red_marshall_qxl_draw_transparent(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > SpiceMarshaller *src_bitmap_out;
> > SpiceTransparent transparent;
> > @@ -6629,7 +6728,7 @@ static void red_marshall_qxl_draw_transparent(RedWorker *worker,
> > spice_marshall_Transparent(base_marshaller,
> > &transparent,
> > &src_bitmap_out);
> > - fill_bits(rcc, src_bitmap_out, transparent.src_bitmap, item, FALSE);
> > + fill_bits(dcc, src_bitmap_out, transparent.src_bitmap, item, FALSE);
> > }
> >
> > static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
> > @@ -6637,7 +6736,6 @@ static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > RedDrawable *drawable = item->red_drawable;
> > int src_is_lossy;
> > BitmapData src_bitmap_data;
> > @@ -6655,7 +6753,7 @@ static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
> > resend_surface_ids[0] = src_bitmap_data.id;
> > resend_areas[0] = &src_bitmap_data.lossy_rect;
> >
> > - red_add_lossless_drawable_dependencies(worker, display_channel, item,
> > + red_add_lossless_drawable_dependencies(worker, rcc, item,
> > resend_surface_ids, resend_areas, 1);
> > }
> > }
> > @@ -6666,6 +6764,7 @@ static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
> > Drawable *item,
> > int src_allowed_lossy)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > SpiceMarshaller *src_bitmap_out;
> > SpiceAlphaBlend alpha_blend;
> > @@ -6677,7 +6776,7 @@ static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
> > spice_marshall_AlphaBlend(base_marshaller,
> > &alpha_blend,
> > &src_bitmap_out);
> > - src_send_type = fill_bits(rcc, src_bitmap_out, alpha_blend.src_bitmap, item, src_allowed_lossy);
> > + src_send_type = fill_bits(dcc, src_bitmap_out, alpha_blend.src_bitmap, item, src_allowed_lossy);
> >
> > return src_send_type;
> > }
> > @@ -6687,7 +6786,7 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > int src_is_lossy;
> > BitmapData src_bitmap_data;
> > @@ -6705,7 +6804,7 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
> > }
> >
> > if (src_is_lossy) {
> > - surface_lossy_region_update(worker, display_channel, item, FALSE, src_is_lossy);
> > + surface_lossy_region_update(worker, dcc, item, FALSE, src_is_lossy);
> > } // else, the area stays lossy/lossless as the destination
> > }
> >
> > @@ -6729,7 +6828,7 @@ static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > SpiceRect src_rect;
> > int horz_offset;
> > @@ -6747,10 +6846,10 @@ static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
> > src_rect.right = drawable->bbox.right + horz_offset;
> > src_rect.bottom = drawable->bbox.bottom + vert_offset;
> >
> > - src_is_lossy = is_surface_area_lossy(display_channel, item->surface_id,
> > + src_is_lossy = is_surface_area_lossy(dcc, item->surface_id,
> > &src_rect, &src_lossy_area);
> >
> > - surface_lossy_region_update(worker, display_channel, item, FALSE,
> > + surface_lossy_region_update(worker, dcc, item, FALSE,
> > src_is_lossy);
> > }
> >
> > @@ -6759,6 +6858,7 @@ static void red_marshall_qxl_draw_blend(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > SpiceMarshaller *src_bitmap_out;
> > SpiceMarshaller *mask_bitmap_out;
> > @@ -6772,7 +6872,7 @@ static void red_marshall_qxl_draw_blend(RedWorker *worker,
> > &src_bitmap_out,
> > &mask_bitmap_out);
> >
> > - fill_bits(rcc, src_bitmap_out, blend.src_bitmap, item, FALSE);
> > + fill_bits(dcc, src_bitmap_out, blend.src_bitmap, item, FALSE);
> >
> > fill_mask(rcc, mask_bitmap_out, blend.mask.bitmap, item);
> > }
> > @@ -6782,7 +6882,7 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > int src_is_lossy;
> > BitmapData src_bitmap_data;
> > @@ -6791,7 +6891,7 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
> >
> > src_is_lossy = is_bitmap_lossy(rcc, drawable->u.blend.src_bitmap,
> > &drawable->u.blend.src_area, item, &src_bitmap_data);
> > - dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
> > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
> > &drawable->bbox, &dest_lossy_area);
> >
> > if (!dest_is_lossy &&
> > @@ -6814,7 +6914,7 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
> > num_resend++;
> > }
> >
> > - red_add_lossless_drawable_dependencies(worker, display_channel, item,
> > + red_add_lossless_drawable_dependencies(worker, rcc, item,
> > resend_surface_ids, resend_areas, num_resend);
> > }
> > }
> > @@ -6844,13 +6944,13 @@ static void red_lossy_marshall_qxl_draw_blackness(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > int has_mask = !!drawable->u.blackness.mask.bitmap;
> >
> > red_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, item);
> >
> > - surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
> > + surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
> > }
> >
> > static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
> > @@ -6878,13 +6978,13 @@ static void red_lossy_marshall_qxl_draw_whiteness(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > int has_mask = !!drawable->u.whiteness.mask.bitmap;
> >
> > red_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, item);
> >
> > - surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
> > + surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
> > }
> >
> > static void red_marshall_qxl_draw_inverse(RedWorker *worker,
> > @@ -6920,6 +7020,7 @@ static void red_marshall_qxl_draw_rop3(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > SpiceRop3 rop3;
> > SpiceMarshaller *src_bitmap_out;
> > @@ -6935,10 +7036,10 @@ static void red_marshall_qxl_draw_rop3(RedWorker *worker,
> > &brush_pat_out,
> > &mask_bitmap_out);
> >
> > - fill_bits(rcc, src_bitmap_out, rop3.src_bitmap, item, FALSE);
> > + fill_bits(dcc, src_bitmap_out, rop3.src_bitmap, item, FALSE);
> >
> > if (brush_pat_out) {
> > - fill_bits(rcc, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE);
> > + fill_bits(dcc, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE);
> > }
> > fill_mask(rcc, mask_bitmap_out, rop3.mask.bitmap, item);
> > }
> > @@ -6948,7 +7049,7 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > int src_is_lossy;
> > BitmapData src_bitmap_data;
> > @@ -6961,7 +7062,7 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
> > &drawable->u.rop3.src_area, item, &src_bitmap_data);
> > brush_is_lossy = is_brush_lossy(rcc, &drawable->u.rop3.brush, item,
> > &brush_bitmap_data);
> > - dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
> > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
> > &drawable->bbox, &dest_lossy_area);
> >
> > if ((!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
> > @@ -6969,11 +7070,11 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
> > !dest_is_lossy) {
> > int has_mask = !!drawable->u.rop3.mask.bitmap;
> > red_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, item);
> > - surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
> > + surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
> > } else {
> > int resend_surface_ids[3];
> > SpiceRect *resend_areas[3];
> > - int num_resend = 0;
> > + int num_resend = 0;
> >
> > if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) {
> > resend_surface_ids[num_resend] = src_bitmap_data.id;
> > @@ -6993,7 +7094,7 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
> > num_resend++;
> > }
> >
> > - red_add_lossless_drawable_dependencies(worker, display_channel, item,
> > + red_add_lossless_drawable_dependencies(worker, rcc, item,
> > resend_surface_ids, resend_areas, num_resend);
> > }
> > }
> > @@ -7003,6 +7104,7 @@ static void red_marshall_qxl_draw_stroke(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > SpiceStroke stroke;
> > SpiceMarshaller *brush_pat_out;
> > @@ -7018,7 +7120,7 @@ static void red_marshall_qxl_draw_stroke(RedWorker *worker,
> >
> > fill_attr(style_out, &stroke.attr, item->group_id);
> > if (brush_pat_out) {
> > - fill_bits(rcc, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
> > + fill_bits(dcc, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
> > }
> > }
> >
> > @@ -7027,7 +7129,7 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > int brush_is_lossy;
> > BitmapData brush_bitmap_data;
> > @@ -7046,7 +7148,7 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
> > if (drawable->u.stroke.brush.type != SPICE_BRUSH_TYPE_SOLID &&
> > ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) ||
> > (rop & SPICE_ROPD_OP_XOR))) {
> > - dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
> > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
> > &drawable->bbox, &dest_lossy_area);
> > }
> >
> > @@ -7072,7 +7174,7 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
> > num_resend++;
> > }
> >
> > - red_add_lossless_drawable_dependencies(worker, display_channel, item,
> > + red_add_lossless_drawable_dependencies(worker, rcc, item,
> > resend_surface_ids, resend_areas, num_resend);
> > }
> > }
> > @@ -7082,6 +7184,7 @@ static void red_marshall_qxl_draw_text(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > SpiceText text;
> > SpiceMarshaller *brush_pat_out;
> > @@ -7096,10 +7199,10 @@ static void red_marshall_qxl_draw_text(RedWorker *worker,
> > &back_brush_pat_out);
> >
> > if (brush_pat_out) {
> > - fill_bits(rcc, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE);
> > + fill_bits(dcc, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE);
> > }
> > if (back_brush_pat_out) {
> > - fill_bits(rcc, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE);
> > + fill_bits(dcc, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE);
> > }
> > }
> >
> > @@ -7108,7 +7211,7 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
> > SpiceMarshaller *base_marshaller,
> > Drawable *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *drawable = item->red_drawable;
> > int fg_is_lossy;
> > BitmapData fg_bitmap_data;
> > @@ -7135,7 +7238,7 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
> >
> > if ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) ||
> > (rop & SPICE_ROPD_OP_XOR)) {
> > - dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
> > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
> > &drawable->bbox, &dest_lossy_area);
> > }
> >
> > @@ -7165,7 +7268,7 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
> > resend_areas[num_resend] = &dest_lossy_area;
> > num_resend++;
> > }
> > - red_add_lossless_drawable_dependencies(worker, display_channel, item,
> > + red_add_lossless_drawable_dependencies(worker, rcc, item,
> > resend_surface_ids, resend_areas, num_resend);
> > }
> > }
> > @@ -7268,10 +7371,10 @@ static inline void red_marshall_qxl_drawable(RedWorker *worker, RedChannelClient
> > }
> > }
> >
> > -static void display_channel_push_release(DisplayChannel *channel, uint8_t type, uint64_t id,
> > +static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type, uint64_t id,
> > uint64_t* sync_data)
> > {
> > - FreeList *free_list = &channel->send_data.free_list;
> > + FreeList *free_list = &dcc->send_data.free_list;
> > int i;
> >
> > for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
> > @@ -7294,8 +7397,8 @@ static void display_channel_push_release(DisplayChannel *channel, uint8_t type,
> >
> > static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > - FreeList *free_list = &display_channel->send_data.free_list;
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > + FreeList *free_list = &dcc->send_data.free_list;
> > SpiceDataHeader *header = red_channel_client_get_header(rcc);
> >
> > if (free_list->res->count) {
> > @@ -7314,7 +7417,7 @@ static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarsha
> > spice_marshall_msg_display_inval_list(inval_m, free_list->res);
> >
> > for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
> > - if (i != display_channel->common.id && free_list->sync[i] != 0) {
> > + if (i != dcc->common.id && free_list->sync[i] != 0) {
> > free_list->wait.header.wait_list[sync_count].channel_type = SPICE_CHANNEL_DISPLAY;
> > free_list->wait.header.wait_list[sync_count].channel_id = i;
> > free_list->wait.header.wait_list[sync_count++].message_serial = free_list->sync[i];
> > @@ -7344,29 +7447,6 @@ static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarsha
> > red_channel_client_begin_send_message(rcc);
> > }
> >
> > -static inline RedChannel *red_ref_channel(RedChannel *channel)
> > -{
> > - CommonChannel *common;
> > -
> > - if (!channel) {
> > - return NULL;
> > - }
> > - common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> > - ++common->listener.refs;
> > - return channel;
> > -}
> > -
> > -static inline void red_unref_channel(RedChannel *channel)
> > -{
> > - CommonChannel *common;
> > -
> > - ASSERT(channel);
> > - common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> > - if (!--common->listener.refs) {
> > - red_channel_destroy(channel);
> > - }
> > -}
> > -
> > static inline uint8_t *red_get_image_line(RedWorker *worker, SpiceChunks *chunks, size_t *offset,
> > int *chunk_nr, int stride)
> > {
> > @@ -7545,11 +7625,12 @@ static int red_rgb16bpp_to_24 (RedWorker *worker, const SpiceRect *src,
> > static inline int red_marshall_stream_data(RedChannelClient *rcc,
> > SpiceMarshaller *base_marshaller, Drawable *drawable)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > Stream *stream = drawable->stream;
> > SpiceImage *image;
> > RedWorker* worker;
> > - Surfaces *surfaces;
> > + Surfaces *surfaces = dcc->common.surfaces;
> > uint8_t *frame;
> > size_t frame_stride;
> > int n;
> > @@ -7558,14 +7639,13 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
> > ASSERT(drawable->red_drawable->type == QXL_DRAW_COPY);
> >
> > worker = display_channel->common.worker;
> > - surfaces = &worker->surfaces;
> > image = drawable->red_drawable->u.copy.src_bitmap;
> >
> > if (image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) {
> > return FALSE;
> > }
> >
> > - StreamAgent *agent = &display_channel->stream_agents[stream - surfaces->streams_buf];
> > + StreamAgent *agent = &dcc->stream_agents[stream - surfaces->streams_buf];
> > uint64_t time_now = red_now();
> > if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) {
> > agent->frames--;
> > @@ -7603,18 +7683,18 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
> > }
> >
> > while ((n = mjpeg_encoder_encode_frame(stream->mjpeg_encoder,
> > - display_channel->send_data.stream_outbuf,
> > - display_channel->send_data.stream_outbuf_size)) == 0) {
> > + dcc->send_data.stream_outbuf,
> > + dcc->send_data.stream_outbuf_size)) == 0) {
> > uint8_t *new_buf;
> > size_t new_size;
> >
> > - new_size = display_channel->send_data.stream_outbuf_size * 2;
> > + new_size = dcc->send_data.stream_outbuf_size * 2;
> > new_buf = spice_malloc(new_size);
> >
> > red_display_unshare_stream_buf(display_channel);
> > - free(display_channel->send_data.stream_outbuf);
> > - display_channel->send_data.stream_outbuf = new_buf;
> > - display_channel->send_data.stream_outbuf_size = new_size;
> > + free(dcc->send_data.stream_outbuf);
> > + dcc->send_data.stream_outbuf = new_buf;
> > + dcc->send_data.stream_outbuf_size = new_size;
> > red_display_share_stream_buf(display_channel);
> > }
> >
> > @@ -7627,7 +7707,7 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
> > stream_data.data_size = n;
> > spice_marshall_msg_display_stream_data(base_marshaller, &stream_data);
> > spice_marshaller_add_ref(base_marshaller,
> > - display_channel->send_data.stream_outbuf, n);
> > + dcc->send_data.stream_outbuf, n);
> > agent->last_send_time = time_now;
> > return TRUE;
> > }
> > @@ -7678,30 +7758,30 @@ static void display_channel_marshall_migrate(RedChannelClient *rcc,
> >
> > static void display_channel_marshall_migrate_data(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > DisplayChannelMigrateData display_data;
> >
> > red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL);
> >
> > - ASSERT(display_channel->pixmap_cache);
> > + ASSERT(dcc->pixmap_cache);
> > display_data.magic = DISPLAY_MIGRATE_DATA_MAGIC;
> > ASSERT(MAX_CACHE_CLIENTS == 4); //MIGRATE_DATA_VERSION dependent
> > display_data.version = DISPLAY_MIGRATE_DATA_VERSION;
> >
> > display_data.message_serial = red_channel_client_get_message_serial(rcc);
> >
> > - display_data.pixmap_cache_freezer = pixmap_cache_freeze(display_channel->pixmap_cache);
> > - display_data.pixmap_cache_id = display_channel->pixmap_cache->id;
> > - display_data.pixmap_cache_size = display_channel->pixmap_cache->size;
> > - memcpy(display_data.pixmap_cache_clients, display_channel->pixmap_cache->sync,
> > + display_data.pixmap_cache_freezer = pixmap_cache_freeze(dcc->pixmap_cache);
> > + display_data.pixmap_cache_id = dcc->pixmap_cache->id;
> > + display_data.pixmap_cache_size = dcc->pixmap_cache->size;
> > + memcpy(display_data.pixmap_cache_clients, dcc->pixmap_cache->sync,
> > sizeof(display_data.pixmap_cache_clients));
> >
> > - ASSERT(display_channel->glz_dict);
> > - red_freeze_glz(display_channel);
> > - display_data.glz_dict_id = display_channel->glz_dict->id;
> > - glz_enc_dictionary_get_restore_data(display_channel->glz_dict->dict,
> > + ASSERT(dcc->glz_dict);
> > + red_freeze_glz(dcc);
> > + display_data.glz_dict_id = dcc->glz_dict->id;
> > + glz_enc_dictionary_get_restore_data(dcc->glz_dict->dict,
> > &display_data.glz_dict_restore_data,
> > - &display_channel->glz_data.usr);
> > + &dcc->glz_data.usr);
> >
> > spice_marshaller_add_ref(base_marshaller,
> > (uint8_t *)&display_data, sizeof(display_data));
> > @@ -7709,12 +7789,12 @@ static void display_channel_marshall_migrate_data(RedChannelClient *rcc, SpiceMa
> >
> > static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > SpiceMsgWaitForChannels wait;
> > PixmapCache *pixmap_cache;
> >
> > red_channel_client_init_send_data(rcc, SPICE_MSG_WAIT_FOR_CHANNELS, NULL);
> > - pixmap_cache = display_channel->pixmap_cache;
> > + pixmap_cache = dcc->pixmap_cache;
> >
> > pthread_mutex_lock(&pixmap_cache->lock);
> >
> > @@ -7722,8 +7802,8 @@ static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, SpiceMar
> > wait.wait_list[0].channel_type = SPICE_CHANNEL_DISPLAY;
> > wait.wait_list[0].channel_id = pixmap_cache->generation_initiator.client;
> > wait.wait_list[0].message_serial = pixmap_cache->generation_initiator.message;
> > - display_channel->pixmap_cache_generation = pixmap_cache->generation;
> > - display_channel->pending_pixmaps_sync = FALSE;
> > + dcc->pixmap_cache_generation = pixmap_cache->generation;
> > + dcc->pending_pixmaps_sync = FALSE;
> >
> > pthread_mutex_unlock(&pixmap_cache->lock);
> >
> > @@ -7732,11 +7812,11 @@ static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, SpiceMar
> >
> > static void display_channel_marshall_reset_cache(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > SpiceMsgWaitForChannels wait;
> >
> > red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL);
> > - pixmap_cache_reset(display_channel->pixmap_cache, rcc, &wait);
> > + pixmap_cache_reset(dcc->pixmap_cache, dcc, &wait);
> >
> > spice_marshall_msg_display_inval_all_pixmaps(base_marshaller,
> > &wait);
> > @@ -7744,7 +7824,8 @@ static void display_channel_marshall_reset_cache(RedChannelClient *rcc, SpiceMar
> >
> > static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, ImageItem *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > + DisplayChannel *display_channel = DCC_TO_DC(dcc);
> > SpiceImage red_image;
> > RedWorker *worker;
> > SpiceBitmap bitmap;
> > @@ -7818,7 +7899,7 @@ static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, Image
> > &bitmap,
> > worker->mem_slots.internal_groupslot_id);
> > if (grad_level == BITMAP_GRADUAL_HIGH) {
> > - // if we use lz for alpha, the stride can't be extra
> > + // if we use lz for alpha, the stride can't be extra
> > lossy_comp = display_channel->enable_jpeg && item->can_lossy;
> > } else {
> > lz_comp = TRUE;
> > @@ -7830,27 +7911,27 @@ static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, Image
> > }
> >
> > if (lossy_comp) {
> > - comp_succeeded = red_jpeg_compress_image(display_channel, &red_image,
> > + comp_succeeded = red_jpeg_compress_image(dcc, &red_image,
> > &bitmap, &comp_send_data,
> > worker->mem_slots.internal_groupslot_id);
> > } else {
> > if (!lz_comp) {
> > - comp_succeeded = red_quic_compress_image(display_channel, &red_image, &bitmap,
> > + comp_succeeded = red_quic_compress_image(dcc, &red_image, &bitmap,
> > &comp_send_data,
> > worker->mem_slots.internal_groupslot_id);
> > } else {
> > - comp_succeeded = red_lz_compress_image(display_channel, &red_image, &bitmap,
> > + comp_succeeded = red_lz_compress_image(dcc, &red_image, &bitmap,
> > &comp_send_data,
> > worker->mem_slots.internal_groupslot_id);
> > }
> > }
> >
> > - surface_lossy_region = &display_channel->surface_client_lossy_region[item->surface_id];
> > + surface_lossy_region = &dcc->surface_client_lossy_region[item->surface_id];
> > if (comp_succeeded) {
> > spice_marshall_Image(src_bitmap_out, &red_image,
> > &bitmap_palette_out, &lzplt_palette_out);
> >
> > - marshaller_add_compressed(worker, src_bitmap_out,
> > + marshaller_add_compressed(src_bitmap_out,
> > comp_send_data.comp_buf, comp_send_data.comp_buf_size);
> >
> > if (lzplt_palette_out && comp_send_data.lzplt_palette) {
> > @@ -7877,6 +7958,7 @@ static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, Image
> >
> > static void red_display_marshall_upgrade(RedChannelClient *rcc, SpiceMarshaller *m, UpgradeItem *item)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > RedDrawable *red_drawable;
> > SpiceMsgDisplayDrawCopy copy;
> > SpiceMarshaller *src_bitmap_out, *mask_bitmap_out;
> > @@ -7899,13 +7981,13 @@ static void red_display_marshall_upgrade(RedChannelClient *rcc, SpiceMarshaller
> > spice_marshall_msg_display_draw_copy(m, ©,
> > &src_bitmap_out, &mask_bitmap_out);
> >
> > - fill_bits(rcc, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
> > + fill_bits(dcc, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
> > }
> >
> > static void red_display_marshall_stream_start(RedChannelClient *rcc,
> > SpiceMarshaller *base_marshaller, StreamAgent *agent)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > Stream *stream = agent->stream;
> >
> > agent->last_send_time = 0;
> > @@ -7916,7 +7998,7 @@ static void red_display_marshall_stream_start(RedChannelClient *rcc,
> > SpiceClipRects clip_rects;
> >
> > stream_create.surface_id = 0;
> > - stream_create.id = agent - display_channel->stream_agents;
> > + stream_create.id = agent - dcc->stream_agents;
> > stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0;
> > stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG;
> >
> > @@ -7942,7 +8024,7 @@ static void red_display_marshall_stream_clip(RedChannelClient *rcc,
> > SpiceMarshaller *base_marshaller,
> > StreamClipItem *item)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > StreamAgent *agent = item->stream_agent;
> > Stream *stream = agent->stream;
> >
> > @@ -7951,7 +8033,7 @@ static void red_display_marshall_stream_clip(RedChannelClient *rcc,
> > red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base);
> > SpiceMsgDisplayStreamClip stream_clip;
> >
> > - stream_clip.id = agent - display_channel->stream_agents;
> > + stream_clip.id = agent - dcc->stream_agents;
> > stream_clip.clip.type = item->clip_type;
> > stream_clip.clip.rects = item->rects;
> >
> > @@ -7961,11 +8043,11 @@ static void red_display_marshall_stream_clip(RedChannelClient *rcc,
> > static void red_display_marshall_stream_end(RedChannelClient *rcc,
> > SpiceMarshaller *base_marshaller, StreamAgent* agent)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > SpiceMsgDisplayStreamDestroy destroy;
> >
> > red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
> > - destroy.id = agent - display_channel->stream_agents;
> > + destroy.id = agent - dcc->stream_agents;
> >
> > spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
> > }
> > @@ -7980,6 +8062,7 @@ static void red_cursor_marshall_inval(RedChannelClient *rcc,
> > static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
> > {
> > CursorChannel *cursor_channel;
> > + CursorChannelClient *ccc = RCC_TO_CCC(rcc);
> > RedWorker *worker;
> > SpiceMsgCursorInit msg;
> > AddBufInfo info;
> > @@ -7994,7 +8077,7 @@ static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *bas
> > msg.trail_length = worker->cursor_trail_length;
> > msg.trail_frequency = worker->cursor_trail_frequency;
> >
> > - fill_cursor(cursor_channel, &msg.cursor, worker->cursor, &info);
> > + fill_cursor(ccc, &msg.cursor, worker->cursor, &info);
> > spice_marshall_msg_cursor_init(base_marshaller, &msg);
> > add_buf_from_info(base_marshaller, &info);
> > }
> > @@ -8003,6 +8086,7 @@ static void red_marshall_local_cursor(RedChannelClient *rcc,
> > SpiceMarshaller *base_marshaller, LocalCursor *cursor)
> > {
> > CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
> > + CursorChannelClient *ccc = RCC_TO_CCC(rcc);
> > SpiceMsgCursorSet cursor_set;
> > AddBufInfo info;
> > RedWorker *worker;
> > @@ -8013,7 +8097,7 @@ static void red_marshall_local_cursor(RedChannelClient *rcc,
> > cursor_set.position = cursor->position;
> > cursor_set.visible = worker->cursor_visible;
> >
> > - fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
> > + fill_cursor(ccc, &cursor_set.cursor, &cursor->base, &info);
> > spice_marshall_msg_cursor_set(base_marshaller, &cursor_set);
> > add_buf_from_info(base_marshaller, &info);
> > red_release_cursor(worker, (CursorItem *)cursor);
> > @@ -8033,6 +8117,7 @@ static void red_marshall_cursor(RedChannelClient *rcc,
> > SpiceMarshaller *m, CursorItem *cursor)
> > {
> > CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
> > + CursorChannelClient *ccc = RCC_TO_CCC(rcc);
> > RedCursorCmd *cmd;
> > RedWorker *worker;
> >
> > @@ -8059,7 +8144,7 @@ static void red_marshall_cursor(RedChannelClient *rcc,
> > cursor_set.position = cmd->u.set.position;
> > cursor_set.visible = worker->cursor_visible;
> >
> > - fill_cursor(cursor_channel, &cursor_set.cursor, cursor, &info);
> > + fill_cursor(ccc, &cursor_set.cursor, cursor, &info);
> > spice_marshall_msg_cursor_set(m, &cursor_set);
> > add_buf_from_info(m, &info);
> > break;
> > @@ -8086,10 +8171,9 @@ static void red_marshall_cursor(RedChannelClient *rcc,
> > static void red_marshall_surface_create(RedChannelClient *rcc,
> > SpiceMarshaller *base_marshaller, SpiceMsgSurfaceCreate *surface_create)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> >
> > - ASSERT(display_channel);
> > - region_init(&display_channel->surface_client_lossy_region[surface_create->surface_id]);
> > + region_init(&dcc->surface_client_lossy_region[surface_create->surface_id]);
> > red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL);
> >
> > spice_marshall_msg_display_surface_create(base_marshaller, surface_create);
> > @@ -8098,12 +8182,10 @@ static void red_marshall_surface_create(RedChannelClient *rcc,
> > static void red_marshall_surface_destroy(RedChannelClient *rcc,
> > SpiceMarshaller *base_marshaller, uint32_t surface_id)
> > {
> > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > SpiceMsgSurfaceDestroy surface_destroy;
> >
> > - ASSERT(display_channel);
> > -
> > - region_destroy(&display_channel->surface_client_lossy_region[surface_id]);
> > + region_destroy(&dcc->surface_client_lossy_region[surface_id]);
> > red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_DESTROY, NULL);
> >
> > surface_destroy.surface_id = surface_id;
> > @@ -8114,10 +8196,12 @@ static void red_marshall_surface_destroy(RedChannelClient *rcc,
> > static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
> > {
> > SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
> > - DisplayChannel *display_channel = (DisplayChannel *)red_ref_channel(rcc->channel);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > + DisplayChannel *display_channel = DCC_TO_DC(dcc);
> > RedWorker *worker = display_channel->common.worker;
> > + Surfaces *surfaces = dcc->common.surfaces;
> >
> > - red_display_reset_send_data(display_channel);
> > + red_display_reset_send_data(dcc);
> > switch (pipe_item->type) {
> > case PIPE_ITEM_TYPE_DRAW: {
> > Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
> > @@ -8132,19 +8216,19 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
> > case PIPE_ITEM_TYPE_STREAM_CREATE: {
> > StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, create_item);
> > red_display_marshall_stream_start(rcc, m, agent);
> > - red_display_release_stream(display_channel, agent);
> > + red_display_release_stream(surfaces, agent);
> > break;
> > }
> > case PIPE_ITEM_TYPE_STREAM_CLIP: {
> > StreamClipItem* clip_item = (StreamClipItem *)pipe_item;
> > red_display_marshall_stream_clip(rcc, m, clip_item);
> > - red_display_release_stream_clip(display_channel, clip_item);
> > + red_display_release_stream_clip(surfaces, clip_item);
> > break;
> > }
> > case PIPE_ITEM_TYPE_STREAM_DESTROY: {
> > StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, destroy_item);
> > red_display_marshall_stream_end(rcc, m, agent);
> > - red_display_release_stream(display_channel, agent);
> > + red_display_release_stream(surfaces, agent);
> > break;
> > }
> > case PIPE_ITEM_TYPE_UPGRADE:
> > @@ -8177,7 +8261,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
> > free(pipe_item);
> > break;
> > case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
> > - red_reset_palette_cache(display_channel);
> > + red_reset_palette_cache(dcc);
> > red_marshall_verb(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
> > free(pipe_item);
> > break;
> > @@ -8202,15 +8286,12 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
> > if (red_channel_client_send_message_pending(rcc)) {
> > display_begin_send_message(rcc, m);
> > }
> > - red_unref_channel(&display_channel->common.base);
> > }
> >
> > static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
> > {
> > SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
> > - CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
> >
> > - red_ref_channel(rcc->channel);
> > switch (pipe_item->type) {
> > case PIPE_ITEM_TYPE_CURSOR:
> > red_marshall_cursor(rcc, m, (CursorItem *)pipe_item);
> > @@ -8232,12 +8313,12 @@ static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
> > free(pipe_item);
> > break;
> > case PIPE_ITEM_TYPE_CURSOR_INIT:
> > - red_reset_cursor_cache(cursor_channel);
> > + red_reset_cursor_cache(rcc);
> > red_marshall_cursor_init(rcc, m);
> > free(pipe_item);
> > break;
> > case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
> > - red_reset_cursor_cache(cursor_channel);
> > + red_reset_cursor_cache(rcc);
> > red_marshall_verb(rcc, SPICE_MSG_CURSOR_INVAL_ALL);
> > free(pipe_item);
> > break;
> > @@ -8245,7 +8326,6 @@ static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
> > red_error("invalid pipe item type");
> > }
> > red_channel_client_begin_send_message(rcc);
> > - red_unref_channel(rcc->channel);
> > }
> >
> > static inline void red_push(RedWorker *worker)
> > @@ -8329,7 +8409,6 @@ void red_show_tree(RedWorker *worker)
> > static void red_disconnect_channel(RedChannel *channel)
> > {
> > red_channel_disconnect(channel);
> > - red_unref_channel(channel);
> > }
> >
> > static void init_surfaces(Surfaces *surfaces)
> > @@ -8338,10 +8417,11 @@ static void init_surfaces(Surfaces *surfaces)
> > image_surface_init(surfaces);
> > }
> >
> > -static void red_disconnect_display(RedChannelClient *rcc)
> > +static void display_channel_client_disconnect(RedChannelClient *rcc)
> > {
> > // TODO: MC: right now we assume single channel
> > DisplayChannel *display_channel;
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > CommonChannel *common;
> > RedWorker *worker;
> >
> > @@ -8355,32 +8435,38 @@ static void red_disconnect_display(RedChannelClient *rcc)
> > #ifdef COMPRESS_STAT
> > print_compress_stats(display_channel);
> > #endif
> > - worker->display_channel = NULL;
> > - red_display_unshare_stream_buf(display_channel);
> > - red_release_pixmap_cache(display_channel);
> > - red_release_glz(display_channel);
> > - red_reset_palette_cache(display_channel);
> > - free(display_channel->send_data.stream_outbuf);
> > - red_display_reset_compress_buf(display_channel);
> > - while (display_channel->send_data.free_compress_bufs) {
> > - RedCompressBuf *buf = display_channel->send_data.free_compress_bufs;
> > - display_channel->send_data.free_compress_bufs = buf->next;
> > + red_release_pixmap_cache(dcc);
> > + red_release_glz(dcc);
> > + red_reset_palette_cache(dcc);
> > + free(dcc->send_data.stream_outbuf);
> > + red_display_reset_compress_buf(dcc);
> > + while (dcc->send_data.free_compress_bufs) {
> > + RedCompressBuf *buf = dcc->send_data.free_compress_bufs;
> > + dcc->send_data.free_compress_bufs = buf->next;
> > free(buf);
> > }
> > - free(display_channel->send_data.free_list.res);
> > - red_display_destroy_streams(display_channel);
> > - red_disconnect_channel(rcc->channel);
> > + free(dcc->send_data.free_list.res);
> > + red_display_destroy_streams(dcc);
> > + red_channel_client_pipe_clear(rcc); // do this before deleting surfaces
> > + worker->surfaces.dcc = NULL;
>
> Can you add a comment to explain where dcc is being freed?
>
I don't think it is. I mean, it should be released by
red_channel_client_destroy(&dcc->common.base), I'll need to find where that is
called / where that should be called.
> > + red_channel_client_disconnect(rcc);
> > }
> >
> > void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
> > {
> > + DisplayChannel *display_channel;
> > + RedWorker *worker;
> > // TODO: we need to record the client that actually causes the timeout. So
> > // we need to check the locations of the various pipe heads when counting,
> > // and disconnect only those/that.
> > if (!channel) {
> > return;
> > }
> > - red_channel_apply_clients(channel, red_disconnect_display);
> > + display_channel = SPICE_CONTAINEROF(channel, DisplayChannel, common.base);
> > + worker = display_channel->common.worker;
> > + red_channel_apply_clients(channel, display_channel_client_disconnect);
> > + worker->display_channel = NULL;
>
> Same here, where is display_channel being freed?
>
will check.
> > + red_display_unshare_stream_buf(display_channel);
> > }
> >
> > static void red_migrate_display(RedWorker *worker)
> > @@ -8500,33 +8586,31 @@ static SurfaceCreateItem *get_surface_create_item(
> > return create;
> > }
> >
> > -static inline void __red_create_surface_item(RedWorker *worker, int surface_id, uint32_t flags)
> > +static inline void __red_create_surface_item(RedWorker *worker,
> > + DisplayChannelClient *dcc, int surface_id, uint32_t flags)
> > {
> > RedSurface *surface;
> > SurfaceCreateItem *create;
> > + Surfaces *surfaces = dcc ? dcc->common.surfaces : NULL;
> >
> > - if (!display_connected(worker)) {
> > + if (!dcc) {
> > return;
> > }
> > -
> > - surface = &worker->surfaces.surfaces[surface_id];
> > -
> > - create = get_surface_create_item(&worker->display_channel->common.base,
> > + surface = &surfaces->surfaces[surface_id];
> > + create = get_surface_create_item(dcc->common.base.channel,
> > surface_id, surface->context.width, surface->context.height,
> > surface->context.format, flags);
> > -
> > - worker->display_channel->surface_client_created[surface_id] = TRUE;
> > -
> > - red_channel_client_pipe_add(worker->display_channel->common.base.rcc, &create->pipe_item);
> > + dcc->surface_client_created[surface_id] = TRUE;
> > + red_channel_client_pipe_add(&dcc->common.base, &create->pipe_item);
> > }
> >
> > -static inline void red_create_surface_item(RedWorker *worker, int surface_id)
> > +static inline void red_create_surface_item(RedWorker *worker,
> > + DisplayChannelClient *dcc, int surface_id)
> > {
> > - if (is_primary_surface(surface_id)) {
> > - __red_create_surface_item(worker, surface_id, SPICE_SURFACE_FLAGS_PRIMARY);
> > - } else {
> > - __red_create_surface_item(worker, surface_id, 0);
> > - }
> > + int is_primary = is_primary_surface(surface_id);
> > +
> > + __red_create_surface_item(worker, dcc, surface_id,
> > + is_primary ? SPICE_SURFACE_FLAGS_PRIMARY : 0);
> > }
> > static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
> > @@ -8536,6 +8620,8 @@ static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
> > {
> > uint32_t i;
> > RedSurface *surface = &surfaces->surfaces[surface_id];
> > + DisplayChannelClient *dcc = surfaces->dcc;
> > +
> > if (stride >= 0) {
> > PANIC("Untested path stride >= 0");
> > }
> > @@ -8566,7 +8652,7 @@ static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
> > PANIC("drawing canvas creating failed - can`t create same type canvas");
> > }
> >
> > - red_create_surface_item(worker, surface_id);
> > + red_create_surface_item(worker, dcc, surface_id);
> > return;
> > }
> >
> > @@ -8577,7 +8663,7 @@ static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
> > surface->context.format, line_0);
> > if (surface->context.canvas) { //no need canvas check
> > worker->renderer = worker->renderers[i];
> > - red_create_surface_item(worker, surface_id);
> > + red_create_surface_item(worker, dcc, surface_id);
> > return;
> > }
> > }
> > @@ -8585,7 +8671,8 @@ static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
> > PANIC("unable to create drawing canvas");
> > }
> >
> > -static void red_wait_outgoing_item(RedChannel *channel);
> > +static void red_wait_outgoing_item(RedChannelClient *rcc);
> > +static void red_wait_outgoing_items(RedChannel *channel);
> >
> > static inline void flush_display_commands(RedWorker *worker)
> > {
> > @@ -8614,7 +8701,6 @@ static inline void flush_display_commands(RedWorker *worker)
> > break;
> > }
> > RedChannel *channel = (RedChannel *)worker->display_channel;
> > - red_ref_channel(channel);
> > red_channel_receive(channel);
> > red_channel_send(channel);
> > // TODO: MC: the whole timeout will break since it takes lowest timeout, should
> > @@ -8626,7 +8712,6 @@ static inline void flush_display_commands(RedWorker *worker)
> > sleep_count++;
> > usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
> > }
> > - red_unref_channel(channel);
> > }
> > }
> > }
> > @@ -8658,7 +8743,6 @@ static inline void flush_cursor_commands(RedWorker *worker)
> > break;
> > }
> > RedChannel *channel = (RedChannel *)worker->cursor_channel;
> > - red_ref_channel(channel);
> > red_channel_receive(channel);
> > red_channel_send(channel);
> > if (red_now() >= end_time) {
> > @@ -8668,7 +8752,6 @@ static inline void flush_cursor_commands(RedWorker *worker)
> > sleep_count++;
> > usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
> > }
> > - red_unref_channel(channel);
> > }
> > }
> > }
> > @@ -8679,41 +8762,43 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
> > flush_cursor_commands(worker);
> > }
> >
> > -static void push_new_primary_surface(RedWorker *worker)
> > +static void push_new_primary_surface(DisplayChannelClient *dcc)
> > {
> > - DisplayChannel *display_channel;
> > + RedWorker *worker = DCC_TO_WORKER(dcc);
> > + RedChannelClient *rcc = &dcc->common.base;
> >
> > - if ((display_channel = worker->display_channel)) {
> > - red_channel_client_pipe_add_type(display_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> > - if (!display_channel->common.base.migrate) {
> > - red_create_surface_item(worker, 0);
> > - }
> > - red_channel_push(&worker->display_channel->common.base);
> > + red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> > + if (!worker->display_channel->common.base.migrate) {
> > + red_create_surface_item(worker, dcc, 0);
> > }
> > + red_channel_client_push(rcc);
> > }
> >
> > -static int display_channel_wait_for_init(DisplayChannel *display_channel)
> > +/* TODO: this function is evil^Wsynchronous, fix */
> > +static int display_channel_wait_for_init(DisplayChannelClient *dcc)
> > {
> > - display_channel->expect_init = TRUE;
> > + DisplayChannel *display_channel = DCC_TO_DC(dcc);
> > +
> > + dcc->expect_init = TRUE;
> > uint64_t end_time = red_now() + DISPLAY_CLIENT_TIMEOUT;
> > for (;;) {
> > red_channel_receive((RedChannel *)display_channel);
> > if (!red_channel_is_connected(&display_channel->common.base)) {
> > break;
> > }
> > - if (display_channel->pixmap_cache && display_channel->glz_dict) {
> > - display_channel->pixmap_cache_generation = display_channel->pixmap_cache->generation;
> > - display_channel->glz = glz_encoder_create(display_channel->common.id,
> > - display_channel->glz_dict->dict,
> > - &display_channel->glz_data.usr);
> > - if (!display_channel->glz) {
> > + if (dcc->pixmap_cache && dcc->glz_dict) {
> > + dcc->pixmap_cache_generation = dcc->pixmap_cache->generation;
> > + /* TODO: move common.id? if it's used for a per client structure.. */
> > + red_printf("creating encoder with id == %d", dcc->common.id);
> > + dcc->glz = glz_encoder_create(dcc->common.id, dcc->glz_dict->dict, &dcc->glz_data.usr);
> > + if (!dcc->glz) {
> > PANIC("create global lz failed");
> > }
> > return TRUE;
> > }
> > if (red_now() > end_time) {
> > red_printf("timeout");
> > - red_disconnect_all_display_TODO_remove_me((RedChannel *)display_channel);
> > + display_channel_client_disconnect(&dcc->common.base);
> > break;
> > }
> > usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
> > @@ -8721,10 +8806,12 @@ static int display_channel_wait_for_init(DisplayChannel *display_channel)
> > return FALSE;
> > }
> >
> > -static void on_new_display_channel(RedWorker *worker)
> > +static void on_new_display_channel_client(DisplayChannelClient *dcc)
> > {
> > - DisplayChannel *display_channel = worker->display_channel;
> > - ASSERT(display_channel);
> > + DisplayChannel *display_channel = DCC_TO_DC(dcc);
> > + RedWorker *worker = display_channel->common.worker;
> > + Surfaces *surfaces = dcc->common.surfaces;
> > + RedChannelClient *rcc = &dcc->common.base;
> >
> > red_channel_push_set_ack(&display_channel->common.base);
> >
> > @@ -8733,17 +8820,17 @@ static void on_new_display_channel(RedWorker *worker)
> > return;
> > }
> >
> > - if (!display_channel_wait_for_init(display_channel)) {
> > + if (!display_channel_wait_for_init(dcc)) {
> > return;
> > }
> > - red_channel_ack_zero_messages_window(&display_channel->common.base);
> > - if (worker->surfaces.surfaces[0].context.canvas) {
> > - red_current_flush(worker, &worker->surfaces, 0);
> > - push_new_primary_surface(worker);
> > + red_channel_client_ack_zero_messages_window(&dcc->common.base);
> > + if (surfaces->surfaces[0].context.canvas) {
> > + red_current_flush(worker, surfaces, 0);
> > + push_new_primary_surface(dcc);
> > red_add_surface_image(worker, 0);
> > if (red_channel_is_connected(&display_channel->common.base)) {
> > - red_pipe_add_verb(display_channel->common.base.rcc, SPICE_MSG_DISPLAY_MARK);
> > - red_disply_start_streams(display_channel);
> > + red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK);
> > + red_disply_start_streams(dcc);
> > }
> > }
> > }
> > @@ -8765,11 +8852,11 @@ static GlzSharedDictionary *_red_find_glz_dictionary(uint8_t dict_id)
> > return ret;
> > }
> >
> > -static GlzSharedDictionary *_red_create_glz_dictionary(DisplayChannel *display,
> > - uint8_t id,
> > +static GlzSharedDictionary *_red_create_glz_dictionary(uint8_t id,
> > GlzEncDictContext *opaque_dict)
> > {
> > GlzSharedDictionary *shared_dict = spice_new0(GlzSharedDictionary, 1);
> > +
> > shared_dict->dict = opaque_dict;
> > shared_dict->id = id;
> > shared_dict->refs = 1;
> > @@ -8779,12 +8866,12 @@ static GlzSharedDictionary *_red_create_glz_dictionary(DisplayChannel *display,
> > return shared_dict;
> > }
> >
> > -static GlzSharedDictionary *red_create_glz_dictionary(DisplayChannel *display,
> > +static GlzSharedDictionary *red_create_glz_dictionary(DisplayChannelClient *dcc,
> > uint8_t id, int window_size)
> > {
> > GlzEncDictContext *glz_dict = glz_enc_dictionary_create(window_size,
> > MAX_LZ_ENCODERS,
> > - &display->glz_data.usr);
> > + &dcc->glz_data.usr);
> > #ifdef COMPRESS_DEBUG
> > red_printf("Lz Window %d Size=%d", id, window_size);
> > #endif
> > @@ -8792,23 +8879,23 @@ static GlzSharedDictionary *red_create_glz_dictionary(DisplayChannel *display,
> > PANIC("failed creating lz dictionary");
> > return NULL;
> > }
> > - return _red_create_glz_dictionary(display, id, glz_dict);
> > + return _red_create_glz_dictionary(id, glz_dict);
> > }
> >
> > -static GlzSharedDictionary *red_create_restored_glz_dictionary(DisplayChannel *display,
> > +static GlzSharedDictionary *red_create_restored_glz_dictionary(DisplayChannelClient *dcc,
> > uint8_t id,
> > GlzEncDictRestoreData *restore_data)
> > {
> > GlzEncDictContext *glz_dict = glz_enc_dictionary_restore(restore_data,
> > - &display->glz_data.usr);
> > + &dcc->glz_data.usr);
> > if (!glz_dict) {
> > PANIC("failed creating lz dictionary");
> > return NULL;
> > }
> > - return _red_create_glz_dictionary(display, id, glz_dict);
> > + return _red_create_glz_dictionary(id, glz_dict);
> > }
> >
> > -static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannel *display,
> > +static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannelClient *dcc,
> > uint8_t id, int window_size)
> > {
> > GlzSharedDictionary *shared_dict = NULL;
> > @@ -8818,7 +8905,7 @@ static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannel *display,
> > shared_dict = _red_find_glz_dictionary(id);
> >
> > if (!shared_dict) {
> > - shared_dict = red_create_glz_dictionary(display, id, window_size);
> > + shared_dict = red_create_glz_dictionary(dcc, id, window_size);
> > ring_add(&glz_dictionary_list, &shared_dict->base);
> > } else {
> > shared_dict->refs++;
> > @@ -8827,7 +8914,7 @@ static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannel *display,
> > return shared_dict;
> > }
> >
> > -static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannel *display,
> > +static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannelClient *dcc,
> > uint8_t id,
> > GlzEncDictRestoreData *restore_data)
> > {
> > @@ -8838,7 +8925,7 @@ static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannel *display,
> > shared_dict = _red_find_glz_dictionary(id);
> >
> > if (!shared_dict) {
> > - shared_dict = red_create_restored_glz_dictionary(display, id, restore_data);
> > + shared_dict = red_create_restored_glz_dictionary(dcc, id, restore_data);
> > ring_add(&glz_dictionary_list, &shared_dict->base);
> > } else {
> > shared_dict->refs++;
> > @@ -8847,30 +8934,30 @@ static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannel *display,
> > return shared_dict;
> > }
> >
> > -static void red_freeze_glz(DisplayChannel *channel)
> > +static void red_freeze_glz(DisplayChannelClient *dcc)
> > {
> > - pthread_rwlock_wrlock(&channel->glz_dict->encode_lock);
> > - if (!channel->glz_dict->migrate_freeze) {
> > - channel->glz_dict->migrate_freeze = TRUE;
> > + pthread_rwlock_wrlock(&dcc->glz_dict->encode_lock);
> > + if (!dcc->glz_dict->migrate_freeze) {
> > + dcc->glz_dict->migrate_freeze = TRUE;
> > }
> > - pthread_rwlock_unlock(&channel->glz_dict->encode_lock);
> > + pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
> > }
> >
> > /* destroy encoder, and dictionary if no one uses it*/
> > -static void red_release_glz(DisplayChannel *channel)
> > +static void red_release_glz(DisplayChannelClient *dcc)
> > {
> > GlzSharedDictionary *shared_dict;
> >
> > - red_display_clear_glz_drawables(channel);
> > + red_display_client_clear_glz_drawables(dcc);
> >
> > - glz_encoder_destroy(channel->glz);
> > - channel->glz = NULL;
> > + glz_encoder_destroy(dcc->glz);
> > + dcc->glz = NULL;
> >
> > - if (!(shared_dict = channel->glz_dict)) {
> > + if (!(shared_dict = dcc->glz_dict)) {
> > return;
> > }
> >
> > - channel->glz_dict = NULL;
> > + dcc->glz_dict = NULL;
> > pthread_mutex_lock(&cache_lock);
> > if (--shared_dict->refs) {
> > pthread_mutex_unlock(&cache_lock);
> > @@ -8878,7 +8965,7 @@ static void red_release_glz(DisplayChannel *channel)
> > }
> > ring_remove(&shared_dict->base);
> > pthread_mutex_unlock(&cache_lock);
> > - glz_enc_dictionary_destroy(shared_dict->dict, &channel->glz_data.usr);
> > + glz_enc_dictionary_destroy(shared_dict->dict, &dcc->glz_data.usr);
> > free(shared_dict);
> > }
> >
> > @@ -8917,13 +9004,13 @@ static PixmapCache *red_get_pixmap_cache(uint8_t id, int64_t size)
> > return cache;
> > }
> >
> > -static void red_release_pixmap_cache(DisplayChannel *channel)
> > +static void red_release_pixmap_cache(DisplayChannelClient *dcc)
> > {
> > PixmapCache *cache;
> > - if (!(cache = channel->pixmap_cache)) {
> > + if (!(cache = dcc->pixmap_cache)) {
> > return;
> > }
> > - channel->pixmap_cache = NULL;
> > + dcc->pixmap_cache = NULL;
> > pthread_mutex_lock(&cache_lock);
> > if (--cache->refs) {
> > pthread_mutex_unlock(&cache_lock);
> > @@ -8935,56 +9022,58 @@ static void red_release_pixmap_cache(DisplayChannel *channel)
> > free(cache);
> > }
> >
> > -static int display_channel_init_cache(DisplayChannel *channel, SpiceMsgcDisplayInit *init_info)
> > +static int display_channel_init_cache(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init_info)
> > {
> > - ASSERT(!channel->pixmap_cache);
> > - return !!(channel->pixmap_cache = red_get_pixmap_cache(init_info->pixmap_cache_id,
> > - init_info->pixmap_cache_size));
> > + ASSERT(!dcc->pixmap_cache);
> > + return !!(dcc->pixmap_cache = red_get_pixmap_cache(init_info->pixmap_cache_id,
> > + init_info->pixmap_cache_size));
> > }
> >
> > -static int display_channel_init_glz_dictionary(DisplayChannel *channel, SpiceMsgcDisplayInit *init_info)
> > +static int display_channel_init_glz_dictionary(DisplayChannelClient *dcc,
> > + SpiceMsgcDisplayInit *init_info)
> > {
> > - ASSERT(!channel->glz_dict);
> > - ring_init(&channel->glz_drawables);
> > - ring_init(&channel->glz_drawables_inst_to_free);
> > - pthread_mutex_init(&channel->glz_drawables_inst_to_free_lock, NULL);
> > - return !!(channel->glz_dict = red_get_glz_dictionary(channel,
> > - init_info->glz_dictionary_id,
> > - init_info->glz_dictionary_window_size));
> > + ASSERT(!dcc->glz_dict);
> > + ring_init(&dcc->glz_drawables);
> > + ring_init(&dcc->glz_drawables_inst_to_free);
> > + pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
> > + return !!(dcc->glz_dict = red_get_glz_dictionary(dcc,
> > + init_info->glz_dictionary_id,
> > + init_info->glz_dictionary_window_size));
> > }
> >
> > -static int display_channel_init(DisplayChannel *channel, SpiceMsgcDisplayInit *init_info)
> > +static int display_channel_init(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init_info)
> > {
> > - return (display_channel_init_cache(channel, init_info) &&
> > - display_channel_init_glz_dictionary(channel, init_info));
> > + return (display_channel_init_cache(dcc, init_info) &&
> > + display_channel_init_glz_dictionary(dcc, init_info));
> > }
> >
> > -static int display_channel_handle_migrate_glz_dictionary(DisplayChannel *channel,
> > +static int display_channel_handle_migrate_glz_dictionary(DisplayChannelClient *dcc,
> > DisplayChannelMigrateData *migrate_info)
> > {
> > - ASSERT(!channel->glz_dict);
> > - ring_init(&channel->glz_drawables);
> > - ring_init(&channel->glz_drawables_inst_to_free);
> > - pthread_mutex_init(&channel->glz_drawables_inst_to_free_lock, NULL);
> > - return !!(channel->glz_dict = red_restore_glz_dictionary(channel,
> > - migrate_info->glz_dict_id,
> > - &migrate_info->glz_dict_restore_data));
> > + ASSERT(!dcc->glz_dict);
> > + ring_init(&dcc->glz_drawables);
> > + ring_init(&dcc->glz_drawables_inst_to_free);
> > + pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
> > + return !!(dcc->glz_dict = red_restore_glz_dictionary(dcc,
> > + migrate_info->glz_dict_id,
> > + &migrate_info->glz_dict_restore_data));
> > }
> >
> > static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
> > {
> > - DisplayChannel *channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + RedChannel *channel = &display_channel->common.base;
> >
> > - if (!channel->expect_migrate_mark) {
> > + if (!display_channel->expect_migrate_mark) {
> > red_printf("unexpected");
> > return FALSE;
> > }
> > - channel->expect_migrate_mark = FALSE;
> > - red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_MIGRATE_DATA);
> > + display_channel->expect_migrate_mark = FALSE;
> > + red_channel_pipes_add_type(channel, PIPE_ITEM_TYPE_MIGRATE_DATA);
> > return TRUE;
> > }
> >
> > -static uint64_t display_channel_handle_migrate_data_get_serial_proc(
> > +static uint64_t display_channel_handle_migrate_data_get_serial(
> > RedChannelClient *rcc, uint32_t size, void *message)
> > {
> > DisplayChannelMigrateData *migrate_data = message;
> > @@ -9004,8 +9093,10 @@ static uint64_t display_channel_handle_migrate_data_get_serial_proc(
> > static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
> > {
> > DisplayChannelMigrateData *migrate_data;
> > + DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > + RedChannel *channel = &display_channel->common.base;
> > int i;
> > - DisplayChannel *channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
> >
> > if (size < sizeof(*migrate_data)) {
> > red_printf("bad message size");
> > @@ -9017,51 +9108,54 @@ static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint3
> > red_printf("invalid content");
> > return FALSE;
> > }
> > - if (!channel->expect_migrate_data) {
> > + if (!display_channel->expect_migrate_data) {
> > red_printf("unexpected");
> > return FALSE;
> > }
> > - channel->expect_migrate_data = FALSE;
> > - if (!(channel->pixmap_cache = red_get_pixmap_cache(migrate_data->pixmap_cache_id, -1))) {
> > + display_channel->expect_migrate_data = FALSE;
> > + if (!(dcc->pixmap_cache = red_get_pixmap_cache(migrate_data->pixmap_cache_id, -1))) {
> > return FALSE;
> > }
> > - pthread_mutex_lock(&channel->pixmap_cache->lock);
> > + pthread_mutex_lock(&dcc->pixmap_cache->lock);
> > for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
> > - channel->pixmap_cache->sync[i] = MAX(channel->pixmap_cache->sync[i],
> > - migrate_data->pixmap_cache_clients[i]);
> > + dcc->pixmap_cache->sync[i] = MAX(dcc->pixmap_cache->sync[i],
> > + migrate_data->pixmap_cache_clients[i]);
> > }
> > - pthread_mutex_unlock(&channel->pixmap_cache->lock);
> > + pthread_mutex_unlock(&dcc->pixmap_cache->lock);
> >
> > if (migrate_data->pixmap_cache_freezer) {
> > - channel->pixmap_cache->size = migrate_data->pixmap_cache_size;
> > - red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_PIXMAP_RESET);
> > + dcc->pixmap_cache->size = migrate_data->pixmap_cache_size;
> > + // TODO - should this be red_channel_client_pipe_add_type?
> > + red_channel_pipes_add_type(channel,
> > + PIPE_ITEM_TYPE_PIXMAP_RESET);
> > }
> >
> > - if (display_channel_handle_migrate_glz_dictionary(channel, migrate_data)) {
> > - channel->glz = glz_encoder_create(channel->common.id,
> > - channel->glz_dict->dict, &channel->glz_data.usr);
> > - if (!channel->glz) {
> > + if (display_channel_handle_migrate_glz_dictionary(dcc, migrate_data)) {
> > + dcc->glz = glz_encoder_create(dcc->common.id,
> > + dcc->glz_dict->dict, &dcc->glz_data.usr);
> > + if (!dcc->glz) {
> > PANIC("create global lz failed");
> > }
> > } else {
> > PANIC("restoring global lz dictionary failed");
> > }
> >
> > - red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> > - red_channel_ack_zero_messages_window(&channel->common.base);
> > + red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> > + red_channel_client_ack_zero_messages_window(rcc);
> > return TRUE;
> > }
> >
> > static int display_channel_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
> > {
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > switch (type) {
> > case SPICE_MSGC_DISPLAY_INIT:
> > - if (!((DisplayChannel *)rcc->channel)->expect_init) {
> > + if (!dcc->expect_init) {
> > red_printf("unexpected SPICE_MSGC_DISPLAY_INIT");
> > return FALSE;
> > }
> > - ((DisplayChannel *)rcc->channel)->expect_init = FALSE;
> > - return display_channel_init((DisplayChannel *)rcc->channel, (SpiceMsgcDisplayInit *)message);
> > + dcc->expect_init = FALSE;
> > + return display_channel_init(dcc, (SpiceMsgcDisplayInit *)message);
> > default:
> > return red_channel_client_handle_message(rcc, size, type, message);
> > }
> > @@ -9093,23 +9187,24 @@ int common_channel_config_socket(RedChannelClient *rcc)
> > return TRUE;
> > }
> >
> > -static void free_common_channel_from_listener(EventListener *ctx)
> > +static void free_common_cc_from_listener(EventListener *ctx)
> > {
> > - CommonChannel* common = SPICE_CONTAINEROF(ctx, CommonChannel, listener);
> > + CommonChannelClient* common_cc = SPICE_CONTAINEROF(ctx, CommonChannelClient, listener);
> >
> > - free(common);
> > + red_printf("");
> > + free(common_cc);
> > }
> >
> > -void worker_watch_update_mask(SpiceWatch *watch, int event_mask)
> > +static void worker_watch_update_mask(SpiceWatch *watch, int event_mask)
> > {
> > }
> >
> > -SpiceWatch *worker_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
> > +static SpiceWatch *worker_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
> > {
> > return NULL; // apparently allowed?
> > }
> >
> > -void worker_watch_remove(SpiceWatch *watch)
> > +static void worker_watch_remove(SpiceWatch *watch)
> > {
> > }
> >
> > @@ -9119,8 +9214,74 @@ SpiceCoreInterface worker_core = {
> > .watch_remove = worker_watch_remove,
> > };
> >
> > -static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
> > - RedClient *client, RedsStream *stream, int migrate,
> > +static CommonChannelClient *common_channel_client_create(int size,
> > + CommonChannel *common, RedClient *client, RedsStream *stream)
> > +{
> > + MainChannelClient *mcc = red_client_get_main(client);
> > + RedChannelClient *rcc =
> > + red_channel_client_create(size, &common->base, client, stream);
> > + CommonChannelClient *common_cc = (CommonChannelClient*)rcc;
> > +
> > + // TODO: Should this be distinctive for the Display/Cursor channels? doesn't
> > + // make sense, does it?
> > + red_channel_client_ack_set_client_window(rcc,
> > + main_channel_client_is_low_bandwidth(mcc) ?
> > + WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW);
> > + return common_cc;
> > +}
> > +
> > +
> > +DisplayChannelClient *display_channel_client_create(CommonChannel *common,
> > + RedClient *client, RedsStream *stream)
> > +{
> > + DisplayChannelClient *dcc =
> > + (DisplayChannelClient*)common_channel_client_create(
> > + sizeof(DisplayChannelClient), common, client, stream);
> > +
> > + if (!dcc) {
> > + return NULL;
> > + }
> > + ring_init(&dcc->palette_cache_lru);
> > + dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
> > + return dcc;
> > +}
> > +
> > +CursorChannelClient *cursor_channel_create_rcc(CommonChannel *common,
> > + RedClient *client, RedsStream *stream)
> > +{
> > + CursorChannelClient *ccc =
> > + (CursorChannelClient*)common_channel_client_create(
> > + sizeof(CursorChannelClient), common, client, stream);
> > +
> > + if (!ccc) {
> > + return NULL;
> > + }
> > + ring_init(&ccc->cursor_cache_lru);
> > + ccc->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE;
> > + return ccc;
> > +}
> > +
> > +static int listen_to_new_client_channel(CommonChannel *common,
> > + CommonChannelClient *common_cc, RedsStream *stream)
> > +{
>
> This is just an example, but from what I can see, we could just take
> CommonChannelClient as an argument, and access the rest from it.
>
> It's easier to require the least amount of arguments, imho, and it
> seems there is a lot if not hundreds of function which could benefit
> this simplification as well. That would also help to put more correct
> prefixes and function names.
>
> listen_to_new_client_channel() -> common_channel_client_listen()
>
Yeah, I've taken that to heart, is it working wonders but is taking some time
to do all the fixes. RedRender in particular got a worker variable (despite my
pointing out it can be inferred), and I'll do the same any place I can. Ditto
about the correct prefix, and last about dropping usage of __ prefix.
> > + struct epoll_event event;
> > +
> > + common_cc->listener.refs = 1;
> > + common_cc->listener.action = common->listener_action;
> > + common_cc->listener.free = free_common_cc_from_listener;
> > + ASSERT(common->base.clients_num);
> > + common_cc->id = common->worker->id;
> > + red_printf("NEW ID = %d", common_cc->id);
> > + event.events = EPOLLIN | EPOLLOUT | EPOLLET;
> > + event.data.ptr = &common_cc->listener;
> > + if (epoll_ctl(common->worker->epoll, EPOLL_CTL_ADD, stream->socket, &event) == -1) {
> > + red_printf("epoll_ctl failed, %s", strerror(errno));
> > + return FALSE;
> > + }
> > + return TRUE;
> > +}
> > +
> > +static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id, int migrate,
> > event_listener_action_proc handler,
> > channel_disconnect_proc disconnect,
> > channel_send_pipe_item_proc send_item,
> > @@ -9133,10 +9294,8 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
> > channel_handle_migrate_data_proc handle_migrate_data,
> > channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial)
> > {
> > - struct epoll_event event;
> > - RedChannel *channel;
> > + RedChannel *channel = NULL;
> > CommonChannel *common;
> > - MainChannelClient *mcc = red_client_get_main(client);
> >
> > channel = red_channel_create_parser(size, &worker_core, migrate,
> > TRUE /* handle_acks */,
> > @@ -9158,45 +9317,26 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
> > if (!channel) {
> > goto error;
> > }
> > - red_channel_client_create(sizeof(RedChannelClient), channel, client, stream);
> > - common->id = worker->id;
> > - common->listener.refs = 1;
> > - common->listener.action = handler;
> > - common->listener.free = free_common_channel_from_listener;
> > common->worker = worker;
> > - // TODO: Should this be distinctive for the Display/Cursor channels? doesn't
> > - // make sense, does it?
> > - red_channel_ack_set_client_window(channel,
> > - main_channel_client_is_low_bandwidth(mcc) ?
> > - WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW);
> > -
> > - event.events = EPOLLIN | EPOLLOUT | EPOLLET;
> > - event.data.ptr = &common->listener;
> > - if (epoll_ctl(worker->epoll, EPOLL_CTL_ADD, stream->socket, &event) == -1) {
> > - red_printf("epoll_ctl failed, %s", strerror(errno));
> > - goto error;
> > - }
> > -
> > + common->listener_action = handler;
> > return channel;
> >
> > error:
> > free(channel);
> > - reds_stream_free(stream);
> > -
> > return NULL;
> > }
> >
> > static void handle_channel_events(EventListener *in_listener, uint32_t events)
> > {
> > - CommonChannel *common = SPICE_CONTAINEROF(in_listener, CommonChannel, listener);
> > - RedChannel *channel = &common->base;
> > + CommonChannelClient *common_cc = SPICE_CONTAINEROF(in_listener, CommonChannelClient, listener);
> > + RedChannelClient *rcc = &common_cc->base;
> >
> > - if ((events & EPOLLIN)) {
> > - red_channel_receive(channel);
> > + if ((events & EPOLLIN) && red_channel_client_is_connected(rcc)) {
> > + red_channel_client_receive(rcc);
> > }
> >
> > - if (red_channel_any_blocked(channel)) {
> > - red_channel_send(channel);
> > + if (rcc->send_data.blocked && red_channel_client_is_connected(rcc)) {
> > + red_channel_client_push(rcc);
> > }
> > }
> >
> > @@ -9222,11 +9362,14 @@ static void display_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item
> > }
> > }
> >
> > -static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed /* ignored */)
> > +static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
> > + int item_pushed /* ignored */)
> > {
> > RedChannel *channel = rcc->channel;
> > CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> > RedWorker *worker = common->worker;
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > + Surfaces *surfaces = dcc->common.surfaces;
> >
> > ASSERT(item);
> > switch (item->type) {
> > @@ -9236,7 +9379,7 @@ static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
> > SPICE_CONTAINEROF(item, Drawable, pipe_item));
> > break;
> > case PIPE_ITEM_TYPE_STREAM_CLIP:
> > - red_display_release_stream_clip((DisplayChannel *)channel, (StreamClipItem *)item);
> > + red_display_release_stream_clip(surfaces, (StreamClipItem *)item);
> > break;
> > case PIPE_ITEM_TYPE_UPGRADE:
> > release_upgrade_item(worker, &worker->surfaces, (UpgradeItem *)item);
> > @@ -9296,19 +9439,19 @@ static void dispatch_cursor_channel_client_disconnect(RedChannelClient *rcc)
> > red_dispatcher_disconnect_cursor_client(dispatcher, rcc);
> > }
> >
> > -static void handle_new_display_channel(RedWorker *worker, RedClient *client, RedsStream *stream,
> > - int migrate)
> > +static void ensure_display_channel_created(RedWorker *worker, int migrate)
> > {
> > DisplayChannel *display_channel;
> > - size_t stream_buf_size;
> > - int is_low_bandwidth = main_channel_client_is_low_bandwidth(red_client_get_main(client));
> >
> > - red_disconnect_all_display_TODO_remove_me((RedChannel *)worker->display_channel);
> > + if (worker->display_channel) {
> > + return;
> > + }
> >
> > - if (!(display_channel = (DisplayChannel *)__new_channel(
> > + red_printf("create display channel");
> > + if (!(worker->display_channel = (DisplayChannel *)__new_channel(
> > worker, sizeof(*display_channel),
> > - SPICE_CHANNEL_DISPLAY, client, stream,
> > - migrate, handle_channel_events,
> > + SPICE_CHANNEL_DISPLAY, migrate,
> > + handle_channel_events,
> > dispatch_display_channel_client_disconnect,
> > display_channel_send_item,
> > display_channel_hold_pipe_item,
> > @@ -9318,9 +9461,11 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
> > display_channel_on_outgoing_error,
> > display_channel_handle_migrate_mark,
> > display_channel_handle_migrate_data,
> > - display_channel_handle_migrate_data_get_serial_proc))) {
> > + display_channel_handle_migrate_data_get_serial
> > + ))) {
> > return;
> > }
> > + display_channel = worker->display_channel;
> > #ifdef RED_STATISTICS
> > display_channel->stat = stat_add_node(worker->stat, "display_channel", TRUE);
> > display_channel->common.base.out_bytes_counter = stat_add_counter(display_channel->stat,
> > @@ -9332,22 +9477,45 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
> > display_channel->non_cache_counter = stat_add_counter(display_channel->stat,
> > "non_cache", TRUE);
> > #endif
> > - ring_init(&display_channel->palette_cache_lru);
> > - display_channel->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
> > - red_display_init_streams(display_channel);
> > + stat_compress_init(&display_channel->lz_stat, lz_stat_name);
> > + stat_compress_init(&display_channel->glz_stat, glz_stat_name);
> > + stat_compress_init(&display_channel->quic_stat, quic_stat_name);
> > + stat_compress_init(&display_channel->jpeg_stat, jpeg_stat_name);
> > + stat_compress_init(&display_channel->zlib_glz_stat, zlib_stat_name);
> > + stat_compress_init(&display_channel->jpeg_alpha_stat, jpeg_alpha_stat_name);
> > +}
> > +
> > +
> > +static void handle_new_display_channel(RedWorker *worker, RedClient *client, RedsStream *stream,
> > + int migrate)
> > +{
> > + DisplayChannel *display_channel;
> > + DisplayChannelClient *dcc;
> > + size_t stream_buf_size;
> > + int is_low_bandwidth = main_channel_client_is_low_bandwidth(red_client_get_main(client));
> > +
> > + red_disconnect_all_display_TODO_remove_me((RedChannel *)worker->display_channel);
> > + ensure_display_channel_created(worker, migrate);
> > + if (!worker->display_channel) {
> > + return;
> > + }
> > + display_channel = worker->display_channel;
> > + red_printf("add display channel client");
> > + dcc = display_channel_client_create(&display_channel->common, client, stream);
> > + if (!dcc) {
> > + return;
> > + }
> >
> > stream_buf_size = 32*1024;
> > - display_channel->send_data.stream_outbuf = spice_malloc(stream_buf_size);
> > - display_channel->send_data.stream_outbuf_size = stream_buf_size;
> > + dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size);
> > + dcc->send_data.stream_outbuf_size = stream_buf_size;
> > red_display_share_stream_buf(display_channel);
> > - red_display_init_glz_data(display_channel);
> > - worker->display_channel = display_channel;
> > -
> > + red_display_init_glz_data(dcc);
> >
> > - display_channel->send_data.free_list.res =
> > + dcc->send_data.free_list.res =
> > spice_malloc(sizeof(SpiceResourceList) +
> > DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID));
> > - display_channel->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
> > + dcc->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
> >
> > if (worker->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
> > display_channel->enable_jpeg = is_low_bandwidth;
> > @@ -9370,17 +9538,17 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
> >
> > // todo: tune level according to bandwidth
> > display_channel->zlib_level = ZLIB_DEFAULT_COMPRESSION_LEVEL;
> > + if (!listen_to_new_client_channel(&display_channel->common, &dcc->common, stream)) {
> > + goto error;
> > + }
> > + dcc->common.surfaces = &worker->surfaces;
> > + dcc->common.surfaces->dcc = dcc;
> > + red_display_client_init_streams(dcc);
> > + on_new_display_channel_client(dcc);
> > + return;
> >
> > - red_ref_channel((RedChannel*)display_channel);
> > - on_new_display_channel(worker);
> > - red_unref_channel((RedChannel*)display_channel);
> > -
> > - stat_compress_init(&display_channel->lz_stat, lz_stat_name);
> > - stat_compress_init(&display_channel->glz_stat, glz_stat_name);
> > - stat_compress_init(&display_channel->quic_stat, quic_stat_name);
> > - stat_compress_init(&display_channel->jpeg_stat, jpeg_stat_name);
> > - stat_compress_init(&display_channel->zlib_glz_stat, zlib_stat_name);
> > - stat_compress_init(&display_channel->jpeg_alpha_stat, jpeg_alpha_stat_name);
> > +error:
> > + red_channel_client_destroy(&dcc->common.base);
> > }
> >
> > static void red_disconnect_cursor(RedChannel *channel)
> > @@ -9393,7 +9561,7 @@ static void red_disconnect_cursor(RedChannel *channel)
> > common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> > ASSERT(channel == (RedChannel *)common->worker->cursor_channel);
> > common->worker->cursor_channel = NULL;
> > - red_reset_cursor_cache((CursorChannel *)channel);
> > + red_channel_apply_clients(channel, red_reset_cursor_cache);
> > red_disconnect_channel(channel);
> > }
> >
> > @@ -9405,15 +9573,17 @@ static void red_migrate_cursor(RedWorker *worker)
> > }
> > }
> >
> > -static void on_new_cursor_channel(RedWorker *worker)
> > +static void on_new_cursor_channel(RedWorker *worker, RedChannelClient *rcc)
> > {
> > CursorChannel *channel = worker->cursor_channel;
> >
> > ASSERT(channel);
> > - red_channel_ack_zero_messages_window(&channel->common.base);
> > - red_channel_push_set_ack(&channel->common.base);
> > + red_channel_client_ack_zero_messages_window(rcc);
> > + red_channel_client_push_set_ack(rcc);
> > + // TODO: why do we check for context.canvas? defer this to after display cc is connected
> > + // and test it's canvas? this is just a test to see if there is an active renderer?
> > if (worker->surfaces.surfaces[0].context.canvas && !channel->common.base.migrate) {
> > - red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_CURSOR_INIT);
> > + red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_CURSOR_INIT);
> > }
> > }
> >
> > @@ -9437,37 +9607,53 @@ static void cursor_channel_release_item(RedChannelClient *rcc, PipeItem *item, i
> > }
> > }
> >
> > +static void ensure_cursor_channel_created(RedWorker *worker, int migrate)
> > +{
> > + if (worker->cursor_channel != NULL) {
> > + return;
> > + }
> > + red_printf("create cursor channel");
> > + worker->cursor_channel = (CursorChannel *)__new_channel(
> > + worker, sizeof(*worker->cursor_channel),
> > + SPICE_CHANNEL_CURSOR, migrate,
> > + handle_channel_events,
> > + dispatch_cursor_channel_client_disconnect,
> > + cursor_channel_send_item,
> > + cursor_channel_hold_pipe_item,
> > + cursor_channel_release_item,
> > + red_channel_client_handle_message,
> > + cursor_channel_on_incoming_error,
> > + cursor_channel_on_outgoing_error,
> > + NULL,
> > + NULL,
> > + NULL);
> > +}
> > +
> > +
> > static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream *stream,
> > int migrate)
> > {
> > CursorChannel *channel;
> > + CursorChannelClient *ccc;
> >
> > red_disconnect_cursor((RedChannel *)worker->cursor_channel);
> > -
> > - if (!(channel = (CursorChannel *)__new_channel(
> > - worker, sizeof(*channel),
> > - SPICE_CHANNEL_CURSOR, client, stream, migrate,
> > - handle_channel_events,
> > - dispatch_cursor_channel_client_disconnect,
> > - cursor_channel_send_item,
> > - cursor_channel_hold_pipe_item,
> > - cursor_channel_release_item,
> > - red_channel_client_handle_message,
> > - cursor_channel_on_incoming_error,
> > - cursor_channel_on_outgoing_error,
> > - NULL,
> > - NULL,
> > - NULL))) {
> > + ensure_cursor_channel_created(worker, migrate);
> > + if (worker->cursor_channel == NULL) {
> > + red_printf("failed to create cursor channel");
> > + return;
> > + }
> > + channel = worker->cursor_channel;
> > + red_printf("add cursor channel client");
> > + ccc = cursor_channel_create_rcc(&channel->common, client, stream);
> > + if (!ccc) {
> > return;
> > }
> > #ifdef RED_STATISTICS
> > channel->stat = stat_add_node(worker->stat, "cursor_channel", TRUE);
> > channel->common.base.out_bytes_counter = stat_add_counter(channel->stat, "out_bytes", TRUE);
> > #endif
> > - ring_init(&channel->cursor_cache_lru);
> > - channel->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE;
> > - worker->cursor_channel = channel;
> > - on_new_cursor_channel(worker);
> > + listen_to_new_client_channel(&channel->common, &ccc->common, stream);
> > + on_new_cursor_channel(worker, &ccc->common.base);
> > }
> >
> > typedef struct __attribute__ ((__packed__)) CursorData {
> > @@ -9528,16 +9714,47 @@ static void red_cursor_flush(RedWorker *worker)
> > red_release_cursor(worker, &local->base);
> > }
> >
> > -static void red_wait_outgoing_item(RedChannel *channel)
> > +static void red_wait_outgoing_item(RedChannelClient *rcc)
> > {
> > uint64_t end_time;
> > int blocked;
> >
> > - if (!channel || !red_channel_all_blocked(channel)) {
> > + if (!red_channel_client_blocked(rcc)) {
> > return;
> > }
> > - red_ref_channel(channel);
> > + end_time = red_now() + DETACH_TIMEOUT;
> > + red_printf("blocked");
> > +
> > + do {
> > + usleep(DETACH_SLEEP_DURATION);
> > + red_channel_client_receive(rcc);
> > + red_channel_client_send(rcc);
> > + } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time);
> > +
> > + if (blocked) {
> > + red_printf("timeout");
> > + // TODO - shutting down the socket but we still need to trigger
> > + // disconnection. Right now we wait for main channel to error for that.
> > + red_channel_client_shutdown(rcc);
> > + }
> > +}
> > +
> > +static void rcc_shutdown_if_blocked(RedChannelClient *rcc)
> > +{
> > + if (red_channel_client_blocked(rcc)) {
> > + red_channel_client_shutdown(rcc);
> > + }
> > +}
> > +
> > +static void red_wait_outgoing_items(RedChannel *channel)
> > +{
> > + uint64_t end_time;
> > + int blocked;
> >
> > + if (!red_channel_any_blocked(channel)) {
> > + return;
> > + }
> > +
> > end_time = red_now() + DETACH_TIMEOUT;
> > red_printf("blocked");
> >
> > @@ -9545,59 +9762,52 @@ static void red_wait_outgoing_item(RedChannel *channel)
> > usleep(DETACH_SLEEP_DURATION);
> > red_channel_receive(channel);
> > red_channel_send(channel);
> > - } while ((blocked = red_channel_all_blocked(channel)) && red_now() < end_time);
> > + } while ((blocked = red_channel_any_blocked(channel)) && red_now() < end_time);
> >
> > if (blocked) {
> > red_printf("timeout");
> > - // TODO - not MC friendly
> > - red_channel_apply_clients(channel, channel->disconnect);
> > + red_channel_apply_clients(channel, rcc_shutdown_if_blocked);
> > }
> > - red_unref_channel(channel);
> > }
> >
> > -static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
> > +/* TODO: more evil sync stuff. anything with the word wait in it's name. */
> > +static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item)
> > {
> > - CommonChannel *common;
> > + RedChannel *channel = rcc->channel;
> > uint64_t end_time;
> > int item_in_pipe;
> >
> > - if (!channel) {
> > + if (!red_channel_client_blocked(rcc)) {
> > return;
> > }
> >
> > red_printf("");
> > - common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> > - red_ref_channel(channel);
> > - channel->hold_item(channel->rcc, item);
> > + channel->hold_item(rcc, item);
> >
> > end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
> >
> > - if (red_channel_all_blocked(channel)) {
> > - red_channel_receive(channel);
> > - red_channel_send(channel);
> > + if (red_channel_client_blocked(rcc)) {
> > + red_channel_client_receive(rcc);
> > + red_channel_client_send(rcc);
> > }
> > - // todo: different push for each channel
> > - red_push(common->worker);
> > + red_channel_client_push(rcc);
> >
> > while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
> > usleep(CHANNEL_PUSH_SLEEP_DURATION);
> > - red_channel_receive(channel);
> > - red_channel_send(channel);
> > - red_push(common->worker);
> > + red_channel_client_receive(rcc);
> > + red_channel_client_send(rcc);
> > + red_channel_client_push(rcc);
> > }
> >
> > if (item_in_pipe) {
> > red_printf("timeout");
> > - // TODO - not MC friendly
> > - red_channel_apply_clients(channel, channel->disconnect);
> > + red_channel_client_disconnect(rcc);
> > } else {
> > - if (red_channel_item_being_sent(channel, item)) {
> > - red_wait_outgoing_item(channel);
> > + if (red_channel_client_item_being_sent(rcc, item)) {
> > + red_wait_outgoing_item(rcc);
> > }
> > }
> > -
> > - channel->release_item(channel->rcc, item, FALSE);
> > - red_unref_channel(channel);
> > + channel->release_item(rcc, item, FALSE);
> > }
> >
> > static inline void handle_dev_update(RedWorker *worker)
> > @@ -9663,6 +9873,9 @@ static inline void handle_dev_del_memslot(RedWorker *worker)
> >
> > static inline void destroy_surface_wait(RedWorker *worker, Surfaces *surfaces, int surface_id)
> > {
> > + DisplayChannelClient *dcc = surfaces->dcc;
> > + RedChannelClient *rcc = &dcc->common.base;
> > +
> > if (!surfaces->surfaces[surface_id].context.canvas) {
> > return;
> > }
> > @@ -9672,12 +9885,12 @@ static inline void destroy_surface_wait(RedWorker *worker, Surfaces *surfaces, i
> > otherwise "current" will hold items that other drawables may depend on, and then
> > red_current_clear will remove them from the pipe. */
> > red_current_clear(worker, surfaces, surface_id);
> > - red_clear_surface_drawables_from_pipe(worker, surface_id, TRUE);
> > + red_clear_surface_drawables_from_pipe(dcc, surface_id, TRUE);
> > // in case that the pipe didn't contain any item that is dependent on the surface, but
> > // there is one during sending.
> > - red_wait_outgoing_item((RedChannel *)worker->display_channel);
> > - if (worker->display_channel) {
> > - ASSERT(red_channel_no_item_being_sent(&worker->display_channel->common.base));
> > + red_wait_outgoing_item(rcc);
> > + if (dcc) {
> > + ASSERT(red_channel_client_no_item_being_sent(rcc));
> > }
> > }
> >
> > @@ -9701,6 +9914,8 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
> > }
> >
> > /* called upon device reset */
> > +
> > +/* TODO: split me*/
> > static inline void handle_dev_destroy_surfaces(RedWorker *worker)
> > {
> > Surfaces *surfaces = &worker->surfaces;
> > @@ -9721,18 +9936,22 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
> > }
> > ASSERT(ring_is_empty(&surfaces->streams));
> >
> > - red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
> > - if (worker->cursor_channel) {
> > - red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> > + if (cursor_connected(worker)) {
> > + red_wait_outgoing_items(&worker->cursor_channel->common.base);
> > + red_channel_pipes_add_type(&worker->cursor_channel->common.base,
> > + PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> > if (!worker->cursor_channel->common.base.migrate) {
> > - red_pipe_add_verb(worker->cursor_channel->common.base.rcc, SPICE_MSG_CURSOR_RESET);
> > + red_pipes_add_verb(&worker->cursor_channel->common.base,
> > + SPICE_MSG_CURSOR_RESET);
> > }
> > ASSERT(red_channel_no_item_being_sent(&worker->cursor_channel->common.base));
> > }
> >
> > - if (worker->display_channel) {
> > - red_channel_client_pipe_add_type(worker->display_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> > - red_pipe_add_verb(worker->display_channel->common.base.rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
> > + if (display_connected(worker)) {
> > + red_channel_pipes_add_type(&worker->display_channel->common.base,
> > + PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> > + red_pipes_add_verb(&worker->display_channel->common.base,
> > + SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
> > }
> >
> > red_display_clear_glz_drawables(worker->display_channel);
> > @@ -9788,6 +10007,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
> > RedWorkerMessage message;
> > uint32_t surface_id;
> > Surfaces *surfaces = &worker->surfaces;
> > + RedChannel *cursor_red_channel = &worker->cursor_channel->common.base;
> >
> > receive_data(worker->channel, &surface_id, sizeof(uint32_t));
> >
> > @@ -9799,13 +10019,13 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
> > worker->cursor = NULL;
> > }
> >
> > - red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
> > - if (worker->cursor_channel) {
> > - red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> > + if (cursor_connected(worker)) {
> > + red_wait_outgoing_items(cursor_red_channel);
> > + red_channel_pipes_add_type(cursor_red_channel, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> > if (!worker->cursor_channel->common.base.migrate) {
> > - red_pipe_add_verb(worker->cursor_channel->common.base.rcc, SPICE_MSG_CURSOR_RESET);
> > + red_pipes_add_verb(cursor_red_channel, SPICE_MSG_CURSOR_RESET);
> > }
> > - ASSERT(red_channel_no_item_being_sent(&worker->cursor_channel->common.base));
> > + ASSERT(red_channel_no_item_being_sent(cursor_red_channel));
> > }
> >
> > flush_all_qxl_commands(worker);
> > @@ -9813,7 +10033,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
> > red_destroy_surface(worker, surfaces, 0);
> > ASSERT(ring_is_empty(&surfaces->streams));
> >
> > - ASSERT(!worker->surfaces.surfaces[surface_id].context.canvas);
> > + ASSERT(!surfaces->surfaces[surface_id].context.canvas);
> >
> > worker->cursor_visible = TRUE;
> > worker->cursor_position.x = worker->cursor_position.y = 0;
> > @@ -9861,12 +10081,11 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> > worker->cursor = NULL;
> > }
> >
> > - red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
> > - if (worker->cursor_channel) {
> > - red_channel_client_pipe_add_type(cursor_red_channel->rcc,
> > - PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> > + if (cursor_connected(worker)) {
> > + red_wait_outgoing_items(cursor_red_channel);
> > + red_channel_pipes_add_type(cursor_red_channel, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> > if (!cursor_red_channel->migrate) {
> > - red_pipe_add_verb(cursor_red_channel->rcc, SPICE_MSG_CURSOR_RESET);
> > + red_pipes_add_verb(cursor_red_channel, SPICE_MSG_CURSOR_RESET);
> > }
> > ASSERT(red_channel_no_item_being_sent(cursor_red_channel));
> >
> > @@ -9912,7 +10131,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> >
> > red_printf("disconnect display client");
> > receive_data(worker->channel, &rcc, sizeof(RedChannelClient *));
> > - red_disconnect_display(rcc);
> > + display_channel_client_disconnect(rcc);
> > message = RED_WORKER_MESSAGE_READY;
> > write_message(worker->channel, &message);
> > break;
> > @@ -9927,15 +10146,15 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> > red_printf("stop");
> > ASSERT(worker->running);
> > worker->running = FALSE;
> > - red_display_clear_glz_drawables(worker->display_channel);
> > + red_display_client_clear_glz_drawables(worker->surfaces.dcc);
> > for (x = 0; x < NUM_SURFACES; ++x) {
> > if (worker->surfaces.surfaces[x].context.canvas) {
> > red_current_flush(worker, &worker->surfaces, x);
> > }
> > }
> > red_cursor_flush(worker);
> > - red_wait_outgoing_item((RedChannel *)worker->display_channel);
> > - red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
> > + red_wait_outgoing_items(display_red_channel);
> > + red_wait_outgoing_items(cursor_red_channel);
> > message = RED_WORKER_MESSAGE_READY;
> > write_message(worker->channel, &message);
> > break;
> > @@ -10162,6 +10381,13 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
> > write_message(worker->channel, &message);
> > }
> >
> > +static void red_display_cc_free_glz_drawables(RedChannelClient *rcc)
> > +{
> > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> > +
> > + red_display_handle_glz_drawables_to_free(dcc);
> > +}
> > +
> > void *red_worker_main(void *arg)
> > {
> > RedWorker worker;
> > @@ -10192,11 +10418,12 @@ void *red_worker_main(void *arg)
> > num_events = epoll_wait(worker.epoll, events, MAX_EPOLL_SOURCES, worker.epoll_timeout);
> > red_handle_streams_timout(&worker, &worker.surfaces);
> >
> > - if (worker.display_channel && worker.display_channel->glz_dict) {
> > + if (worker.display_channel) {
> > /* 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_display_handle_glz_drawables_to_free(worker.display_channel);
> > + red_channel_apply_clients(&worker.display_channel->common.base,
> > + red_display_cc_free_glz_drawables);
> > }
> >
> > worker.epoll_timeout = INF_EPOLL_WAIT;
> > --
> > 1.7.4.4
> >
> > _______________________________________________
> > Spice-devel mailing list
> > Spice-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/spice-devel
> >
>
>
>
> --
> Marc-André Lureau
More information about the Spice-devel
mailing list