[Spice-devel] [PATCH 3/7] worker: move surfaces to DisplayChannel

Frediano Ziglio fziglio at redhat.com
Thu Nov 12 06:00:57 PST 2015


From: Marc-André Lureau <marcandre.lureau at gmail.com>

Ok. this one was painful.Note that in some cases, DCC_TO_DC should be
made safer (there used to be a if !dcc guard in some places, although
that looks wrong anyway)...
---
 server/display-channel.c |   79 ++++
 server/display-channel.h |   37 +-
 server/red_worker.c      | 1116 ++++++++++++++++++++--------------------------
 server/red_worker.h      |    2 +
 4 files changed, 592 insertions(+), 642 deletions(-)

diff --git a/server/display-channel.c b/server/display-channel.c
index 51302bd..f6f96a4 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -305,3 +305,82 @@ void display_channel_set_stream_video(DisplayChannel *display, int stream_video)
 
     display->stream_video = stream_video;
 }
+
+static void stop_streams(DisplayChannel *display)
+{
+    Ring *ring = &display->streams;
+    RingItem *item = ring_get_head(ring);
+
+    while (item) {
+        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
+        item = ring_next(ring, item);
+        if (!stream->current) {
+            stream_stop(display, stream);
+        } else {
+            spice_info("attached stream");
+        }
+    }
+
+    display->next_item_trace = 0;
+    memset(display->items_trace, 0, sizeof(display->items_trace));
+}
+
+void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id)
+{
+    RedSurface *surface = &display->surfaces[surface_id];
+    RedWorker *worker = COMMON_CHANNEL(display)->worker;
+    QXLInstance *qxl = red_worker_get_qxl(worker);
+    DisplayChannelClient *dcc;
+    RingItem *link, *next;
+
+    if (--surface->refs != 0) {
+        return;
+    }
+
+    // only primary surface streams are supported
+    if (is_primary_surface(display, surface_id)) {
+        stop_streams(display);
+    }
+    spice_assert(surface->context.canvas);
+
+    surface->context.canvas->ops->destroy(surface->context.canvas);
+    if (surface->create.info) {
+        qxl->st->qif->release_resource(qxl, surface->create);
+    }
+    if (surface->destroy.info) {
+        qxl->st->qif->release_resource(qxl, surface->destroy);
+    }
+
+    region_destroy(&surface->draw_dirty_region);
+    surface->context.canvas = NULL;
+    FOREACH_DCC(display, link, next, dcc) {
+        dcc_push_destroy_surface(dcc, surface_id);
+    }
+
+    spice_warn_if(!ring_is_empty(&surface->depend_on_me));
+}
+
+void display_channel_show_tree(DisplayChannel *display)
+{
+    int x;
+
+    for (x = 0; x < NUM_SURFACES; ++x) {
+        if (!display->surfaces[x].context.canvas)
+            continue;
+
+        RingItem *it;
+        Ring *ring = &display->surfaces[x].current;
+        RING_FOREACH(it, ring) {
+            TreeItem *now = SPICE_CONTAINEROF(it, TreeItem, siblings_link);
+            tree_item_dump(now);
+        }
+
+    }
+}
+
+/* TODO: perhaps rename to "ready" or "realized" ? */
+bool display_channel_surface_has_canvas(DisplayChannel *display,
+                                        uint32_t surface_id)
+{
+    return display->surfaces[surface_id].context.canvas != NULL;
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index 27e5203..5518494 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -204,8 +204,8 @@ struct DisplayChannelClient {
 
 #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 DCC_TO_DC(dcc)                                                  \
+     SPICE_CONTAINEROF((dcc)->common.base.channel, DisplayChannel, common.base)
 #define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
 
 
@@ -272,6 +272,30 @@ void                       monitors_config_unref                     (MonitorsCo
 #define NUM_TRACE_ITEMS (1 << TRACE_ITEMS_SHIFT)
 #define ITEMS_TRACE_MASK (NUM_TRACE_ITEMS - 1)
 
+typedef struct DrawContext {
+    SpiceCanvas *canvas;
+    int canvas_draws_on_surface;
+    int top_down;
+    uint32_t width;
+    uint32_t height;
+    int32_t stride;
+    uint32_t format;
+    void *line_0;
+} DrawContext;
+
+typedef struct RedSurface {
+    uint32_t refs;
+    Ring current;
+    Ring current_list;
+    DrawContext context;
+
+    Ring depend_on_me;
+    QRegion draw_dirty_region;
+
+    //fix me - better handling here
+    QXLReleaseInfoExt create, destroy;
+} RedSurface;
+
 #define NUM_DRAWABLES 1000
 typedef struct _Drawable _Drawable;
 struct _Drawable {
@@ -310,6 +334,10 @@ struct DisplayChannel {
     uint32_t next_item_trace;
     uint64_t streams_size_total;
 
+    RedSurface surfaces[NUM_SURFACES];
+    uint32_t n_surfaces;
+    SpiceImageSurfaces image_surfaces;
+
     ImageCache image_cache;
     RedCompressBuf *free_compress_bufs;
 
@@ -371,6 +399,11 @@ int                        display_channel_get_streams_timeout       (DisplayCha
 void                       display_channel_compress_stats_print      (const DisplayChannel *display);
 void                       display_channel_compress_stats_reset      (DisplayChannel *display);
 void                       display_channel_drawable_unref            (DisplayChannel *display, Drawable *drawable);
+void                       display_channel_surface_unref             (DisplayChannel *display,
+                                                                      uint32_t surface_id);
+bool                       display_channel_surface_has_canvas        (DisplayChannel *display,
+                                                                      uint32_t surface_id);
+void                       display_channel_show_tree                 (DisplayChannel *display);
 
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
diff --git a/server/red_worker.c b/server/red_worker.c
index 6e1535b..68ac527 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -209,30 +209,6 @@ typedef struct UpgradeItem {
     SpiceClipRects *rects;
 } UpgradeItem;
 
-typedef struct DrawContext {
-    SpiceCanvas *canvas;
-    int canvas_draws_on_surface;
-    int top_down;
-    uint32_t width;
-    uint32_t height;
-    int32_t stride;
-    uint32_t format;
-    void *line_0;
-} DrawContext;
-
-typedef struct RedSurface {
-    uint32_t refs;
-    Ring current;
-    Ring current_list;
-    DrawContext context;
-
-    Ring depend_on_me;
-    QRegion draw_dirty_region;
-
-    //fix me - better handling here
-    QXLReleaseInfoExt create, destroy;
-} RedSurface;
-
 typedef struct RedWorker {
     pthread_t thread;
     clockid_t clockid;
@@ -249,10 +225,6 @@ typedef struct RedWorker {
     CursorChannel *cursor_channel;
     uint32_t cursor_poll_tries;
 
-    RedSurface surfaces[NUM_SURFACES];
-    uint32_t n_surfaces;
-    SpiceImageSurfaces image_surfaces;
-
     uint32_t red_drawable_count;
     uint32_t glz_drawable_count;
     uint32_t bits_unique;
@@ -306,13 +278,13 @@ typedef struct BitmapData {
     SpiceRect lossy_rect;
 } BitmapData;
 
-static inline int validate_surface(RedWorker *worker, uint32_t surface_id);
+static inline int validate_surface(DisplayChannel *display, uint32_t surface_id);
 
-static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable);
-static void red_current_flush(RedWorker *worker, int surface_id);
-static void red_draw_drawable(RedWorker *worker, Drawable *item);
-static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id);
-static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int surface_id,
+static void red_draw_qxl_drawable(DisplayChannel *display, Drawable *drawable);
+static void red_current_flush(DisplayChannel *display, int surface_id);
+static void red_draw_drawable(DisplayChannel *display, Drawable *item);
+static void red_update_area(DisplayChannel *display, const SpiceRect *area, int surface_id);
+static void red_update_area_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
                                  Drawable *last);
 static void detach_stream(DisplayChannel *display, Stream *stream, int detach_sized);
 static inline void display_channel_stream_maintenance(DisplayChannel *display, Drawable *candidate, Drawable *sect);
@@ -329,6 +301,9 @@ static void display_channel_client_release_item_before_push(DisplayChannelClient
                                                             PipeItem *item);
 static void display_channel_client_release_item_after_push(DisplayChannelClient *dcc,
                                                            PipeItem *item);
+static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uint32_t width,
+                               uint32_t height, int32_t stride, uint32_t format,
+                               void *line_0, int data_is_valid, int send_client);
 
 #define LINK_TO_DPI(ptr) SPICE_CONTAINEROF((ptr), DrawablePipeItem, base)
 #define DRAWABLE_FOREACH_DPI_SAFE(drawable, link, next, dpi)          \
@@ -464,8 +439,8 @@ static int validate_drawable_bbox(RedWorker *worker, RedDrawable *drawable)
         /* surface_id must be validated before calling into
          * validate_drawable_bbox
          */
-        VALIDATE_SURFACE_RETVAL(worker, surface_id, FALSE);
-        context = &worker->surfaces[surface_id].context;
+        VALIDATE_SURFACE_RETVAL(worker->display_channel, surface_id, FALSE);
+        context = &worker->display_channel->surfaces[surface_id].context;
 
         if (drawable->bbox.top < 0)
                 return FALSE;
@@ -483,15 +458,15 @@ static int validate_drawable_bbox(RedWorker *worker, RedDrawable *drawable)
         return TRUE;
 }
 
-static inline int validate_surface(RedWorker *worker, uint32_t surface_id)
+static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
 {
-    if SPICE_UNLIKELY(surface_id >= worker->n_surfaces) {
+    if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
         spice_warning("invalid surface_id %u", surface_id);
         return 0;
     }
-    if (!worker->surfaces[surface_id].context.canvas) {
+    if (!display->surfaces[surface_id].context.canvas) {
         spice_warning("canvas address is %p for %d (and is NULL)\n",
-                   &(worker->surfaces[surface_id].context.canvas), surface_id);
+                   &(display->surfaces[surface_id].context.canvas), surface_id);
         spice_warning("failed on %d", surface_id);
         return 0;
     }
@@ -504,7 +479,7 @@ static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id);
 static inline void red_handle_drawable_surfaces_client_synced(
                         DisplayChannelClient *dcc, Drawable *drawable)
 {
-    RedWorker *worker = DCC_TO_WORKER(dcc);
+    DisplayChannel *display = DCC_TO_DC(dcc);
     int x;
 
     for (x = 0; x < 3; ++x) {
@@ -516,7 +491,7 @@ static inline void red_handle_drawable_surfaces_client_synced(
                 continue;
             }
             red_create_surface_item(dcc, surface_id);
-            red_current_flush(worker, surface_id);
+            red_current_flush(display, surface_id);
             red_push_surface_image(dcc, surface_id);
         }
     }
@@ -526,7 +501,7 @@ static inline void red_handle_drawable_surfaces_client_synced(
     }
 
     red_create_surface_item(dcc, drawable->surface_id);
-    red_current_flush(worker, drawable->surface_id);
+    red_current_flush(display, drawable->surface_id);
     red_push_surface_image(dcc, drawable->surface_id);
 }
 
@@ -551,13 +526,13 @@ static void dcc_add_drawable(DisplayChannelClient *dcc, Drawable *drawable)
     red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item);
 }
 
-static void red_pipes_add_drawable(RedWorker *worker, Drawable *drawable)
+static void red_pipes_add_drawable(DisplayChannel *display, Drawable *drawable)
 {
     DisplayChannelClient *dcc;
     RingItem *dcc_ring_item, *next;
 
     spice_warn_if(!ring_is_empty(&drawable->pipes));
-    FOREACH_DCC(worker->display_channel, dcc_ring_item, next, dcc) {
+    FOREACH_DCC(display, dcc_ring_item, next, dcc) {
         dcc_add_drawable(dcc, drawable);
     }
 }
@@ -574,7 +549,7 @@ static void dcc_add_drawable_to_tail(DisplayChannelClient *dcc, Drawable *drawab
     red_channel_client_pipe_add_tail(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item);
 }
 
-static inline void red_pipes_add_drawable_after(RedWorker *worker,
+static inline void red_pipes_add_drawable_after(DisplayChannel *display,
                                                 Drawable *drawable, Drawable *pos_after)
 {
     DrawablePipeItem *dpi, *dpi_pos_after;
@@ -591,13 +566,13 @@ static inline void red_pipes_add_drawable_after(RedWorker *worker,
                                           &dpi_pos_after->dpi_pipe_item);
     }
     if (num_other_linked == 0) {
-        red_pipes_add_drawable(worker, drawable);
+        red_pipes_add_drawable(display, drawable);
         return;
     }
-    if (num_other_linked != worker->display_channel->common.base.clients_num) {
-        RingItem *worker_item, *next;
+    if (num_other_linked != display->common.base.clients_num) {
+        RingItem *item, *next;
         spice_debug("TODO: not O(n^2)");
-        FOREACH_DCC(worker->display_channel, worker_item, next, dcc) {
+        FOREACH_DCC(display, item, next, dcc) {
             int sent = 0;
             DRAWABLE_FOREACH_DPI_SAFE(pos_after, dpi_link, dpi_next, dpi_pos_after) {
                 if (dpi_pos_after->dcc == dcc) {
@@ -621,8 +596,6 @@ static inline PipeItem *red_pipe_get_tail(DisplayChannelClient *dcc)
     return (PipeItem*)ring_get_tail(&RED_CHANNEL_CLIENT(dcc)->pipe);
 }
 
-static void red_surface_unref(RedWorker *worker, uint32_t surface_id);
-
 static inline void red_pipes_remove_drawable(Drawable *drawable)
 {
     DrawablePipeItem *dpi;
@@ -737,59 +710,6 @@ static void drawables_init(DisplayChannel *display)
 }
 
 
-static void stop_streams(DisplayChannel *display)
-{
-    Ring *ring = &display->streams;
-    RingItem *item = ring_get_head(ring);
-
-    while (item) {
-        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
-        item = ring_next(ring, item);
-        if (!stream->current) {
-            stream_stop(display, stream);
-        } else {
-            spice_info("attached stream");
-        }
-    }
-
-    display->next_item_trace = 0;
-    memset(display->items_trace, 0, sizeof(display->items_trace));
-}
-
-static void red_surface_unref(RedWorker *worker, uint32_t surface_id)
-{
-    DisplayChannel *display = worker->display_channel;
-    RedSurface *surface = &worker->surfaces[surface_id];
-    DisplayChannelClient *dcc;
-    RingItem *link, *next;
-
-    if (--surface->refs != 0) {
-        return;
-    }
-
-    // only primary surface streams are supported
-    if (is_primary_surface(worker->display_channel, surface_id)) {
-        stop_streams(display);
-    }
-    spice_assert(surface->context.canvas);
-
-    surface->context.canvas->ops->destroy(surface->context.canvas);
-    if (surface->create.info) {
-        worker->qxl->st->qif->release_resource(worker->qxl, surface->create);
-    }
-    if (surface->destroy.info) {
-        worker->qxl->st->qif->release_resource(worker->qxl, surface->destroy);
-    }
-
-    region_destroy(&surface->draw_dirty_region);
-    surface->context.canvas = NULL;
-    FOREACH_DCC(worker->display_channel, link, next, dcc) {
-        dcc_push_destroy_surface(dcc, surface_id);
-    }
-
-    spice_warn_if(!ring_is_empty(&surface->depend_on_me));
-}
-
 static inline void set_surface_release_info(QXLReleaseInfoExt *release_info_ext,
                                             QXLReleaseInfo *release_info, uint32_t group_id)
 {
@@ -838,7 +758,7 @@ static void drawable_unref_surface_deps(DisplayChannel *display, Drawable *drawa
         if (surface_id == -1) {
             continue;
         }
-        red_surface_unref(COMMON_CHANNEL(display)->worker, surface_id);
+        display_channel_surface_unref(display, surface_id);
     }
 }
 
@@ -872,7 +792,7 @@ void display_channel_drawable_unref(DisplayChannel *display, Drawable *drawable)
 
     drawable_remove_dependencies(display, drawable);
     drawable_unref_surface_deps(display, drawable);
-    red_surface_unref(COMMON_CHANNEL(display)->worker, drawable->surface_id);
+    display_channel_surface_unref(display, drawable->surface_id);
 
     RING_FOREACH_SAFE(item, next, &drawable->glz_ring) {
         SPICE_CONTAINEROF(item, RedGlzDrawable, drawable_link)->drawable = NULL;
@@ -917,12 +837,12 @@ static void display_stream_trace_add_drawable(DisplayChannel *display, Drawable
     trace->dest_area = item->red_drawable->bbox;
 }
 
-static void surface_flush(RedWorker *worker, int surface_id, SpiceRect *rect)
+static void surface_flush(DisplayChannel *display, int surface_id, SpiceRect *rect)
 {
-    red_update_area(worker, rect, surface_id);
+    red_update_area(display, rect, surface_id);
 }
 
-static void red_flush_source_surfaces(RedWorker *worker, Drawable *drawable)
+static void red_flush_source_surfaces(DisplayChannel *display, Drawable *drawable)
 {
     int x;
     int surface_id;
@@ -931,15 +851,13 @@ static void red_flush_source_surfaces(RedWorker *worker, Drawable *drawable)
         surface_id = drawable->surface_deps[x];
         if (surface_id != -1 && drawable->depend_items[x].drawable) {
             remove_depended_item(&drawable->depend_items[x]);
-            surface_flush(worker, surface_id, &drawable->red_drawable->surfaces_rects[x]);
+            surface_flush(display, surface_id, &drawable->red_drawable->surfaces_rects[x]);
         }
     }
 }
 
-static inline void current_remove_drawable(RedWorker *worker, Drawable *item)
+static inline void current_remove_drawable(DisplayChannel *display, Drawable *item)
 {
-    DisplayChannel *display = worker->display_channel;
-
     display_stream_trace_add_drawable(display, item);
     remove_shadow(&item->tree_item);
     ring_remove(&item->tree_item.base.siblings_link);
@@ -949,23 +867,24 @@ static inline void current_remove_drawable(RedWorker *worker, Drawable *item)
     display->current_size--;
 }
 
-static void remove_drawable(RedWorker *worker, Drawable *drawable)
+static void remove_drawable(DisplayChannel *display, Drawable *drawable)
 {
     red_pipes_remove_drawable(drawable);
-    current_remove_drawable(worker, drawable);
+    current_remove_drawable(display, drawable);
 }
 
-static inline void current_remove(RedWorker *worker, TreeItem *item)
+static inline void current_remove(DisplayChannel *display, TreeItem *item)
 {
     TreeItem *now = item;
 
+    /* depth-first tree traversal, todo: do a to tree_foreach()? */
     for (;;) {
         Container *container = now->container;
         RingItem *ring_item;
 
         if (now->type == TREE_ITEM_TYPE_DRAWABLE) {
             ring_item = now->siblings_link.prev;
-            remove_drawable(worker, SPICE_CONTAINEROF(now, Drawable, tree_item));
+            remove_drawable(display, SPICE_CONTAINEROF(now, Drawable, tree_item));
         } else {
             Container *container = (Container *)now;
 
@@ -990,13 +909,14 @@ static inline void current_remove(RedWorker *worker, TreeItem *item)
     }
 }
 
-static void red_current_clear(RedWorker *worker, int surface_id)
+static void current_clear(DisplayChannel *display, int surface_id)
 {
+    Ring *ring = &display->surfaces[surface_id].current;
     RingItem *ring_item;
 
-    while ((ring_item = ring_get_head(&worker->surfaces[surface_id].current))) {
+    while ((ring_item = ring_get_head(ring))) {
         TreeItem *now = SPICE_CONTAINEROF(ring_item, TreeItem, siblings_link);
-        current_remove(worker, now);
+        current_remove(display, now);
     }
 }
 
@@ -1081,14 +1001,14 @@ static int red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int
     return TRUE;
 }
 
-static void red_clear_surface_drawables_from_pipes(RedWorker *worker,
+static void red_clear_surface_drawables_from_pipes(DisplayChannel *display,
                                                    int surface_id,
                                                    int wait_if_used)
 {
     RingItem *item, *next;
     DisplayChannelClient *dcc;
 
-    FOREACH_DCC(worker->display_channel, item, next, dcc) {
+    FOREACH_DCC(display, item, next, dcc) {
         if (!red_clear_surface_drawables_from_pipe(dcc, surface_id, wait_if_used)) {
             red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
         }
@@ -1128,11 +1048,12 @@ static inline int __contained_by(TreeItem *item, Ring *ring)
     return FALSE;
 }
 
-static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *item, QRegion *rgn,
-                                    Ring **top_ring, Drawable *frame_candidate)
+static void __exclude_region(DisplayChannel *display, Ring *ring, TreeItem *item, QRegion *rgn,
+                             Ring **top_ring, Drawable *frame_candidate)
 {
     QRegion and_rgn;
 #ifdef RED_WORKER_STAT
+    RedWorker *worker = COMMON_CHANNEL(display)->worker;
     stat_time_t start_time = stat_now(worker->clockid);
 #endif
 
@@ -1168,7 +1089,7 @@ static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *ite
             } else {
                 if (frame_candidate) {
                     Drawable *drawable = SPICE_CONTAINEROF(draw, Drawable, tree_item);
-                    display_channel_stream_maintenance(worker->display_channel, frame_candidate, drawable);
+                    display_channel_stream_maintenance(display, frame_candidate, drawable);
                 }
                 region_exclude(&draw->base.rgn, &and_rgn);
             }
@@ -1196,13 +1117,14 @@ static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *ite
         }
     }
     region_destroy(&and_rgn);
-    stat_add(&worker->display_channel->__exclude_stat, start_time);
+    stat_add(&display->__exclude_stat, start_time);
 }
 
-static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, QRegion *rgn,
-                           TreeItem **last, Drawable *frame_candidate)
+static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_item,
+                           QRegion *rgn, TreeItem **last, Drawable *frame_candidate)
 {
 #ifdef RED_WORKER_STAT
+    RedWorker *worker = COMMON_CHANNEL(display)->worker;
     stat_time_t start_time = stat_now(worker->clockid);
 #endif
     Ring *top_ring;
@@ -1220,12 +1142,12 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
         spice_assert(!region_is_empty(&now->rgn));
 
         if (region_intersects(rgn, &now->rgn)) {
-            __exclude_region(worker, ring, now, rgn, &top_ring, frame_candidate);
+            __exclude_region(display, ring, now, rgn, &top_ring, frame_candidate);
 
             if (region_is_empty(&now->rgn)) {
                 spice_assert(now->type != TREE_ITEM_TYPE_SHADOW);
                 ring_item = now->siblings_link.prev;
-                current_remove(worker, now);
+                current_remove(display, now);
                 if (last && *last == now) {
                     *last = (TreeItem *)ring_next(ring, ring_item);
                 }
@@ -1240,7 +1162,7 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
             }
 
             if (region_is_empty(rgn)) {
-                stat_add(&worker->display_channel->exclude_stat, start_time);
+                stat_add(&display->exclude_stat, start_time);
                 return;
             }
         }
@@ -1248,7 +1170,7 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
         while ((last && *last == (TreeItem *)ring_item) ||
                !(ring_item = ring_next(ring, ring_item))) {
             if (ring == top_ring) {
-                stat_add(&worker->display_channel->exclude_stat, start_time);
+                stat_add(&display->exclude_stat, start_time);
                 return;
             }
             ring_item = &container->base.siblings_link;
@@ -1258,13 +1180,13 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
     }
 }
 
-static inline void current_add_drawable(RedWorker *worker, Drawable *drawable, RingItem *pos)
+static void current_add_drawable(DisplayChannel *display,
+                                 Drawable *drawable, RingItem *pos)
 {
-    DisplayChannel *display = worker->display_channel;
     RedSurface *surface;
     uint32_t surface_id = drawable->surface_id;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &display->surfaces[surface_id];
     ring_add_after(&drawable->tree_item.base.siblings_link, pos);
     ring_add(&display->current_list, &drawable->list_link);
     ring_add(&surface->current_list, &drawable->surface_list_link);
@@ -1360,9 +1282,9 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
                     stream_id, stream->current != NULL);
         rect_debug(&upgrade_area);
         if (update_area_limit) {
-            red_update_area_till(DCC_TO_WORKER(dcc), &upgrade_area, 0, update_area_limit);
+            red_update_area_till(DCC_TO_DC(dcc), &upgrade_area, 0, update_area_limit);
         } else {
-            red_update_area(DCC_TO_WORKER(dcc), &upgrade_area, 0);
+            red_update_area(DCC_TO_DC(dcc), &upgrade_area, 0);
         }
         red_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
     }
@@ -2017,9 +1939,8 @@ static inline int is_drawable_independent_from_surfaces(Drawable *drawable)
     return TRUE;
 }
 
-static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeItem *other)
+static inline int red_current_add_equal(DisplayChannel *display, DrawItem *item, TreeItem *other)
 {
-    DisplayChannel *display  = worker->display_channel;
     DrawItem *other_draw_item;
     Drawable *drawable;
     Drawable *other_drawable;
@@ -2039,14 +1960,14 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
     if (item->effect == QXL_EFFECT_OPAQUE) {
         int add_after = !!other_drawable->stream &&
                         is_drawable_independent_from_surfaces(drawable);
-        display_channel_stream_maintenance(worker->display_channel, drawable, other_drawable);
-        current_add_drawable(worker, drawable, &other->siblings_link);
+        display_channel_stream_maintenance(display, drawable, other_drawable);
+        current_add_drawable(display, drawable, &other->siblings_link);
         other_drawable->refs++;
-        current_remove_drawable(worker, other_drawable);
+        current_remove_drawable(display, other_drawable);
         if (add_after) {
-            red_pipes_add_drawable_after(worker, drawable, other_drawable);
+            red_pipes_add_drawable_after(display, drawable, other_drawable);
         } else {
-            red_pipes_add_drawable(worker, drawable);
+            red_pipes_add_drawable(display, drawable);
         }
         red_pipes_remove_drawable(other_drawable);
         display_channel_drawable_unref(display, other_drawable);
@@ -2062,11 +1983,11 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
             RingItem *worker_ring_item, *dpi_ring_item;
 
             other_drawable->refs++;
-            current_remove_drawable(worker, other_drawable);
+            current_remove_drawable(display, other_drawable);
 
             /* sending the drawable to clients that already received
              * (or will receive) other_drawable */
-            worker_ring_item = ring_get_head(&RED_CHANNEL(worker->display_channel)->clients);
+            worker_ring_item = ring_get_head(&RED_CHANNEL(display)->clients);
             dpi_ring_item = ring_get_head(&other_drawable->pipes);
             /* dpi contains a sublist of dcc's, ordered the same */
             while (worker_ring_item) {
@@ -2075,7 +1996,7 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
                 dpi = SPICE_CONTAINEROF(dpi_ring_item, DrawablePipeItem, base);
                 while (worker_ring_item && (!dpi || dcc != dpi->dcc)) {
                     dcc_add_drawable(dcc, drawable);
-                    worker_ring_item = ring_next(&RED_CHANNEL(worker->display_channel)->clients,
+                    worker_ring_item = ring_next(&RED_CHANNEL(display)->clients,
                                                  worker_ring_item);
                     dcc = SPICE_CONTAINEROF(worker_ring_item, DisplayChannelClient,
                                             common.base.channel_link);
@@ -2085,7 +2006,7 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
                     dpi_ring_item = ring_next(&other_drawable->pipes, dpi_ring_item);
                 }
                 if (worker_ring_item) {
-                    worker_ring_item = ring_next(&RED_CHANNEL(worker->display_channel)->clients,
+                    worker_ring_item = ring_next(&RED_CHANNEL(display)->clients,
                                                  worker_ring_item);
                 }
             }
@@ -2098,9 +2019,9 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
         break;
     case QXL_EFFECT_OPAQUE_BRUSH:
         if (is_same_geometry(drawable, other_drawable)) {
-            current_add_drawable(worker, drawable, &other->siblings_link);
-            remove_drawable(worker, other_drawable);
-            red_pipes_add_drawable(worker, drawable);
+            current_add_drawable(display, drawable, &other->siblings_link);
+            remove_drawable(display, other_drawable);
+            red_pipes_add_drawable(display, drawable);
             return TRUE;
         }
         break;
@@ -2168,10 +2089,11 @@ static void red_use_stream_trace(DisplayChannel *display, Drawable *drawable)
     }
 }
 
-static inline int current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
+static int current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
 {
     DrawItem *item = &drawable->tree_item;
 #ifdef RED_WORKER_STAT
+    RedWorker *worker = COMMON_CHANNEL(display)->worker;
     stat_time_t start_time = stat_now(worker->clockid);
 #endif
     RingItem *now;
@@ -2197,8 +2119,8 @@ static inline int current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
         } else if (sibling->type != TREE_ITEM_TYPE_SHADOW) {
             if (!(test_res & REGION_TEST_RIGHT_EXCLUSIVE) &&
                                                    !(test_res & REGION_TEST_LEFT_EXCLUSIVE) &&
-                                                   red_current_add_equal(worker, item, sibling)) {
-                stat_add(&worker->display_channel->add_stat, start_time);
+                                                   red_current_add_equal(display, item, sibling)) {
+                stat_add(&display->add_stat, start_time);
                 return FALSE;
             }
 
@@ -2209,7 +2131,7 @@ static inline int current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
                 if ((shadow = __find_shadow(sibling))) {
                     if (exclude_base) {
                         TreeItem *next = sibling;
-                        exclude_region(worker, ring, exclude_base, &exclude_rgn, &next, NULL);
+                        exclude_region(display, ring, exclude_base, &exclude_rgn, &next, NULL);
                         if (next != sibling) {
                             now = next ? &next->siblings_link : NULL;
                             exclude_base = NULL;
@@ -2219,7 +2141,7 @@ static inline int current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
                     region_or(&exclude_rgn, &shadow->on_hold);
                 }
                 now = now->prev;
-                current_remove(worker, sibling);
+                current_remove(display, sibling);
                 now = ring_next(ring, now);
                 if (shadow || skip) {
                     exclude_base = now;
@@ -2231,7 +2153,7 @@ static inline int current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
                 Container *container;
 
                 if (exclude_base) {
-                    exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL, NULL);
+                    exclude_region(display, ring, exclude_base, &exclude_rgn, NULL, NULL);
                     region_clear(&exclude_rgn);
                     exclude_base = NULL;
                 }
@@ -2262,28 +2184,28 @@ static inline int current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
     }
     if (item->effect == QXL_EFFECT_OPAQUE) {
         region_or(&exclude_rgn, &item->base.rgn);
-        exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL, drawable);
-        red_use_stream_trace(worker->display_channel, drawable);
-        streams_update_visible_region(worker->display_channel, drawable);
+        exclude_region(display, ring, exclude_base, &exclude_rgn, NULL, drawable);
+        red_use_stream_trace(display, drawable);
+        streams_update_visible_region(display, drawable);
         /*
          * Performing the insertion after exclude_region for
          * safety (todo: Not sure if exclude_region can affect the drawable
          * if it is added to the tree before calling exclude_region).
          */
-        current_add_drawable(worker, drawable, ring);
+        current_add_drawable(display, drawable, ring);
     } else {
         /*
          * red_detach_streams_behind can affect the current tree since it may
          * trigger calls to update_area. Thus, the drawable should be added to the tree
          * before calling red_detach_streams_behind
          */
-        current_add_drawable(worker, drawable, ring);
-        if (is_primary_surface(worker->display_channel, drawable->surface_id)) {
-            detach_streams_behind(worker->display_channel, &drawable->tree_item.base.rgn, drawable);
+        current_add_drawable(display, drawable, ring);
+        if (is_primary_surface(display, drawable->surface_id)) {
+            detach_streams_behind(display, &drawable->tree_item.base.rgn, drawable);
         }
     }
     region_destroy(&exclude_rgn);
-    stat_add(&worker->display_channel->add_stat, start_time);
+    stat_add(&display->add_stat, start_time);
     return TRUE;
 }
 
@@ -2296,10 +2218,10 @@ static void add_clip_rects(QRegion *rgn, SpiceClipRects *data)
     }
 }
 
-static inline int current_add_with_shadow(RedWorker *worker, Ring *ring, Drawable *item)
+static int current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawable *item)
 {
-    DisplayChannel *display = worker->display_channel;
 #ifdef RED_WORKER_STAT
+    RedWorker *worker = COMMON_CHANNEL(display)->worker;
     stat_time_t start_time = stat_now(worker->clockid);
     ++display->add_with_shadow_count;
 #endif
@@ -2324,11 +2246,11 @@ static inline int current_add_with_shadow(RedWorker *worker, Ring *ring, Drawabl
     }
 
     ring_add(ring, &shadow->base.siblings_link);
-    current_add_drawable(worker, item, ring);
+    current_add_drawable(display, item, ring);
     if (item->tree_item.effect == QXL_EFFECT_OPAQUE) {
         QRegion exclude_rgn;
         region_clone(&exclude_rgn, &item->tree_item.base.rgn);
-        exclude_region(worker, ring, &shadow->base.siblings_link, &exclude_rgn, NULL, NULL);
+        exclude_region(display, ring, &shadow->base.siblings_link, &exclude_rgn, NULL, NULL);
         region_destroy(&exclude_rgn);
         streams_update_visible_region(display, item);
     } else {
@@ -2410,18 +2332,17 @@ void print_stats(DisplayChannel *display)
 #endif
 }
 
-static int red_add_drawable(RedWorker *worker, Drawable *drawable)
+ static int red_add_drawable(DisplayChannel *display, Drawable *drawable)
 {
-    DisplayChannel *display = worker->display_channel;
     int ret = FALSE, surface_id = drawable->surface_id;
     RedDrawable *red_drawable = drawable->red_drawable;
-    Ring *ring = &worker->surfaces[surface_id].current;
+    Ring *ring = &display->surfaces[surface_id].current;
 
     if (has_shadow(red_drawable)) {
-        ret = current_add_with_shadow(worker, ring, drawable);
+        ret = current_add_with_shadow(display, ring, drawable);
     } else {
         drawable_update_streamable(display, drawable);
-        ret = current_add(worker, ring, drawable);
+        ret = current_add(display, ring, drawable);
     }
 
 #ifdef RED_WORKER_STAT
@@ -2431,15 +2352,15 @@ static int red_add_drawable(RedWorker *worker, Drawable *drawable)
     return ret;
 }
 
-static void red_get_area(RedWorker *worker, int surface_id, const SpiceRect *area, uint8_t *dest,
-                         int dest_stride, int update)
+static void red_get_area(DisplayChannel *display, int surface_id, const SpiceRect *area,
+                         uint8_t *dest, int dest_stride, int update)
 {
     SpiceCanvas *canvas;
     RedSurface *surface;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &display->surfaces[surface_id];
     if (update) {
-        red_update_area(worker, area, surface_id);
+        red_update_area(display, area, surface_id);
     }
 
     canvas = surface->context.canvas;
@@ -2491,7 +2412,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
         return TRUE;
     }
 
-    surface = &worker->surfaces[drawable->surface_id];
+    surface = &display->surfaces[drawable->surface_id];
 
     bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
 
@@ -2517,7 +2438,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     image->u.bitmap.data = spice_chunks_new_linear(dest, height * dest_stride);
     image->u.bitmap.data->flags |= SPICE_CHUNKS_FLAGS_FREE;
 
-    red_get_area(worker, drawable->surface_id,
+    red_get_area(display, drawable->surface_id,
                  &red_drawable->self_bitmap_area, dest, dest_stride, TRUE);
 
     /* For 32bit non-primary surfaces we need to keep any non-zero
@@ -2536,9 +2457,8 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     return TRUE;
 }
 
-static bool free_one_drawable(RedWorker *worker, int force_glz_free)
+static bool free_one_drawable(DisplayChannel *display, int force_glz_free)
 {
-    DisplayChannel *display = worker->display_channel;
     RingItem *ring_item = ring_get_tail(&display->current_list);
     Drawable *drawable;
     Container *container;
@@ -2554,12 +2474,11 @@ static bool free_one_drawable(RedWorker *worker, int force_glz_free)
             red_display_free_glz_drawable(glz->dcc, glz);
         }
     }
-    red_draw_drawable(worker, drawable);
+    red_draw_drawable(display, drawable);
     container = drawable->tree_item.base.container;
 
-    current_remove_drawable(worker, drawable);
+    current_remove_drawable(display, drawable);
     container_cleanup(container);
-
     return TRUE;
 }
 
@@ -2570,19 +2489,19 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
     Drawable *drawable;
     int x;
 
-    VALIDATE_SURFACE_RETVAL(worker, red_drawable->surface_id, NULL)
+    VALIDATE_SURFACE_RETVAL(display, red_drawable->surface_id, NULL)
     if (!validate_drawable_bbox(worker, red_drawable)) {
         rendering_incorrect(__func__);
         return NULL;
     }
     for (x = 0; x < 3; ++x) {
         if (red_drawable->surface_deps[x] != -1) {
-            VALIDATE_SURFACE_RETVAL(worker, red_drawable->surface_deps[x], NULL)
+            VALIDATE_SURFACE_RETVAL(display, red_drawable->surface_deps[x], NULL)
         }
     }
 
     while (!(drawable = drawable_try_new(display))) {
-        if (!free_one_drawable(COMMON_CHANNEL(display)->worker, FALSE))
+        if (!free_one_drawable(display, FALSE))
             return NULL;
     }
 
@@ -2607,24 +2526,24 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
     return drawable;
 }
 
-static inline int red_handle_depends_on_target_surface(RedWorker *worker, uint32_t surface_id)
+static inline int red_handle_depends_on_target_surface(DisplayChannel *display, uint32_t surface_id)
 {
     RedSurface *surface;
     RingItem *ring_item;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &display->surfaces[surface_id];
 
     while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
         Drawable *drawable;
         DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item);
         drawable = depended_item->drawable;
-        surface_flush(worker, drawable->surface_id, &drawable->red_drawable->bbox);
+        surface_flush(display, drawable->surface_id, &drawable->red_drawable->bbox);
     }
 
     return TRUE;
 }
 
-static inline void add_to_surface_dependency(RedWorker *worker, int depend_on_surface_id,
+static inline void add_to_surface_dependency(DisplayChannel *display, int depend_on_surface_id,
                                              DependItem *depend_item, Drawable *drawable)
 {
     RedSurface *surface;
@@ -2634,22 +2553,21 @@ static inline void add_to_surface_dependency(RedWorker *worker, int depend_on_su
         return;
     }
 
-    surface = &worker->surfaces[depend_on_surface_id];
+    surface = &display->surfaces[depend_on_surface_id];
 
     depend_item->drawable = drawable;
     ring_add(&surface->depend_on_me, &depend_item->ring_item);
 }
 
-static inline int red_handle_surfaces_dependencies(RedWorker *worker, Drawable *drawable)
+static inline int red_handle_surfaces_dependencies(DisplayChannel *display, Drawable *drawable)
 {
-    DisplayChannel *display = worker->display_channel;
     int x;
 
     for (x = 0; x < 3; ++x) {
         // surface self dependency is handled by shadows in "current", or by
         // handle_self_bitmap
         if (drawable->surface_deps[x] != drawable->surface_id) {
-            add_to_surface_dependency(worker, drawable->surface_deps[x],
+            add_to_surface_dependency(display, drawable->surface_deps[x],
                                       &drawable->depend_items[x], drawable);
 
             if (drawable->surface_deps[x] == 0) {
@@ -2664,7 +2582,7 @@ static inline int red_handle_surfaces_dependencies(RedWorker *worker, Drawable *
     return TRUE;
 }
 
-static inline void red_inc_surfaces_drawable_dependencies(RedWorker *worker, Drawable *drawable)
+static inline void red_inc_surfaces_drawable_dependencies(DisplayChannel *display, Drawable *drawable)
 {
     int x;
     int surface_id;
@@ -2675,7 +2593,7 @@ static inline void red_inc_surfaces_drawable_dependencies(RedWorker *worker, Dra
         if (surface_id == -1) {
             continue;
         }
-        surface = &worker->surfaces[surface_id];
+        surface = &display->surfaces[surface_id];
         surface->refs++;
     }
 }
@@ -2694,7 +2612,7 @@ static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable
     red_drawable->mm_time = reds_get_mm_time();
     surface_id = drawable->surface_id;
 
-    worker->surfaces[surface_id].refs++;
+    display->surfaces[surface_id].refs++;
 
     region_add(&drawable->tree_item.base.rgn, &red_drawable->bbox);
 
@@ -2706,13 +2624,14 @@ static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable
         region_and(&drawable->tree_item.base.rgn, &rgn);
         region_destroy(&rgn);
     }
+
     /*
         surface->refs is affected by a drawable (that is
         dependent on the surface) as long as the drawable is alive.
         However, surface->depend_on_me is affected by a drawable only
         as long as it is in the current tree (hasn't been rendered yet).
     */
-    red_inc_surfaces_drawable_dependencies(worker, drawable);
+    red_inc_surfaces_drawable_dependencies(worker->display_channel, drawable);
 
     if (region_is_empty(&drawable->tree_item.base.rgn)) {
         goto cleanup;
@@ -2722,38 +2641,36 @@ static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable
         goto cleanup;
     }
 
-    if (!red_handle_depends_on_target_surface(worker, surface_id)) {
+    if (!red_handle_depends_on_target_surface(worker->display_channel, surface_id)) {
         goto cleanup;
     }
 
-    if (!red_handle_surfaces_dependencies(worker, drawable)) {
+    if (!red_handle_surfaces_dependencies(worker->display_channel, drawable)) {
         goto cleanup;
     }
 
-    if (red_add_drawable(worker, drawable)) {
-        red_pipes_add_drawable(worker, drawable);
+    if (red_add_drawable(worker->display_channel, drawable)) {
+        red_pipes_add_drawable(worker->display_channel, drawable);
     }
 cleanup:
     display_channel_drawable_unref(display, drawable);
 }
 
-static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
-                                      uint32_t height, int32_t stride, uint32_t format,
-                                      void *line_0, int data_is_valid, int send_client);
 
 static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface,
                                        uint32_t group_id, int loadvm)
 {
+    DisplayChannel *display = worker->display_channel;
     uint32_t surface_id;
     RedSurface *red_surface;
     uint8_t *data;
 
     surface_id = surface->surface_id;
-    if SPICE_UNLIKELY(surface_id >= worker->n_surfaces) {
+    if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
         goto exit;
     }
 
-    red_surface = &worker->surfaces[surface_id];
+    red_surface = &display->surfaces[surface_id];
 
     switch (surface->type) {
     case QXL_SURFACE_CMD_CREATE: {
@@ -2769,7 +2686,7 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
         if (stride < 0) {
             data -= (int32_t)(stride * (height - 1));
         }
-        red_create_surface(worker, surface_id, surface->u.surface_create.width,
+        red_create_surface(worker->display_channel, surface_id, surface->u.surface_create.width,
                            height, stride, surface->u.surface_create.format, data,
                            reloaded_surface,
                            // reloaded surfaces will be sent on demand
@@ -2783,13 +2700,13 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
             break;
         }
         set_surface_release_info(&red_surface->destroy, surface->release_info, group_id);
-        red_handle_depends_on_target_surface(worker, surface_id);
-        /* note that red_handle_depends_on_target_surface must be called before red_current_clear.
+        red_handle_depends_on_target_surface(display, surface_id);
+        /* note that red_handle_depends_on_target_surface must be called before current_clear.
            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, surface_id);
-        red_clear_surface_drawables_from_pipes(worker, surface_id, FALSE);
-        red_surface_unref(worker, surface_id);
+        current_clear(display, surface_id);
+        red_clear_surface_drawables_from_pipes(display, surface_id, FALSE);
+        display_channel_surface_unref(display, surface_id);
         break;
     default:
             spice_error("unknown surface command");
@@ -2802,31 +2719,30 @@ exit:
 static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces,
                                        uint32_t surface_id)
 {
-    RedWorker *worker;
+    DisplayChannel *display;
 
-    worker = SPICE_CONTAINEROF(surfaces, RedWorker, image_surfaces);
-    VALIDATE_SURFACE_RETVAL(worker, surface_id, NULL);
+    display = SPICE_CONTAINEROF(surfaces, DisplayChannel, image_surfaces);
+    VALIDATE_SURFACE_RETVAL(display, surface_id, NULL);
 
-    return worker->surfaces[surface_id].context.canvas;
+    return display->surfaces[surface_id].context.canvas;
 }
 
-static void image_surface_init(RedWorker *worker)
+static void image_surface_init(DisplayChannel *display)
 {
     static SpiceImageSurfacesOps image_surfaces_ops = {
         image_surfaces_get,
     };
 
-    worker->image_surfaces.ops = &image_surfaces_ops;
+    display->image_surfaces.ops = &image_surfaces_ops;
 }
 
-static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
+static void red_draw_qxl_drawable(DisplayChannel *display, Drawable *drawable)
 {
-    DisplayChannel *display = worker->display_channel;
     RedSurface *surface;
     SpiceCanvas *canvas;
     SpiceClip clip = drawable->red_drawable->clip;
 
-    surface = &worker->surfaces[drawable->surface_id];
+    surface = &display->surfaces[drawable->surface_id];
     canvas = surface->context.canvas;
 
     image_cache_aging(&display->image_cache);
@@ -2957,17 +2873,17 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     }
 }
 
-static void red_draw_drawable(RedWorker *worker, Drawable *drawable)
+static void red_draw_drawable(DisplayChannel *display, Drawable *drawable)
 {
-    red_flush_source_surfaces(worker, drawable);
-    red_draw_qxl_drawable(worker, drawable);
+    red_flush_source_surfaces(display, drawable);
+    red_draw_qxl_drawable(display, drawable);
 }
 
-static void validate_area(RedWorker *worker, const SpiceRect *area, uint32_t surface_id)
+static void validate_area(DisplayChannel *display, const SpiceRect *area, uint32_t surface_id)
 {
     RedSurface *surface;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &display->surfaces[surface_id];
     if (!surface->context.canvas_draws_on_surface) {
         SpiceCanvas *canvas = surface->context.canvas;
         int h;
@@ -2989,10 +2905,9 @@ static void validate_area(RedWorker *worker, const SpiceRect *area, uint32_t sur
     Renders drawables for updating the requested area, but only drawables that are older
     than 'last' (exclusive).
 */
-static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int surface_id,
+static void red_update_area_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
                                  Drawable *last)
 {
-    DisplayChannel *display = worker->display_channel;
     RedSurface *surface;
     Drawable *surface_last = NULL;
     Ring *ring;
@@ -3003,7 +2918,7 @@ static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int s
     spice_assert(last);
     spice_assert(ring_item_is_linked(&last->list_link));
 
-    surface = &worker->surfaces[surface_id];
+    surface = &display->surfaces[surface_id];
 
     if (surface_id != last->surface_id) {
         // find the nearest older drawable from the appropriate surface
@@ -3055,22 +2970,21 @@ static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int s
         now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
         now->refs++;
         container = now->tree_item.base.container;
-        current_remove_drawable(worker, now);
+        current_remove_drawable(display, now);
         container_cleanup(container);
         /* red_draw_drawable may call red_update_area for the surfaces 'now' depends on. Notice,
            that it is valid to call red_update_area in this case and not red_update_area_till:
            It is impossible that there was newer item then 'last' in one of the surfaces
            that red_update_area is called for, Otherwise, 'now' would have already been rendered.
            See the call for red_handle_depends_on_target_surface in red_process_draw */
-        red_draw_drawable(worker, now);
+        red_draw_drawable(display, now);
         display_channel_drawable_unref(display, now);
     } while (now != surface_last);
-    validate_area(worker, area, surface_id);
+    validate_area(display, area, surface_id);
 }
 
-static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id)
+static void red_update_area(DisplayChannel *display, const SpiceRect *area, int surface_id)
 {
-    DisplayChannel *display = worker->display_channel;
     RedSurface *surface;
     Ring *ring;
     RingItem *ring_item;
@@ -3085,7 +2999,7 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
     spice_return_if_fail(area->left >= 0 && area->top >= 0 &&
                          area->left < area->right && area->top < area->bottom);
 
-    surface = &worker->surfaces[surface_id];
+    surface = &display->surfaces[surface_id];
 
     last = NULL;
     ring = &surface->current_list;
@@ -3103,7 +3017,7 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
     region_destroy(&rgn);
 
     if (!last) {
-        validate_area(worker, area, surface_id);
+        validate_area(display, area, surface_id);
         return;
     }
 
@@ -3114,12 +3028,12 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
         now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
         now->refs++;
         container = now->tree_item.base.container;
-        current_remove_drawable(worker, now);
+        current_remove_drawable(display, now);
         container_cleanup(container);
-        red_draw_drawable(worker, now);
+        red_draw_drawable(display, now);
         display_channel_drawable_unref(display, now);
     } while (now != last);
-    validate_area(worker, area, surface_id);
+    validate_area(display, area, surface_id);
 }
 
 static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
@@ -3238,11 +3152,11 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
                                    &update, ext_cmd.cmd.data)) {
                 break;
             }
-            if (!validate_surface(worker, update.surface_id)) {
+            if (!validate_surface(worker->display_channel, update.surface_id)) {
                 rendering_incorrect("QXL_CMD_UPDATE");
                 break;
             }
-            red_update_area(worker, &update.area, update.surface_id);
+            red_update_area(worker->display_channel, &update.area, update.surface_id);
             worker->qxl->st->qif->notify_update(worker->qxl, update.update_id);
             release_info_ext.group_id = ext_cmd.group_id;
             release_info_ext.info = update.release_info;
@@ -3316,7 +3230,7 @@ static void red_free_some(RedWorker *worker)
     }
 
     while (!ring_is_empty(&display->current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
-        free_one_drawable(worker, TRUE);
+        free_one_drawable(display, TRUE);
     }
 
     FOREACH_DCC(worker->display_channel, item, next, dcc) {
@@ -3328,12 +3242,12 @@ static void red_free_some(RedWorker *worker)
     }
 }
 
-static void red_current_flush(RedWorker *worker, int surface_id)
+static void red_current_flush(DisplayChannel *display, int surface_id)
 {
-    while (!ring_is_empty(&worker->surfaces[surface_id].current_list)) {
-        free_one_drawable(worker, FALSE);
+    while (!ring_is_empty(&display->surfaces[surface_id].current_list)) {
+        free_one_drawable(display, FALSE);
     }
-    red_current_clear(worker, surface_id);
+    current_clear(display, surface_id);
 }
 
 // adding the pipe item after pos. If pos == NULL, adding to head.
@@ -3342,8 +3256,7 @@ static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surf
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
     RedChannel *channel = RED_CHANNEL(display);
-    RedWorker *worker = DCC_TO_WORKER(dcc);
-    RedSurface *surface = &worker->surfaces[surface_id];
+    RedSurface *surface = &display->surfaces[surface_id];
     SpiceCanvas *canvas = surface->context.canvas;
     ImageItem *item;
     int stride;
@@ -3403,15 +3316,11 @@ static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surf
 
 static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id)
 {
+    DisplayChannel *display = DCC_TO_DC(dcc);
     SpiceRect area;
     RedSurface *surface;
-    RedWorker *worker;
 
-    if (!dcc) {
-        return;
-    }
-    worker = DCC_TO_WORKER(dcc);
-    surface = &worker->surfaces[surface_id];
+    surface = &display->surfaces[surface_id];
     if (!surface->context.canvas) {
         return;
     }
@@ -4838,8 +4747,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
                               SpiceImage *simage, Drawable *drawable, int can_lossy)
 {
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
-    RedWorker *worker = DCC_TO_WORKER(dcc);
+    DisplayChannel *display = DCC_TO_DC(dcc);
     SpiceImage image;
     compress_send_data_t comp_send_data = {0};
     SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out;
@@ -4862,7 +4770,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
             dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] =
                                                                                image.descriptor.id;
             if (can_lossy || !lossy_cache_item) {
-                if (!display_channel->enable_jpeg || lossy_cache_item) {
+                if (!display->enable_jpeg || lossy_cache_item) {
                     image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
                 } else {
                     // making sure, in multiple monitor scenario, that lossy items that
@@ -4874,7 +4782,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
                                      &bitmap_palette_out, &lzplt_palette_out);
                 spice_assert(bitmap_palette_out == NULL);
                 spice_assert(lzplt_palette_out == NULL);
-                stat_inc_counter(display_channel->cache_hits_counter, 1);
+                stat_inc_counter(display->cache_hits_counter, 1);
                 pthread_mutex_unlock(&dcc->pixmap_cache->lock);
                 return FILL_BITS_TYPE_CACHE;
             } else {
@@ -4891,13 +4799,13 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
         RedSurface *surface;
 
         surface_id = simage->u.surface.surface_id;
-        if (!validate_surface(worker, surface_id)) {
+        if (!validate_surface(display, surface_id)) {
             rendering_incorrect("SPICE_IMAGE_TYPE_SURFACE");
             pthread_mutex_unlock(&dcc->pixmap_cache->lock);
             return FILL_BITS_TYPE_SURFACE;
         }
 
-        surface = &worker->surfaces[surface_id];
+        surface = &display->surfaces[surface_id];
         image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
         image.descriptor.flags = 0;
         image.descriptor.width = surface->context.width;
@@ -4984,16 +4892,16 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
 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);
+    DisplayChannel *display = DCC_TO_DC(dcc);
 
     if (mask_bitmap && m) {
-        if (display_channel->common.worker->image_compression != SPICE_IMAGE_COMPRESSION_OFF) {
+        if (display->common.worker->image_compression != SPICE_IMAGE_COMPRESSION_OFF) {
             SpiceImageCompression save_img_comp =
-                display_channel->common.worker->image_compression;
-            display_channel->common.worker->image_compression = SPICE_IMAGE_COMPRESSION_OFF;
+                display->common.worker->image_compression;
+            display->common.worker->image_compression = SPICE_IMAGE_COMPRESSION_OFF;
             fill_bits(dcc, m, mask_bitmap, drawable, FALSE);
-            display_channel->common.worker->image_compression = save_img_comp;
+            display->common.worker->image_compression = save_img_comp;
         } else {
             fill_bits(dcc, m, mask_bitmap, drawable, FALSE);
         }
@@ -5026,10 +4934,10 @@ static int is_surface_area_lossy(DisplayChannelClient *dcc, uint32_t surface_id,
     RedSurface *surface;
     QRegion *surface_lossy_region;
     QRegion lossy_region;
-    RedWorker *worker = DCC_TO_WORKER(dcc);
+    DisplayChannel *display = DCC_TO_DC(dcc);
 
-    VALIDATE_SURFACE_RETVAL(worker, surface_id, FALSE);
-    surface = &worker->surfaces[surface_id];
+    VALIDATE_SURFACE_RETVAL(display, surface_id, FALSE);
+    surface = &display->surfaces[surface_id];
     surface_lossy_region = &dcc->surface_client_lossy_region[surface_id];
 
     if (!area) {
@@ -5119,7 +5027,7 @@ static int is_brush_lossy(RedChannelClient *rcc, SpiceBrush *brush,
     }
 }
 
-static void surface_lossy_region_update(RedWorker *worker, DisplayChannelClient *dcc,
+static void surface_lossy_region_update(DisplayChannelClient *dcc,
                                         Drawable *item, int has_mask, int lossy)
 {
     QRegion *surface_lossy_region;
@@ -5230,8 +5138,7 @@ static inline int drawable_depends_on_areas(Drawable *drawable,
 }
 
 
-static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
-                                                        DisplayChannelClient *dcc,
+static int pipe_rendered_drawables_intersect_with_areas(DisplayChannelClient *dcc,
                                                         int surface_ids[],
                                                         SpiceRect *surface_areas[],
                                                         int num_surfaces)
@@ -5263,8 +5170,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
     return FALSE;
 }
 
-static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
-                                                            DisplayChannelClient *dcc,
+static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient *dcc,
                                                             int first_surface_id,
                                                             SpiceRect *first_area)
 {
@@ -5319,15 +5225,15 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
     }
 }
 
-static void red_add_lossless_drawable_dependencies(RedWorker *worker,
-                                                   RedChannelClient *rcc,
+static void red_add_lossless_drawable_dependencies(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);
+    DisplayChannel *display = DCC_TO_DC(dcc);
+    RedDrawable *drawable = item->red_drawable;
     int sync_rendered = FALSE;
     int i;
 
@@ -5340,7 +5246,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, dcc,
+            if (pipe_rendered_drawables_intersect_with_areas(dcc,
                                                              deps_surfaces_ids,
                                                              deps_areas,
                                                              num_deps)) {
@@ -5352,7 +5258,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, deps_areas[i],
+            red_update_area_till(display, deps_areas[i],
                                  deps_surfaces_ids[i], item);
         }
     }
@@ -5375,11 +5281,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, dcc,
+        if (pipe_rendered_drawables_intersect_with_areas(dcc,
                                                          drawable_surface_id,
                                                          drawable_bbox,
                                                          1)) {
-            red_pipe_replace_rendered_drawables_with_images(worker, dcc,
+            red_pipe_replace_rendered_drawables_with_images(dcc,
                                                             drawable->surface_id,
                                                             &drawable->bbox);
         }
@@ -5389,10 +5295,9 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
     }
 }
 
-static void red_marshall_qxl_draw_fill(RedWorker *worker,
-                                   RedChannelClient *rcc,
-                                   SpiceMarshaller *base_marshaller,
-                                   DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_fill(RedChannelClient *rcc,
+                                       SpiceMarshaller *base_marshaller,
+                                       DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
@@ -5417,13 +5322,12 @@ static void red_marshall_qxl_draw_fill(RedWorker *worker,
 }
 
 
-static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
-                                         RedChannelClient *rcc,
-                                         SpiceMarshaller *m,
-                                         DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_fill(RedChannelClient *rcc,
+                                             SpiceMarshaller *m,
+                                             DrawablePipeItem *dpi)
 {
-    Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
 
     int dest_allowed_lossy = FALSE;
@@ -5450,9 +5354,9 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
         !(brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE))) {
         int has_mask = !!drawable->u.fill.mask.bitmap;
 
-        red_marshall_qxl_draw_fill(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_fill(rcc, m, dpi);
         // either the brush operation is opaque, or the dest is not lossy
-        surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
+        surface_lossy_region_update(dcc, item, has_mask, FALSE);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -5470,18 +5374,17 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, rcc, item,
+        red_add_lossless_drawable_dependencies(rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
 
-static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
-                                             RedChannelClient *rcc,
-                                             SpiceMarshaller *base_marshaller,
-                                             DrawablePipeItem *dpi, int src_allowed_lossy)
+static FillBitsType red_marshall_qxl_draw_opaque(RedChannelClient *rcc,
+                                                 SpiceMarshaller *base_marshaller,
+                                                 DrawablePipeItem *dpi, int src_allowed_lossy)
 {
-    Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *src_bitmap_out;
@@ -5509,13 +5412,12 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
     return src_send_type;
 }
 
-static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
-                                           RedChannelClient *rcc,
-                                           SpiceMarshaller *m,
-                                           DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_opaque(RedChannelClient *rcc,
+                                               SpiceMarshaller *m,
+                                               DrawablePipeItem *dpi)
 {
-    Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
 
     int src_allowed_lossy;
@@ -5545,14 +5447,14 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
         FillBitsType src_send_type;
         int has_mask = !!drawable->u.opaque.mask.bitmap;
 
-        src_send_type = red_marshall_qxl_draw_opaque(worker, rcc, m, dpi, src_allowed_lossy);
+        src_send_type = red_marshall_qxl_draw_opaque(rcc, m, dpi, src_allowed_lossy);
         if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
             src_is_lossy = TRUE;
         } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) {
             src_is_lossy = FALSE;
         }
 
-        surface_lossy_region_update(worker, dcc, item, has_mask, src_is_lossy);
+        surface_lossy_region_update(dcc, item, has_mask, src_is_lossy);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -5570,19 +5472,18 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, rcc, item,
+        red_add_lossless_drawable_dependencies(rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
 
-static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
-                                           RedChannelClient *rcc,
-                                           SpiceMarshaller *base_marshaller,
-                                           DrawablePipeItem *dpi, int src_allowed_lossy)
+static FillBitsType red_marshall_qxl_draw_copy(RedChannelClient *rcc,
+                                               SpiceMarshaller *base_marshaller,
+                                               DrawablePipeItem *dpi, int src_allowed_lossy)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
-    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceCopy copy;
@@ -5602,13 +5503,12 @@ static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
     return src_send_type;
 }
 
-static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
-                                         RedChannelClient *rcc,
-                                         SpiceMarshaller *base_marshaller,
-                                         DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_copy(RedChannelClient *rcc,
+                                             SpiceMarshaller *base_marshaller,
+                                             DrawablePipeItem *dpi)
 {
-    Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.copy.mask.bitmap;
     int src_is_lossy;
@@ -5618,23 +5518,22 @@ static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
     src_is_lossy = is_bitmap_lossy(rcc, drawable->u.copy.src_bitmap,
                                    &drawable->u.copy.src_area, item, &src_bitmap_data);
 
-    src_send_type = red_marshall_qxl_draw_copy(worker, rcc, base_marshaller, dpi, TRUE);
+    src_send_type = red_marshall_qxl_draw_copy(rcc, base_marshaller, dpi, TRUE);
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
     } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) {
         src_is_lossy = FALSE;
     }
-    surface_lossy_region_update(worker, dcc, item, has_mask,
+    surface_lossy_region_update(dcc, item, has_mask,
                                 src_is_lossy);
 }
 
-static void red_marshall_qxl_draw_transparent(RedWorker *worker,
-                                          RedChannelClient *rcc,
-                                          SpiceMarshaller *base_marshaller,
-                                          DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_transparent(RedChannelClient *rcc,
+                                              SpiceMarshaller *base_marshaller,
+                                              DrawablePipeItem *dpi)
 {
-    Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *src_bitmap_out;
     SpiceTransparent transparent;
@@ -5649,10 +5548,9 @@ static void red_marshall_qxl_draw_transparent(RedWorker *worker,
     fill_bits(dcc, src_bitmap_out, transparent.src_bitmap, item, FALSE);
 }
 
-static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
-                                                RedChannelClient *rcc,
-                                                SpiceMarshaller *base_marshaller,
-                                                DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_transparent(RedChannelClient *rcc,
+                                                    SpiceMarshaller *base_marshaller,
+                                                    DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
@@ -5663,7 +5561,7 @@ static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
                                    &drawable->u.transparent.src_area, item, &src_bitmap_data);
 
     if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) {
-        red_marshall_qxl_draw_transparent(worker, rcc, base_marshaller, dpi);
+        red_marshall_qxl_draw_transparent(rcc, base_marshaller, dpi);
         // don't update surface lossy region since transperent areas might be lossy
     } else {
         int resend_surface_ids[1];
@@ -5672,16 +5570,15 @@ 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, rcc, item,
+        red_add_lossless_drawable_dependencies(rcc, item,
                                                resend_surface_ids, resend_areas, 1);
     }
 }
 
-static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
-                                                  RedChannelClient *rcc,
-                                                  SpiceMarshaller *base_marshaller,
-                                                  DrawablePipeItem *dpi,
-                                                  int src_allowed_lossy)
+static FillBitsType red_marshall_qxl_draw_alpha_blend(RedChannelClient *rcc,
+                                                      SpiceMarshaller *base_marshaller,
+                                                      DrawablePipeItem *dpi,
+                                                      int src_allowed_lossy)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -5703,10 +5600,9 @@ static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
     return src_send_type;
 }
 
-static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
-                                                RedChannelClient *rcc,
-                                                SpiceMarshaller *base_marshaller,
-                                                DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_alpha_blend(RedChannelClient *rcc,
+                                                    SpiceMarshaller *base_marshaller,
+                                                    DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -5718,7 +5614,7 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
     src_is_lossy = is_bitmap_lossy(rcc, drawable->u.alpha_blend.src_bitmap,
                                    &drawable->u.alpha_blend.src_area, item, &src_bitmap_data);
 
-    src_send_type = red_marshall_qxl_draw_alpha_blend(worker, rcc, base_marshaller, dpi, TRUE);
+    src_send_type = red_marshall_qxl_draw_alpha_blend(rcc, base_marshaller, dpi, TRUE);
 
     if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
         src_is_lossy = TRUE;
@@ -5727,14 +5623,13 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
     }
 
     if (src_is_lossy) {
-        surface_lossy_region_update(worker, dcc, item, FALSE, src_is_lossy);
+        surface_lossy_region_update(dcc, item, FALSE, src_is_lossy);
     } // else, the area stays lossy/lossless as the destination
 }
 
-static void red_marshall_qxl_copy_bits(RedWorker *worker,
-                                   RedChannelClient *rcc,
-                                   SpiceMarshaller *base_marshaller,
-                                   DrawablePipeItem *dpi)
+static void red_marshall_qxl_copy_bits(RedChannelClient *rcc,
+                                       SpiceMarshaller *base_marshaller,
+                                       DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
@@ -5747,10 +5642,9 @@ static void red_marshall_qxl_copy_bits(RedWorker *worker,
                          &copy_bits);
 }
 
-static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
-                                         RedChannelClient *rcc,
-                                         SpiceMarshaller *base_marshaller,
-                                         DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_copy_bits(RedChannelClient *rcc,
+                                             SpiceMarshaller *base_marshaller,
+                                             DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -5761,7 +5655,7 @@ static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
     int src_is_lossy;
     SpiceRect src_lossy_area;
 
-    red_marshall_qxl_copy_bits(worker, rcc, base_marshaller, dpi);
+    red_marshall_qxl_copy_bits(rcc, base_marshaller, dpi);
 
     horz_offset = drawable->u.copy_bits.src_pos.x - drawable->bbox.left;
     vert_offset = drawable->u.copy_bits.src_pos.y - drawable->bbox.top;
@@ -5774,14 +5668,12 @@ static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
     src_is_lossy = is_surface_area_lossy(dcc, item->surface_id,
                                          &src_rect, &src_lossy_area);
 
-    surface_lossy_region_update(worker, dcc, item, FALSE,
-                                src_is_lossy);
+    surface_lossy_region_update(dcc, item, FALSE, src_is_lossy);
 }
 
-static void red_marshall_qxl_draw_blend(RedWorker *worker,
-                                    RedChannelClient *rcc,
-                                    SpiceMarshaller *base_marshaller,
-                                    DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_blend(RedChannelClient *rcc,
+                                        SpiceMarshaller *base_marshaller,
+                                        DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -5803,10 +5695,9 @@ static void red_marshall_qxl_draw_blend(RedWorker *worker,
     fill_mask(rcc, mask_bitmap_out, blend.mask.bitmap, item);
 }
 
-static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
-                                          RedChannelClient *rcc,
-                                          SpiceMarshaller *base_marshaller,
-                                          DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_blend(RedChannelClient *rcc,
+                                              SpiceMarshaller *base_marshaller,
+                                              DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -5823,7 +5714,7 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
 
     if (!dest_is_lossy &&
         (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
-        red_marshall_qxl_draw_blend(worker, rcc, base_marshaller, dpi);
+        red_marshall_qxl_draw_blend(rcc, base_marshaller, dpi);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -5841,15 +5732,14 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, rcc, item,
+        red_add_lossless_drawable_dependencies(rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
 
-static void red_marshall_qxl_draw_blackness(RedWorker *worker,
-                                        RedChannelClient *rcc,
-                                        SpiceMarshaller *base_marshaller,
-                                        DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_blackness(RedChannelClient *rcc,
+                                            SpiceMarshaller *base_marshaller,
+                                            DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
@@ -5867,25 +5757,23 @@ static void red_marshall_qxl_draw_blackness(RedWorker *worker,
     fill_mask(rcc, mask_bitmap_out, blackness.mask.bitmap, item);
 }
 
-static void red_lossy_marshall_qxl_draw_blackness(RedWorker *worker,
-                                              RedChannelClient *rcc,
-                                              SpiceMarshaller *base_marshaller,
-                                              DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_blackness(RedChannelClient *rcc,
+                                                  SpiceMarshaller *base_marshaller,
+                                                  DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     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, dpi);
+    red_marshall_qxl_draw_blackness(rcc, base_marshaller, dpi);
 
-    surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
+    surface_lossy_region_update(dcc, item, has_mask, FALSE);
 }
 
-static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
-                                        RedChannelClient *rcc,
-                                        SpiceMarshaller *base_marshaller,
-                                        DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_whiteness(RedChannelClient *rcc,
+                                            SpiceMarshaller *base_marshaller,
+                                            DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
@@ -5903,25 +5791,23 @@ static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
     fill_mask(rcc, mask_bitmap_out, whiteness.mask.bitmap, item);
 }
 
-static void red_lossy_marshall_qxl_draw_whiteness(RedWorker *worker,
-                                              RedChannelClient *rcc,
-                                              SpiceMarshaller *base_marshaller,
-                                              DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_whiteness(RedChannelClient *rcc,
+                                                  SpiceMarshaller *base_marshaller,
+                                                  DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     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, dpi);
+    red_marshall_qxl_draw_whiteness(rcc, base_marshaller, dpi);
 
-    surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
+    surface_lossy_region_update(dcc, item, has_mask, FALSE);
 }
 
-static void red_marshall_qxl_draw_inverse(RedWorker *worker,
-                                        RedChannelClient *rcc,
-                                        SpiceMarshaller *base_marshaller,
-                                        Drawable *item)
+static void red_marshall_qxl_draw_inverse(RedChannelClient *rcc,
+                                          SpiceMarshaller *base_marshaller,
+                                          Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *mask_bitmap_out;
@@ -5938,18 +5824,16 @@ static void red_marshall_qxl_draw_inverse(RedWorker *worker,
     fill_mask(rcc, mask_bitmap_out, inverse.mask.bitmap, item);
 }
 
-static void red_lossy_marshall_qxl_draw_inverse(RedWorker *worker,
-                                            RedChannelClient *rcc,
-                                            SpiceMarshaller *base_marshaller,
-                                            Drawable *item)
+static void red_lossy_marshall_qxl_draw_inverse(RedChannelClient *rcc,
+                                                SpiceMarshaller *base_marshaller,
+                                                Drawable *item)
 {
-    red_marshall_qxl_draw_inverse(worker, rcc, base_marshaller, item);
+    red_marshall_qxl_draw_inverse(rcc, base_marshaller, item);
 }
 
-static void red_marshall_qxl_draw_rop3(RedWorker *worker,
-                                   RedChannelClient *rcc,
-                                   SpiceMarshaller *base_marshaller,
-                                   DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_rop3(RedChannelClient *rcc,
+                                       SpiceMarshaller *base_marshaller,
+                                       DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -5976,10 +5860,9 @@ static void red_marshall_qxl_draw_rop3(RedWorker *worker,
     fill_mask(rcc, mask_bitmap_out, rop3.mask.bitmap, item);
 }
 
-static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
-                                         RedChannelClient *rcc,
-                                         SpiceMarshaller *base_marshaller,
-                                         DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_rop3(RedChannelClient *rcc,
+                                             SpiceMarshaller *base_marshaller,
+                                             DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -6002,8 +5885,8 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
         (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
         !dest_is_lossy) {
         int has_mask = !!drawable->u.rop3.mask.bitmap;
-        red_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, dpi);
-        surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
+        red_marshall_qxl_draw_rop3(rcc, base_marshaller, dpi);
+        surface_lossy_region_update(dcc, item, has_mask, FALSE);
     } else {
         int resend_surface_ids[3];
         SpiceRect *resend_areas[3];
@@ -6027,15 +5910,14 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, rcc, item,
+        red_add_lossless_drawable_dependencies(rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
 
-static void red_marshall_qxl_draw_composite(RedWorker *worker,
-                                     RedChannelClient *rcc,
-                                     SpiceMarshaller *base_marshaller,
-                                     DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_composite(RedChannelClient *rcc,
+                                            SpiceMarshaller *base_marshaller,
+                                            DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -6058,8 +5940,7 @@ static void red_marshall_qxl_draw_composite(RedWorker *worker,
     }
 }
 
-static void red_lossy_marshall_qxl_draw_composite(RedWorker *worker,
-                                                  RedChannelClient *rcc,
+static void red_lossy_marshall_qxl_draw_composite(RedChannelClient *rcc,
                                                   SpiceMarshaller *base_marshaller,
                                                   DrawablePipeItem *dpi)
 {
@@ -6084,8 +5965,8 @@ static void red_lossy_marshall_qxl_draw_composite(RedWorker *worker,
     if ((!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))   &&
         (!mask_is_lossy || (mask_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
         !dest_is_lossy) {
-        red_marshall_qxl_draw_composite(worker, rcc, base_marshaller, dpi);
-        surface_lossy_region_update(worker, dcc, item, FALSE, FALSE);
+        red_marshall_qxl_draw_composite(rcc, base_marshaller, dpi);
+        surface_lossy_region_update(dcc, item, FALSE, FALSE);
     }
     else {
         int resend_surface_ids[3];
@@ -6110,15 +5991,14 @@ static void red_lossy_marshall_qxl_draw_composite(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, rcc, item,
+        red_add_lossless_drawable_dependencies(rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
 
-static void red_marshall_qxl_draw_stroke(RedWorker *worker,
-                                     RedChannelClient *rcc,
-                                     SpiceMarshaller *base_marshaller,
-                                     DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_stroke(RedChannelClient *rcc,
+                                         SpiceMarshaller *base_marshaller,
+                                         DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -6141,10 +6021,9 @@ static void red_marshall_qxl_draw_stroke(RedWorker *worker,
     }
 }
 
-static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
-                                           RedChannelClient *rcc,
-                                           SpiceMarshaller *base_marshaller,
-                                           DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_stroke(RedChannelClient *rcc,
+                                               SpiceMarshaller *base_marshaller,
+                                               DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -6173,7 +6052,7 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
     if (!dest_is_lossy &&
         (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)))
     {
-        red_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, dpi);
+        red_marshall_qxl_draw_stroke(rcc, base_marshaller, dpi);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -6192,15 +6071,14 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, rcc, item,
+        red_add_lossless_drawable_dependencies(rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
 
-static void red_marshall_qxl_draw_text(RedWorker *worker,
-                                   RedChannelClient *rcc,
-                                   SpiceMarshaller *base_marshaller,
-                                   DrawablePipeItem *dpi)
+static void red_marshall_qxl_draw_text(RedChannelClient *rcc,
+                                       SpiceMarshaller *base_marshaller,
+                                       DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -6225,10 +6103,9 @@ static void red_marshall_qxl_draw_text(RedWorker *worker,
     }
 }
 
-static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
-                                         RedChannelClient *rcc,
-                                         SpiceMarshaller *base_marshaller,
-                                         DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_draw_text(RedChannelClient *rcc,
+                                             SpiceMarshaller *base_marshaller,
+                                             DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -6265,7 +6142,7 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
     if (!dest_is_lossy &&
         (!fg_is_lossy || (fg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
         (!bg_is_lossy || (bg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
-        red_marshall_qxl_draw_text(worker, rcc, base_marshaller, dpi);
+        red_marshall_qxl_draw_text(rcc, base_marshaller, dpi);
     } else {
         int resend_surface_ids[3];
         SpiceRect *resend_areas[3];
@@ -6288,111 +6165,112 @@ 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, rcc, item,
+        red_add_lossless_drawable_dependencies(rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
 
-static void red_lossy_marshall_qxl_drawable(RedWorker *worker, RedChannelClient *rcc,
-                                        SpiceMarshaller *base_marshaller, DrawablePipeItem *dpi)
+static void red_lossy_marshall_qxl_drawable(RedChannelClient *rcc,
+                                            SpiceMarshaller *base_marshaller,
+                                            DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     switch (item->red_drawable->type) {
     case QXL_DRAW_FILL:
-        red_lossy_marshall_qxl_draw_fill(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_fill(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_OPAQUE:
-        red_lossy_marshall_qxl_draw_opaque(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_opaque(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_COPY:
-        red_lossy_marshall_qxl_draw_copy(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_copy(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_TRANSPARENT:
-        red_lossy_marshall_qxl_draw_transparent(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_transparent(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_ALPHA_BLEND:
-        red_lossy_marshall_qxl_draw_alpha_blend(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_alpha_blend(rcc, base_marshaller, dpi);
         break;
     case QXL_COPY_BITS:
-        red_lossy_marshall_qxl_copy_bits(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_copy_bits(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_BLEND:
-        red_lossy_marshall_qxl_draw_blend(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_blend(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_BLACKNESS:
-        red_lossy_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_blackness(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_WHITENESS:
-        red_lossy_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_whiteness(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_INVERS:
-        red_lossy_marshall_qxl_draw_inverse(worker, rcc, base_marshaller, item);
+        red_lossy_marshall_qxl_draw_inverse(rcc, base_marshaller, item);
         break;
     case QXL_DRAW_ROP3:
-        red_lossy_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_rop3(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_COMPOSITE:
-        red_lossy_marshall_qxl_draw_composite(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_composite(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_STROKE:
-        red_lossy_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_stroke(rcc, base_marshaller, dpi);
         break;
     case QXL_DRAW_TEXT:
-        red_lossy_marshall_qxl_draw_text(worker, rcc, base_marshaller, dpi);
+        red_lossy_marshall_qxl_draw_text(rcc, base_marshaller, dpi);
         break;
     default:
         spice_error("invalid type");
     }
 }
 
-static inline void red_marshall_qxl_drawable(RedWorker *worker, RedChannelClient *rcc,
-                                SpiceMarshaller *m, DrawablePipeItem *dpi)
+static inline void red_marshall_qxl_drawable(RedChannelClient *rcc,
+                                             SpiceMarshaller *m, DrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
     RedDrawable *drawable = item->red_drawable;
 
     switch (drawable->type) {
     case QXL_DRAW_FILL:
-        red_marshall_qxl_draw_fill(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_fill(rcc, m, dpi);
         break;
     case QXL_DRAW_OPAQUE:
-        red_marshall_qxl_draw_opaque(worker, rcc, m, dpi, FALSE);
+        red_marshall_qxl_draw_opaque(rcc, m, dpi, FALSE);
         break;
     case QXL_DRAW_COPY:
-        red_marshall_qxl_draw_copy(worker, rcc, m, dpi, FALSE);
+        red_marshall_qxl_draw_copy(rcc, m, dpi, FALSE);
         break;
     case QXL_DRAW_TRANSPARENT:
-        red_marshall_qxl_draw_transparent(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_transparent(rcc, m, dpi);
         break;
     case QXL_DRAW_ALPHA_BLEND:
-        red_marshall_qxl_draw_alpha_blend(worker, rcc, m, dpi, FALSE);
+        red_marshall_qxl_draw_alpha_blend(rcc, m, dpi, FALSE);
         break;
     case QXL_COPY_BITS:
-        red_marshall_qxl_copy_bits(worker, rcc, m, dpi);
+        red_marshall_qxl_copy_bits(rcc, m, dpi);
         break;
     case QXL_DRAW_BLEND:
-        red_marshall_qxl_draw_blend(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_blend(rcc, m, dpi);
         break;
     case QXL_DRAW_BLACKNESS:
-        red_marshall_qxl_draw_blackness(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_blackness(rcc, m, dpi);
         break;
     case QXL_DRAW_WHITENESS:
-        red_marshall_qxl_draw_whiteness(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_whiteness(rcc, m, dpi);
         break;
     case QXL_DRAW_INVERS:
-        red_marshall_qxl_draw_inverse(worker, rcc, m, item);
+        red_marshall_qxl_draw_inverse(rcc, m, item);
         break;
     case QXL_DRAW_ROP3:
-        red_marshall_qxl_draw_rop3(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_rop3(rcc, m, dpi);
         break;
     case QXL_DRAW_STROKE:
-        red_marshall_qxl_draw_stroke(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_stroke(rcc, m, dpi);
         break;
     case QXL_DRAW_COMPOSITE:
-        red_marshall_qxl_draw_composite(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_composite(rcc, m, dpi);
         break;
     case QXL_DRAW_TEXT:
-        red_marshall_qxl_draw_text(worker, rcc, m, dpi);
+        red_marshall_qxl_draw_text(rcc, m, dpi);
         break;
     default:
         spice_error("invalid type");
@@ -6691,9 +6569,9 @@ static inline void marshall_qxl_drawable(RedChannelClient *rcc,
         return;
     }
     if (!display_channel->enable_jpeg)
-        red_marshall_qxl_drawable(display_channel->common.worker, rcc, m, dpi);
+        red_marshall_qxl_drawable(rcc, m, dpi);
     else
-        red_lossy_marshall_qxl_drawable(display_channel->common.worker, rcc, m, dpi);
+        red_lossy_marshall_qxl_drawable(rcc, m, dpi);
 }
 
 static inline void red_marshall_inval_palette(RedChannelClient *rcc,
@@ -7249,24 +7127,6 @@ static inline void red_push(RedWorker *worker)
     }
 }
 
-void red_show_tree(RedWorker *worker)
-{
-    int x;
-
-    for (x = 0; x < NUM_SURFACES; ++x) {
-        if (!worker->surfaces[x].context.canvas)
-            continue;
-
-        RingItem *it;
-        Ring *ring = &worker->surfaces[x].current;
-        RING_FOREACH(it, ring) {
-            TreeItem *now = SPICE_CONTAINEROF(it, TreeItem, siblings_link);
-            tree_item_dump(now);
-        }
-
-    }
-}
-
 static void display_channel_client_on_disconnect(RedChannelClient *rcc)
 {
     DisplayChannel *display;
@@ -7344,15 +7204,15 @@ static void red_migrate_display(DisplayChannel *display, RedChannelClient *rcc)
 }
 
 #ifdef USE_OPENGL
-static SpiceCanvas *create_ogl_context_common(RedWorker *worker, OGLCtx *ctx, uint32_t width,
-                                              uint32_t height, int32_t stride, uint8_t depth)
+static SpiceCanvas *create_ogl_context_common(DisplayChannel *display, OGLCtx *ctx,
+                                              uint32_t width, uint32_t height,
+                                              int32_t stride, uint8_t depth)
 {
-    DisplayChannel *display = worker->display_channel;
     SpiceCanvas *canvas;
 
     oglctx_make_current(ctx);
     if (!(canvas = gl_canvas_create(width, height, depth, &display->image_cache.base,
-                                    &worker->image_surfaces, NULL, NULL, NULL))) {
+                                    &display->image_surfaces, NULL, NULL, NULL))) {
         return NULL;
     }
 
@@ -7363,8 +7223,8 @@ static SpiceCanvas *create_ogl_context_common(RedWorker *worker, OGLCtx *ctx, ui
     return canvas;
 }
 
-static SpiceCanvas *create_ogl_pbuf_context(RedWorker *worker, uint32_t width, uint32_t height,
-                                         int32_t stride, uint8_t depth)
+static SpiceCanvas *create_ogl_pbuf_context(DisplayChannel *display, uint32_t width,
+                                            uint32_t height, int32_t stride, uint8_t depth)
 {
     OGLCtx *ctx;
     SpiceCanvas *canvas;
@@ -7373,7 +7233,7 @@ static SpiceCanvas *create_ogl_pbuf_context(RedWorker *worker, uint32_t width, u
         return NULL;
     }
 
-    if (!(canvas = create_ogl_context_common(worker, ctx, width, height, stride, depth))) {
+    if (!(canvas = create_ogl_context_common(display, ctx, width, height, stride, depth))) {
         oglctx_destroy(ctx);
         return NULL;
     }
@@ -7381,8 +7241,9 @@ static SpiceCanvas *create_ogl_pbuf_context(RedWorker *worker, uint32_t width, u
     return canvas;
 }
 
-static SpiceCanvas *create_ogl_pixmap_context(RedWorker *worker, uint32_t width, uint32_t height,
-                                              int32_t stride, uint8_t depth) {
+static SpiceCanvas *create_ogl_pixmap_context(DisplayChannel *display, uint32_t width,
+                                              uint32_t height, int32_t stride, uint8_t depth)
+{
     OGLCtx *ctx;
     SpiceCanvas *canvas;
 
@@ -7390,7 +7251,7 @@ static SpiceCanvas *create_ogl_pixmap_context(RedWorker *worker, uint32_t width,
         return NULL;
     }
 
-    if (!(canvas = create_ogl_context_common(worker, ctx, width, height, stride, depth))) {
+    if (!(canvas = create_ogl_context_common(display, ctx, width, height, stride, depth))) {
         oglctx_destroy(ctx);
         return NULL;
     }
@@ -7399,11 +7260,10 @@ static SpiceCanvas *create_ogl_pixmap_context(RedWorker *worker, uint32_t width,
 }
 #endif
 
-static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *surface,
+static inline void *create_canvas_for_surface(DisplayChannel *display, RedSurface *surface,
                                               uint32_t renderer, uint32_t width, uint32_t height,
                                               int32_t stride, uint32_t format, void *line_0)
 {
-    DisplayChannel *display = worker->display_channel;
     SpiceCanvas *canvas;
 
     switch (renderer) {
@@ -7411,18 +7271,18 @@ static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *sur
         canvas = canvas_create_for_data(width, height, format,
                                         line_0, stride,
                                         &display->image_cache.base,
-                                        &worker->image_surfaces, NULL, NULL, NULL);
+                                        &display->image_surfaces, NULL, NULL, NULL);
         surface->context.top_down = TRUE;
         surface->context.canvas_draws_on_surface = TRUE;
         return canvas;
 #ifdef USE_OPENGL
     case RED_RENDERER_OGL_PBUF:
-        canvas = create_ogl_pbuf_context(worker, width, height, stride,
+        canvas = create_ogl_pbuf_context(display, width, height, stride,
                                          SPICE_SURFACE_FMT_DEPTH(format));
         surface->context.top_down = FALSE;
         return canvas;
     case RED_RENDERER_OGL_PIXMAP:
-        canvas = create_ogl_pixmap_context(worker, width, height, stride,
+        canvas = create_ogl_pixmap_context(display, width, height, stride,
                                            SPICE_SURFACE_FMT_DEPTH(format));
         surface->context.top_down = FALSE;
         return canvas;
@@ -7456,17 +7316,17 @@ static SurfaceCreateItem *get_surface_create_item(
 
 static inline void red_create_surface_item(DisplayChannelClient *dcc, int surface_id)
 {
+    DisplayChannel *display = dcc ? DCC_TO_DC(dcc) : NULL;
     RedSurface *surface;
     SurfaceCreateItem *create;
-    RedWorker *worker = dcc ? DCC_TO_WORKER(dcc) : NULL;
     uint32_t flags = is_primary_surface(DCC_TO_DC(dcc), surface_id) ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
 
     /* don't send redundant create surface commands to client */
-    if (!dcc || worker->display_channel->common.during_target_migrate ||
+    if (!dcc || display->common.during_target_migrate ||
         dcc->surface_client_created[surface_id]) {
         return;
     }
-    surface = &worker->surfaces[surface_id];
+    surface = &display->surfaces[surface_id];
     create = get_surface_create_item(RED_CHANNEL_CLIENT(dcc)->channel,
             surface_id, surface->context.width, surface->context.height,
                                      surface->context.format, flags);
@@ -7474,33 +7334,32 @@ static inline void red_create_surface_item(DisplayChannelClient *dcc, int surfac
     red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &create->pipe_item);
 }
 
-static void red_worker_create_surface_item(RedWorker *worker, int surface_id)
+static void red_worker_create_surface_item(DisplayChannel *display, int surface_id)
 {
     DisplayChannelClient *dcc;
     RingItem *item, *next;
 
-    FOREACH_DCC(worker->display_channel, item, next, dcc) {
+    FOREACH_DCC(display, item, next, dcc) {
         red_create_surface_item(dcc, surface_id);
     }
 }
 
 
-static void red_worker_push_surface_image(RedWorker *worker, int surface_id)
+static void red_worker_push_surface_image(DisplayChannel *display, int surface_id)
 {
     DisplayChannelClient *dcc;
     RingItem *item, *next;
 
-    FOREACH_DCC(worker->display_channel, item, next, dcc) {
+    FOREACH_DCC(display, item, next, dcc) {
         red_push_surface_image(dcc, surface_id);
     }
 }
 
-static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width,
-                                      uint32_t height, int32_t stride, uint32_t format,
-                                      void *line_0, int data_is_valid, int send_client)
+static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uint32_t width,
+                               uint32_t height, int32_t stride, uint32_t format,
+                               void *line_0, int data_is_valid, int send_client)
 {
-    RedSurface *surface = &worker->surfaces[surface_id];
-    DisplayChannel*display = worker->display_channel;
+    RedSurface *surface = &display->surfaces[surface_id];
     uint32_t i;
 
     spice_warn_if(surface->context.canvas);
@@ -7526,7 +7385,7 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
     region_init(&surface->draw_dirty_region);
     surface->refs = 1;
     if (display->renderer != RED_RENDERER_INVALID) {
-        surface->context.canvas = create_canvas_for_surface(worker, surface, display->renderer,
+        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderer,
                                                             width, height, stride,
                                                             surface->context.format, line_0);
         if (!surface->context.canvas) {
@@ -7534,24 +7393,24 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
         }
 
         if (send_client) {
-            red_worker_create_surface_item(worker, surface_id);
+            red_worker_create_surface_item(display, surface_id);
             if (data_is_valid) {
-                red_worker_push_surface_image(worker, surface_id);
+                red_worker_push_surface_image(display, surface_id);
             }
         }
         return;
     }
 
     for (i = 0; i < display->num_renderers; i++) {
-        surface->context.canvas = create_canvas_for_surface(worker, surface, display->renderers[i],
+        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderers[i],
                                                             width, height, stride,
                                                             surface->context.format, line_0);
         if (surface->context.canvas) { //no need canvas check
             display->renderer = display->renderers[i];
             if (send_client) {
-                red_worker_create_surface_item(worker, surface_id);
+                red_worker_create_surface_item(display, surface_id);
                 if (data_is_valid) {
-                    red_worker_push_surface_image(worker, surface_id);
+                    red_worker_push_surface_image(display, surface_id);
                 }
             }
             return;
@@ -7698,8 +7557,7 @@ static int display_channel_client_wait_for_init(DisplayChannelClient *dcc)
 
 static void on_new_display_channel_client(DisplayChannelClient *dcc)
 {
-    DisplayChannel *display_channel = DCC_TO_DC(dcc);
-    RedWorker *worker = display_channel->common.worker;
+    DisplayChannel *display = DCC_TO_DC(dcc);
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
 
     red_channel_client_push_set_ack(RED_CHANNEL_CLIENT(dcc));
@@ -7712,8 +7570,8 @@ static void on_new_display_channel_client(DisplayChannelClient *dcc)
         return;
     }
     red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
-    if (worker->surfaces[0].context.canvas) {
-        red_current_flush(worker, 0);
+    if (display->surfaces[0].context.canvas) {
+        red_current_flush(display, 0);
         push_new_primary_surface(dcc);
         red_push_surface_image(dcc, 0);
         dcc_push_monitors_config(dcc);
@@ -8447,7 +8305,8 @@ static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
     }
 }
 
-static void display_channel_create(RedWorker *worker, int migrate, int stream_video)
+static void display_channel_create(RedWorker *worker, int migrate, int stream_video,
+                                   uint32_t n_surfaces)
 {
     DisplayChannel *display_channel;
     ChannelCbs cbs = {
@@ -8492,12 +8351,15 @@ static void display_channel_create(RedWorker *worker, int migrate, int stream_vi
     stat_compress_init(&display_channel->jpeg_alpha_stat, "jpeg_alpha");
     stat_compress_init(&display_channel->lz4_stat, "lz4");
 
+    display_channel->n_surfaces = n_surfaces;
     display_channel->num_renderers = num_renderers;
     memcpy(display_channel->renderers, renderers, sizeof(display_channel->renderers));
     display_channel->renderer = RED_RENDERER_INVALID;
-    image_cache_init(&display_channel->image_cache);
+
     ring_init(&display_channel->current_list);
+    image_surface_init(display_channel);
     drawables_init(display_channel);
+    image_cache_init(&display_channel->image_cache);
     display_channel->stream_video = stream_video;
     stream_init(display_channel);
 }
@@ -8632,14 +8494,13 @@ static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream
 
     // 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[0].context.canvas)
+    if (display_channel_surface_has_canvas(worker->display_channel, 0))
         cursor_channel_init(channel, ccc);
 }
 
 static void surface_dirty_region_to_rects(RedSurface *surface,
                                           QXLRect *qxl_dirty_rects,
-                                          uint32_t num_dirty_rects,
-                                          int clear_dirty_region)
+                                          uint32_t num_dirty_rects)
 {
     QRegion *surface_dirty_region;
     SpiceRect *dirty_rects;
@@ -8648,9 +8509,6 @@ static void surface_dirty_region_to_rects(RedSurface *surface,
     surface_dirty_region = &surface->draw_dirty_region;
     dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
     region_ret_rects(surface_dirty_region, dirty_rects, num_dirty_rects);
-    if (clear_dirty_region) {
-        region_clear(surface_dirty_region);
-    }
     for (i = 0; i < num_dirty_rects; i++) {
         qxl_dirty_rects[i].top    = dirty_rects[i].top;
         qxl_dirty_rects[i].left   = dirty_rects[i].left;
@@ -8660,67 +8518,60 @@ static void surface_dirty_region_to_rects(RedSurface *surface,
     free(dirty_rects);
 }
 
-static void handle_dev_update_async(void *opaque, void *payload)
+void display_channel_update(DisplayChannel *display,
+                            uint32_t surface_id, const QXLRect *area, uint32_t clear_dirty,
+                            QXLRect **qxl_dirty_rects, uint32_t *num_dirty_rects)
 {
-    RedWorker *worker = opaque;
-    RedWorkerMessageUpdateAsync *msg = payload;
     SpiceRect rect;
-    QXLRect *qxl_dirty_rects;
-    uint32_t num_dirty_rects;
     RedSurface *surface;
-    uint32_t surface_id = msg->surface_id;
-    QXLRect qxl_area = msg->qxl_area;
-    uint32_t clear_dirty_region = msg->clear_dirty_region;
 
-    red_get_rect_ptr(&rect, &qxl_area);
-    flush_display_commands(worker);
+    spice_return_if_fail(validate_surface(display, surface_id));
 
-    spice_assert(worker->running);
+    red_get_rect_ptr(&rect, area);
+    red_update_area(display, &rect, surface_id);
 
-    VALIDATE_SURFACE_RET(worker, surface_id);
-    red_update_area(worker, &rect, surface_id);
-    if (!worker->qxl->st->qif->update_area_complete) {
-        return;
-    }
-    surface = &worker->surfaces[surface_id];
-    num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
-    if (num_dirty_rects == 0) {
-        return;
+    surface = &display->surfaces[surface_id];
+    if (!*qxl_dirty_rects) {
+        *num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
+        *qxl_dirty_rects = spice_new0(QXLRect, *num_dirty_rects);
     }
-    qxl_dirty_rects = spice_new0(QXLRect, num_dirty_rects);
-    surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
-                                  clear_dirty_region);
-    worker->qxl->st->qif->update_area_complete(worker->qxl, surface_id,
-                                          qxl_dirty_rects, num_dirty_rects);
-    free(qxl_dirty_rects);
+
+    surface_dirty_region_to_rects(surface, *qxl_dirty_rects, *num_dirty_rects);
+    if (clear_dirty)
+        region_clear(&surface->draw_dirty_region);
 }
 
-static void handle_dev_update(void *opaque, void *payload)
+static void handle_dev_update_async(void *opaque, void *payload)
 {
     RedWorker *worker = opaque;
-    RedWorkerMessageUpdate *msg = payload;
-    SpiceRect *rect;
-    RedSurface *surface;
-    uint32_t surface_id = msg->surface_id;
-    const QXLRect *qxl_area = msg->qxl_area;
-    uint32_t num_dirty_rects = msg->num_dirty_rects;
-    QXLRect *qxl_dirty_rects = msg->qxl_dirty_rects;
-    uint32_t clear_dirty_region = msg->clear_dirty_region;
+    RedWorkerMessageUpdateAsync *msg = payload;
+    QXLRect *qxl_dirty_rects = NULL;
+    uint32_t num_dirty_rects = 0;
 
-    VALIDATE_SURFACE_RET(worker, surface_id);
+    spice_return_if_fail(worker->running);
+    spice_return_if_fail(worker->qxl->st->qif->update_area_complete);
 
-    rect = spice_new0(SpiceRect, 1);
-    surface = &worker->surfaces[surface_id];
-    red_get_rect_ptr(rect, qxl_area);
     flush_display_commands(worker);
+    display_channel_update(worker->display_channel,
+                           msg->surface_id, &msg->qxl_area, msg->clear_dirty_region,
+                           &qxl_dirty_rects, &num_dirty_rects);
 
-    spice_assert(worker->running);
+    worker->qxl->st->qif->update_area_complete(worker->qxl, msg->surface_id,
+                                                qxl_dirty_rects, num_dirty_rects);
+    free(qxl_dirty_rects);
+}
+
+static void handle_dev_update(void *opaque, void *payload)
+{
+    RedWorker *worker = opaque;
+    RedWorkerMessageUpdate *msg = payload;
 
-    red_update_area(worker, rect, surface_id);
-    free(rect);
+    spice_return_if_fail(worker->running);
 
-    surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
-                                  clear_dirty_region);
+    flush_display_commands(worker);
+    display_channel_update(worker->display_channel,
+                           msg->surface_id, msg->qxl_area, msg->clear_dirty_region,
+                           &msg->qxl_dirty_rects, &msg->num_dirty_rects);
 }
 
 static void handle_dev_del_memslot(void *opaque, void *payload)
@@ -8733,32 +8584,18 @@ static void handle_dev_del_memslot(void *opaque, void *payload)
     red_memslot_info_del_slot(&worker->mem_slots, slot_group_id, slot_id);
 }
 
-/* TODO: destroy_surface_wait, dev_destroy_surface_wait - confusing. one asserts
- * surface_id == 0, maybe move the assert upward and merge the two functions? */
-static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
+void display_channel_destroy_surface_wait(DisplayChannel *display, int surface_id)
 {
-    VALIDATE_SURFACE_RET(worker, surface_id);
-    if (!worker->surfaces[surface_id].context.canvas) {
+    VALIDATE_SURFACE_RET(display, surface_id);
+    if (!display->surfaces[surface_id].context.canvas)
         return;
-    }
 
-    red_handle_depends_on_target_surface(worker, surface_id);
-    /* note that red_handle_depends_on_target_surface must be called before red_current_clear.
+    red_handle_depends_on_target_surface(display, surface_id);
+    /* note that red_handle_depends_on_target_surface must be called before current_clear.
        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, surface_id);
-    red_clear_surface_drawables_from_pipes(worker, surface_id, TRUE);
-}
-
-static void dev_destroy_surface_wait(RedWorker *worker, uint32_t surface_id)
-{
-    spice_assert(surface_id == 0);
-
-    flush_all_qxl_commands(worker);
-
-    if (worker->surfaces[0].context.canvas) {
-        destroy_surface_wait(worker, 0);
-    }
+       current_clear will remove them from the pipe. */
+    current_clear(display, surface_id);
+    red_clear_surface_drawables_from_pipes(display, surface_id, TRUE);
 }
 
 static void handle_dev_destroy_surface_wait(void *opaque, void *payload)
@@ -8766,48 +8603,47 @@ static void handle_dev_destroy_surface_wait(void *opaque, void *payload)
     RedWorkerMessageDestroySurfaceWait *msg = payload;
     RedWorker *worker = opaque;
 
-    dev_destroy_surface_wait(worker, msg->surface_id);
+    spice_return_if_fail(msg->surface_id == 0);
+
+    flush_all_qxl_commands(worker);
+    display_channel_destroy_surface_wait(worker->display_channel, msg->surface_id);
 }
 
 /* called upon device reset */
 
 /* TODO: split me*/
-static inline void dev_destroy_surfaces(RedWorker *worker)
+void display_channel_destroy_surfaces(DisplayChannel *display)
 {
-    DisplayChannel *display = worker->display_channel;
     int i;
 
     spice_debug(NULL);
-    flush_all_qxl_commands(worker);
     //to handle better
     for (i = 0; i < NUM_SURFACES; ++i) {
-        if (worker->surfaces[i].context.canvas) {
-            destroy_surface_wait(worker, i);
-            if (worker->surfaces[i].context.canvas) {
-                red_surface_unref(worker, i);
+        if (display->surfaces[i].context.canvas) {
+            display_channel_destroy_surface_wait(display, i);
+            if (display->surfaces[i].context.canvas) {
+                display_channel_surface_unref(display, i);
             }
-            spice_assert(!worker->surfaces[i].context.canvas);
+            spice_assert(!display->surfaces[i].context.canvas);
         }
     }
-    spice_assert(ring_is_empty(&display->streams));
+    spice_warn_if_fail(ring_is_empty(&display->streams));
 
-    if (display_is_connected(worker)) {
-        red_channel_pipes_add_type(RED_CHANNEL(worker->display_channel),
-                                   PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
-        red_pipes_add_verb(RED_CHANNEL(worker->display_channel),
-                           SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
+    if (red_channel_is_connected(RED_CHANNEL(display))) {
+        red_channel_pipes_add_type(RED_CHANNEL(display), PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
+        red_pipes_add_verb(RED_CHANNEL(display), SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
     }
 
-    red_display_clear_glz_drawables(worker->display_channel);
-
-    cursor_channel_reset(worker->cursor_channel);
+    red_display_clear_glz_drawables(display);
 }
 
 static void handle_dev_destroy_surfaces(void *opaque, void *payload)
 {
     RedWorker *worker = opaque;
 
-    dev_destroy_surfaces(worker);
+    flush_all_qxl_commands(worker);
+    display_channel_destroy_surfaces(worker->display_channel);
+    cursor_channel_reset(worker->cursor_channel);
 }
 
 static void display_update_monitors_config(DisplayChannel *display,
@@ -8832,13 +8668,12 @@ static void red_worker_push_monitors_config(RedWorker *worker)
     }
 }
 
-static void set_monitors_config_to_primary(RedWorker *worker)
+static void set_monitors_config_to_primary(DisplayChannel *display)
 {
-    DrawContext *context = &worker->surfaces[0].context;
-    DisplayChannel *display = worker->display_channel;
+    DrawContext *context = &display->surfaces[0].context;
     QXLHead head = { 0, };
 
-    spice_return_if_fail(worker->surfaces[0].context.canvas);
+    spice_return_if_fail(display->surfaces[0].context.canvas);
 
     if (display->monitors_config)
         monitors_config_unref(display->monitors_config);
@@ -8851,6 +8686,7 @@ static void set_monitors_config_to_primary(RedWorker *worker)
 static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
                                        QXLDevSurfaceCreate surface)
 {
+    DisplayChannel *display = worker->display_channel;
     uint8_t *line_0;
     int error;
 
@@ -8875,9 +8711,9 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
         line_0 -= (int32_t)(surface.stride * (surface.height -1));
     }
 
-    red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.format,
+    red_create_surface(display, 0, surface.width, surface.height, surface.stride, surface.format,
                        line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA, TRUE);
-    set_monitors_config_to_primary(worker);
+    set_monitors_config_to_primary(display);
 
     if (display_is_connected(worker) && !worker->display_channel->common.during_target_migrate) {
         /* guest created primary, so it will (hopefully) send a monitors_config
@@ -8901,25 +8737,25 @@ static void handle_dev_create_primary_surface(void *opaque, void *payload)
     dev_create_primary_surface(worker, msg->surface_id, msg->surface);
 }
 
-static void dev_destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
+static void destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
 {
     DisplayChannel *display = worker->display_channel;
 
-    VALIDATE_SURFACE_RET(worker, surface_id);
+    VALIDATE_SURFACE_RET(display, surface_id);
     spice_warn_if(surface_id != 0);
 
     spice_debug(NULL);
-    if (!worker->surfaces[surface_id].context.canvas) {
+    if (!display->surfaces[surface_id].context.canvas) {
         spice_warning("double destroy of primary surface");
         return;
     }
 
     flush_all_qxl_commands(worker);
-    dev_destroy_surface_wait(worker, 0);
-    red_surface_unref(worker, 0);
-    spice_warn_if_fail(ring_is_empty(&display->streams));
+    display_channel_destroy_surface_wait(display, 0);
+    display_channel_surface_unref(display, 0);
 
-    spice_assert(!worker->surfaces[surface_id].context.canvas);
+    spice_warn_if_fail(ring_is_empty(&display->streams));
+    spice_warn_if_fail(!display->surfaces[surface_id].context.canvas);
 
     cursor_channel_reset(worker->cursor_channel);
 }
@@ -8930,7 +8766,7 @@ static void handle_dev_destroy_primary_surface(void *opaque, void *payload)
     RedWorker *worker = opaque;
     uint32_t surface_id = msg->surface_id;
 
-    dev_destroy_primary_surface(worker, surface_id);
+    destroy_primary_surface(worker, surface_id);
 }
 
 static void handle_dev_destroy_primary_surface_async(void *opaque, void *payload)
@@ -8939,16 +8775,16 @@ static void handle_dev_destroy_primary_surface_async(void *opaque, void *payload
     RedWorker *worker = opaque;
     uint32_t surface_id = msg->surface_id;
 
-    dev_destroy_primary_surface(worker, surface_id);
+    destroy_primary_surface(worker, surface_id);
 }
 
-static void flush_all_surfaces(RedWorker *worker)
+static void flush_all_surfaces(DisplayChannel *display)
 {
     int x;
 
     for (x = 0; x < NUM_SURFACES; ++x) {
-        if (worker->surfaces[x].context.canvas) {
-            red_current_flush(worker, x);
+        if (display->surfaces[x].context.canvas) {
+            red_current_flush(display, x);
         }
     }
 }
@@ -8956,7 +8792,7 @@ static void flush_all_surfaces(RedWorker *worker)
 static void dev_flush_surfaces(RedWorker *worker)
 {
     flush_all_qxl_commands(worker);
-    flush_all_surfaces(worker);
+    flush_all_surfaces(worker->display_channel);
 }
 
 static void handle_dev_flush_surfaces_async(void *opaque, void *payload)
@@ -8974,7 +8810,7 @@ static void handle_dev_stop(void *opaque, void *payload)
     spice_assert(worker->running);
     worker->running = FALSE;
     red_display_clear_glz_drawables(worker->display_channel);
-    flush_all_surfaces(worker);
+    flush_all_surfaces(worker->display_channel);
     /* todo: when the waiting is expected to take long (slow connection and
      * overloaded pipe), don't wait, and in case of migration,
      * purge the pipe, send destroy_all_surfaces
@@ -9103,14 +8939,16 @@ static void handle_dev_destroy_surface_wait_async(void *opaque, void *payload)
     RedWorkerMessageDestroySurfaceWaitAsync *msg = payload;
     RedWorker *worker = opaque;
 
-    dev_destroy_surface_wait(worker, msg->surface_id);
+    display_channel_destroy_surface_wait(worker->display_channel, msg->surface_id);
 }
 
 static void handle_dev_destroy_surfaces_async(void *opaque, void *payload)
 {
     RedWorker *worker = opaque;
 
-    dev_destroy_surfaces(worker);
+    flush_all_qxl_commands(worker);
+    display_channel_destroy_surfaces(worker->display_channel);
+    cursor_channel_reset(worker->cursor_channel);
 }
 
 static void handle_dev_create_primary_surface_async(void *opaque, void *payload)
@@ -9624,7 +9462,6 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher)
     worker->jpeg_state = jpeg_state;
     worker->zlib_glz_state = zlib_glz_state;
     worker->driver_cap_monitors_config = 0;
-    image_surface_init(worker);
 #ifdef RED_STATISTICS
     char worker_str[20];
     sprintf(worker_str, "display[%d]", worker->qxl->id);
@@ -9650,7 +9487,6 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher)
                           init_info.internal_groupslot_id);
 
     spice_warn_if(init_info.n_surfaces > NUM_SURFACES);
-    worker->n_surfaces = init_info.n_surfaces;
 
     red_init_quic(worker);
     red_init_lz(worker);
@@ -9663,7 +9499,7 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher)
 
     worker->cursor_channel = cursor_channel_new(worker);
     // TODO: handle seemless migration. Temp, setting migrate to FALSE
-    display_channel_create(worker, FALSE, streaming_video);
+    display_channel_create(worker, FALSE, streaming_video, init_info.n_surfaces);
 
     return worker;
 }
diff --git a/server/red_worker.h b/server/red_worker.h
index 2995b8f..3604dfd 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include "red_common.h"
 #include "red_dispatcher.h"
+#include "red_parse_qxl.h"
 
 typedef struct RedWorker RedWorker;
 
@@ -108,6 +109,7 @@ bool       red_worker_run(RedWorker *worker);
 QXLInstance* red_worker_get_qxl(RedWorker *worker);
 RedChannel* red_worker_get_cursor_channel(RedWorker *worker);
 RedChannel* red_worker_get_display_channel(RedWorker *worker);
+void red_worker_print_stats(RedWorker *worker);
 
 RedChannel *red_worker_new_channel(RedWorker *worker, int size,
                                    const char *name,
-- 
2.4.3



More information about the Spice-devel mailing list