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

Fabiano FidĂȘncio fidencio at redhat.com
Wed Nov 11 04:54:02 PST 2015


On Tue, Nov 10, 2015 at 9:41 PM, Jonathon Jongsma <jjongsma at redhat.com> wrote:
> 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      | 1121 ++++++++++++++++++++--------------------------
>  server/red_worker.h      |    2 +
>  4 files changed, 593 insertions(+), 646 deletions(-)
>
> diff --git a/server/display-channel.c b/server/display-channel.c
> index b5d8830..5f422c9 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 7bb9c14..c7709ad 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;
>
> @@ -370,6 +398,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 8a2ff0e..2360866 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -111,6 +111,8 @@ static void rendering_incorrect(const char *msg)
>
>  typedef unsigned long stat_time_t;
>
> +static stat_time_t stat_now(RedWorker *worker);
> +
>  #if defined(RED_WORKER_STAT) || defined(COMPRESS_STAT)
>  double stat_cpu_time_to_sec(stat_time_t time)
>  {
> @@ -299,30 +301,6 @@ struct RedGlzDrawable {
>  pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER;
>  Ring glz_dictionary_list = {&glz_dictionary_list, &glz_dictionary_list};
>
> -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;
> @@ -339,10 +317,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;
> @@ -403,7 +377,7 @@ 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 stat_time_t stat_now(RedWorker *worker)
>  {
> @@ -414,11 +388,11 @@ static stat_time_t stat_now(RedWorker *worker)
>      return ts.tv_nsec + ts.tv_sec * 1000 * 1000 * 1000;
>  }
>
> -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);
> @@ -435,6 +409,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)          \
> @@ -570,8 +547,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;
> @@ -589,15 +566,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;
>      }
> @@ -610,7 +587,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) {
> @@ -622,7 +599,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);
>          }
>      }
> @@ -632,7 +609,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);
>  }
>
> @@ -657,13 +634,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);
>      }
>  }
> @@ -680,7 +657,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;
> @@ -697,13 +674,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) {
> @@ -727,8 +704,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;
> @@ -843,59 +818,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)
>  {
> @@ -944,7 +866,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);
>      }
>  }
>
> @@ -978,7 +900,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;
> @@ -1004,7 +926,7 @@ static inline void remove_shadow(DrawItem *item)
>      free(shadow);
>  }
>
> -static inline void current_remove_container(RedWorker *worker, Container *container)
> +static inline void current_remove_container(DisplayChannel *display, Container *container)
>  {
>      spice_assert(ring_is_empty(&container->items));
>      ring_remove(&container->base.siblings_link);
> @@ -1012,7 +934,7 @@ static inline void current_remove_container(RedWorker *worker, Container *contai
>      free(container);
>  }
>
> -static inline void container_cleanup(RedWorker *worker, Container *container)
> +static inline void container_cleanup(DisplayChannel *display, Container *container)
>  {
>      while (container && container->items.next == container->items.prev) {
>          Container *next = container->base.container;
> @@ -1023,7 +945,7 @@ static inline void container_cleanup(RedWorker *worker, Container *container)
>              ring_add_after(&item->siblings_link, &container->base.siblings_link);
>              item->container = container->base.container;
>          }
> -        current_remove_container(worker, container);
> +        current_remove_container(display, container);
>          container = next;
>      }
>  }
> @@ -1047,12 +969,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;
> @@ -1061,15 +983,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);
> @@ -1079,23 +999,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;
>
> @@ -1106,7 +1027,7 @@ static inline void current_remove(RedWorker *worker, TreeItem *item)
>                  continue;
>              }
>              ring_item = now->siblings_link.prev;
> -            current_remove_container(worker, container);
> +            current_remove_container(display, container);
>          }
>          if (now == item) {
>              return;
> @@ -1120,13 +1041,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);
>      }
>  }
>
> @@ -1211,14 +1133,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));
>          }
> @@ -1258,8 +1180,8 @@ 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
> @@ -1298,7 +1220,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);
>              }
> @@ -1329,8 +1251,8 @@ static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *ite
>      stat_add(&worker->__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
>      stat_time_t start_time = stat_now(worker);
> @@ -1350,12 +1272,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);
>                  }
> @@ -1388,13 +1310,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);
> @@ -1490,9 +1412,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);
>      }
> @@ -2148,9 +2070,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;
> @@ -2170,14 +2091,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);
> @@ -2193,11 +2114,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) {
> @@ -2206,7 +2127,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);
> @@ -2216,7 +2137,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);
>                  }
>              }
> @@ -2229,9 +2150,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;
> @@ -2299,7 +2220,7 @@ static void red_use_stream_trace(DisplayChannel *display, Drawable *drawable)
>      }
>  }
>
> -static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
> +static inline int red_current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
>  {
>      DrawItem *item = &drawable->tree_item;
>  #ifdef RED_WORKER_STAT
> @@ -2328,7 +2249,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
>          } 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)) {
> +                                                   red_current_add_equal(display, item, sibling)) {
>                  stat_add(&worker->add_stat, start_time);
>                  return FALSE;
>              }
> @@ -2340,7 +2261,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
>                  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;
> @@ -2350,7 +2271,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
>                      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;
> @@ -2362,7 +2283,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
>                  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;
>                  }
> @@ -2393,24 +2314,24 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
>      }
>      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);
> @@ -2427,9 +2348,8 @@ static void add_clip_rects(QRegion *rgn, SpiceClipRects *data)
>      }
>  }
>
> -static inline int red_current_add_with_shadow(RedWorker *worker, Ring *ring, Drawable *item)
> +static int red_current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawable *item)
>  {
> -    DisplayChannel *display = worker->display_channel;
>  #ifdef RED_WORKER_STAT
>      stat_time_t start_time = stat_now(worker);
>      ++worker->add_with_shadow_count;
> @@ -2455,11 +2375,11 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Ring *ring, Dra
>      }
>
>      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 {
> @@ -2515,7 +2435,7 @@ static void drawable_update_streamable(DisplayChannel *display, Drawable *drawab
>      drawable->streamable = TRUE;
>  }
>
> -static void red_print_stats(RedWorker *worker)
> +void red_worker_print_stats(RedWorker *worker)
>  {
>  #ifdef RED_WORKER_STAT
>      if ((++worker->add_count % 100) == 0) {
> @@ -2543,33 +2463,32 @@ static void red_print_stats(RedWorker *worker)
>  #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 = red_current_add_with_shadow(worker, ring, drawable);
> +        ret = red_current_add_with_shadow(display, ring, drawable);
>      } else {
>          drawable_update_streamable(display, drawable);
> -        ret = red_current_add(worker, ring, drawable);
> +        ret = red_current_add(display, ring, drawable);
>      }
>
> -    red_print_stats(worker);
> +    red_worker_print_stats(COMMON_CHANNEL(display)->worker);
>      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;
> @@ -2621,7 +2540,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;
>
> @@ -2647,7 +2566,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
> @@ -2666,9 +2585,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;
> @@ -2684,12 +2602,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);
> -    container_cleanup(worker, container);
> -
> +    current_remove_drawable(display, drawable);
> +    container_cleanup(display, container);
>      return TRUE;
>  }
>
> @@ -2700,19 +2617,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;
>      }
>
> @@ -2737,24 +2654,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;
> @@ -2764,22 +2681,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) {
> @@ -2794,7 +2710,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;
> @@ -2805,7 +2721,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++;
>      }
>  }
> @@ -2824,7 +2740,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);
>
> @@ -2836,13 +2752,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;
> @@ -2852,38 +2769,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: {
> @@ -2899,7 +2814,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
> @@ -2913,13 +2828,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");
> @@ -2932,31 +2847,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);
> @@ -3087,17 +3001,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;
> @@ -3119,10 +3033,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;
> @@ -3133,7 +3046,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
> @@ -3185,22 +3098,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);
> -        container_cleanup(worker, container);
> +        current_remove_drawable(display, now);
> +        container_cleanup(display, 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;
> @@ -3215,7 +3127,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;
> @@ -3233,7 +3145,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;
>      }
>
> @@ -3244,12 +3156,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);
> -        container_cleanup(worker, container);
> -        red_draw_drawable(worker, now);
> +        current_remove_drawable(display, now);
> +        container_cleanup(display, container);
> +        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)
> @@ -3368,11 +3280,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;
> @@ -3446,7 +3358,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) {
> @@ -3458,12 +3370,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.
> @@ -3472,8 +3384,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;
> @@ -3533,15 +3444,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);

I would do:
    DisplayChannel *display = dcc ? DCC_TO_DC(dcc) : NULL;

>      SpiceRect area;
>      RedSurface *surface;
> -    RedWorker *worker;
>
> -    if (!dcc) {
> -        return;
> -    }

And here check for a NULL display.

> -    worker = DCC_TO_WORKER(dcc);
> -    surface = &worker->surfaces[surface_id];
> +    surface = &display->surfaces[surface_id];
>      if (!surface->context.canvas) {
>          return;
>      }
> @@ -4968,8 +4875,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;
> @@ -4992,7 +4898,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
> @@ -5004,7 +4910,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 {
> @@ -5021,13 +4927,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;
> @@ -5114,16 +5020,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);
>          }
> @@ -5156,10 +5062,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) {
> @@ -5249,7 +5155,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;
> @@ -5360,8 +5266,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)
> @@ -5393,8 +5298,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)
>  {
> @@ -5449,15 +5353,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;
>
> @@ -5470,7 +5374,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)) {
> @@ -5482,7 +5386,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);
>          }
>      }
> @@ -5505,11 +5409,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);
>          }
> @@ -5519,10 +5423,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;
> @@ -5547,13 +5450,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;
> @@ -5580,9 +5482,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];
> @@ -5600,18 +5502,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;
> @@ -5639,13 +5540,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;
> @@ -5675,14 +5575,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];
> @@ -5700,19 +5600,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;
> @@ -5732,13 +5631,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;
> @@ -5748,23 +5646,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;
> @@ -5779,10 +5676,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;
> @@ -5793,7 +5689,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];
> @@ -5802,16 +5698,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);
> @@ -5833,10 +5728,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);
> @@ -5848,7 +5742,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;
> @@ -5857,14 +5751,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;
> @@ -5877,10 +5770,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);
> @@ -5891,7 +5783,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;
> @@ -5904,14 +5796,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);
> @@ -5933,10 +5823,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);
> @@ -5953,7 +5842,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];
> @@ -5971,15 +5860,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;
> @@ -5997,25 +5885,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;
> @@ -6033,25 +5919,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;
> @@ -6068,18 +5952,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);
> @@ -6106,10 +5988,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);
> @@ -6132,8 +6013,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];
> @@ -6157,15 +6038,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);
> @@ -6188,8 +6068,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)
>  {
> @@ -6214,8 +6093,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];
> @@ -6240,15 +6119,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);
> @@ -6271,10 +6149,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);
> @@ -6303,7 +6180,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];
> @@ -6322,15 +6199,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);
> @@ -6355,10 +6231,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);
> @@ -6395,7 +6270,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];
> @@ -6418,111 +6293,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");
> @@ -6821,9 +6697,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,
> @@ -7379,24 +7255,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;
> @@ -7474,15 +7332,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;
>      }
>
> @@ -7493,8 +7351,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;
> @@ -7503,7 +7361,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;
>      }
> @@ -7511,8 +7369,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;
>
> @@ -7520,7 +7379,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;
>      }
> @@ -7529,11 +7388,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) {
> @@ -7541,18 +7399,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;
> @@ -7586,17 +7444,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 ||

I would add a check for a NULL display here.

>          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);
> @@ -7604,33 +7462,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);
> @@ -7656,7 +7513,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) {
> @@ -7664,24 +7521,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;
> @@ -7828,8 +7685,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));
> @@ -7842,8 +7698,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);
> @@ -8577,7 +8433,7 @@ static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
>      }
>  }
>
> -static void display_channel_create(RedWorker *worker, int migrate)
> +static void display_channel_create(RedWorker *worker, int migrate, uint32_t n_surfaces)
>  {
>      DisplayChannel *display_channel;
>      ChannelCbs cbs = {
> @@ -8619,12 +8475,15 @@ static void display_channel_create(RedWorker *worker, int migrate)
>      stat_compress_init(&display_channel->jpeg_alpha_stat, jpeg_alpha_stat_name);
>      stat_compress_init(&display_channel->lz4_stat, lz4_stat_name);
>
> +    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);
>      stream_init(display_channel);
>  }
>
> @@ -8758,14 +8617,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;
> @@ -8774,9 +8632,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;
> @@ -8786,67 +8641,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)
> @@ -8859,32 +8707,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)
> @@ -8892,48 +8726,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,
> @@ -8958,13 +8791,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);
> @@ -8977,6 +8809,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;
>
> @@ -9001,9 +8834,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
> @@ -9027,25 +8860,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);
>  }
> @@ -9056,7 +8889,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)
> @@ -9065,16 +8898,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);
>          }
>      }
>  }
> @@ -9082,7 +8915,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)
> @@ -9100,7 +8933,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
> @@ -9229,14 +9062,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)
> @@ -9750,7 +9585,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);
>      stat_init(&worker->add_stat, add_stat_name);
>      stat_init(&worker->exclude_stat, exclude_stat_name);
>      stat_init(&worker->__exclude_stat, __exclude_stat_name);
> @@ -9779,7 +9613,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);
> @@ -9792,7 +9625,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);
> +    display_channel_create(worker, FALSE, 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
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel

This patch is HUGE!
I agree with Joanthon about the need of some safety check in
DCC_TO_DC. I've suggested to small changes to keep the checks as it
was before. Removing the checks could come in a different patch (in
the future).
Also, there are a few "to do" or "fix me" comments that would be
better to have them replaced by "TODO" or "FIXME".
I've done some tests with both Windows and Linux guests and the patch
seems sane. So, if the comments are addressed and with a better commit
message, ACK.


More information about the Spice-devel mailing list