[Spice-devel] [PATCH 11/16] worker: move surfaces

Jonathon Jongsma jjongsma at redhat.com
Tue Nov 10 10:36:56 PST 2015


I'd like to split this one. Will send a new patch series.


On Tue, 2015-11-10 at 14:16 +0000, Frediano Ziglio 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 |  145 ++++-
>  server/red_worker.c      | 1324 +++++++++++++++++----------------------------
> -
>  server/red_worker.h      |    2 +
>  server/stream.c          |   70 +++
>  server/stream.h          |   12 +-
>  server/tree.h            |    6 +
>  7 files changed, 794 insertions(+), 844 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 1566c21..c7709ad 100644
> --- a/server/display-channel.h
> +++ b/server/display-channel.h
> @@ -20,6 +20,7 @@
>  
>  #include <setjmp.h>
>  
> +#include "common/rect.h"
>  #include "red_worker.h"
>  #include "reds_stream.h"
>  #include "cache-item.h"
> @@ -56,8 +57,6 @@
>  #include "tree.h"
>  #include "stream.h"
>  
> -typedef struct DisplayChannel DisplayChannel;
> -
>  #define PALETTE_CACHE_HASH_SHIFT 8
>  #define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT)
>  #define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1)
> @@ -205,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)
>  
>  
> @@ -273,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

If this comment is needed, it should use the standard "FIXME" format so we can
find it with a grep.

> +    QXLReleaseInfoExt create, destroy;
> +} RedSurface;
> +
>  #define NUM_DRAWABLES 1000
>  typedef struct _Drawable _Drawable;
>  struct _Drawable {
> @@ -311,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;
>  
> @@ -329,6 +356,21 @@ struct DisplayChannel {
>      stat_info_t lz4_stat;
>  #endif
>  };
> +
> +#define LINK_TO_DCC(ptr) SPICE_CONTAINEROF(ptr, DisplayChannelClient,   \
> +                                           common.base.channel_link)
> +#define DCC_FOREACH_SAFE(link, next, dcc, channel)                      \
> +    SAFE_FOREACH(link, next, channel,  &(channel)->clients, dcc,
> LINK_TO_DCC(link))
> +
> +
> +#define FOREACH_DCC(display_channel, link, next, dcc)                   \
> +    DCC_FOREACH_SAFE(link, next, dcc, RED_CHANNEL(display_channel))
> +
> +static inline int get_stream_id(DisplayChannel *display, Stream *stream)
> +{
> +    return (int)(stream - display->streams_buf);
> +}
> +
>  typedef struct SurfaceDestroyItem {
>      SpiceMsgSurfaceDestroy surface_destroy;
>      PipeItem pipe_item;
> @@ -356,7 +398,100 @@ 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)
> +{
> +    SpicePathSeg *seg1, *seg2;
> +    int i, j;
> +
> +    if (path1->num_segments != path2->num_segments)
> +        return FALSE;
> +
> +    for (i = 0; i < path1->num_segments; i++) {
> +        seg1 = path1->segments[i];
> +        seg2 = path2->segments[i];
> +
> +        if (seg1->flags != seg2->flags ||
> +            seg1->count != seg2->count) {
> +            return FALSE;
> +        }
> +        for (j = 0; j < seg1->count; j++) {
> +            if (seg1->points[j].x != seg2->points[j].x ||
> +                seg1->points[j].y != seg2->points[j].y) {
> +                return FALSE;
> +            }
> +        }
> +    }
> +
> +    return TRUE;
> +}
> +
> +// partial imp
> +static inline int is_equal_brush(SpiceBrush *b1, SpiceBrush *b2)
> +{
> +    return b1->type == b2->type &&
> +           b1->type == SPICE_BRUSH_TYPE_SOLID &&
> +           b1->u.color == b2->u.color;
> +}
> +
> +// partial imp
> +static inline int is_equal_line_attr(SpiceLineAttr *a1, SpiceLineAttr *a2)
> +{
> +    return a1->flags == a2->flags &&
> +           a1->style_nseg == a2->style_nseg &&
> +           a1->style_nseg == 0;
> +}
> +
> +// partial imp
> +static inline int is_same_geometry(Drawable *d1, Drawable *d2)
> +{
> +    if (d1->red_drawable->type != d2->red_drawable->type) {
> +        return FALSE;
> +    }
> +
> +    switch (d1->red_drawable->type) {
> +    case QXL_DRAW_STROKE:
> +        return is_equal_line_attr(&d1->red_drawable->u.stroke.attr,
> +                                  &d2->red_drawable->u.stroke.attr) &&
> +               is_equal_path(d1->red_drawable->u.stroke.path,
> +                             d2->red_drawable->u.stroke.path);
> +    case QXL_DRAW_FILL:
> +        return rect_is_equal(&d1->red_drawable->bbox, &d2->red_drawable
> ->bbox);
> +    default:
> +        return FALSE;
> +    }
> +}
> +
> +static inline int is_same_drawable(Drawable *d1, Drawable *d2)
> +{
> +    if (!is_same_geometry(d1, d2)) {
> +        return FALSE;
> +    }
> +
> +    switch (d1->red_drawable->type) {
> +    case QXL_DRAW_STROKE:
> +        return is_equal_brush(&d1->red_drawable->u.stroke.brush,
> +                              &d2->red_drawable->u.stroke.brush);
> +    case QXL_DRAW_FILL:
> +        return is_equal_brush(&d1->red_drawable->u.fill.brush,
> +                              &d2->red_drawable->u.fill.brush);
> +    default:
> +        return FALSE;
> +    }
> +}
> +
> +static inline int is_primary_surface(DisplayChannel *display, uint32_t
> surface_id)
> +{
> +    if (surface_id == 0) {
> +        return TRUE;
> +    }
> +    return FALSE;
> +}
>  
>  
>  #endif /* DISPLAY_CHANNEL_H_ */
> diff --git a/server/red_worker.c b/server/red_worker.c
> index 23c54e8..2360866 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -75,7 +75,6 @@
>  #define CMD_RING_POLL_RETRIES 200
>  
>  #define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano
> -#define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano
>  #define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
>  #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
>  
> @@ -112,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)
>  {
> @@ -300,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;
> @@ -340,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;
> @@ -404,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)
>  {
> @@ -415,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);
> @@ -436,22 +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);
> -
> -/*
> - * Macros to make iterating over stuff easier
> - * The two collections we iterate over:
> - *  given a channel, iterate over it's clients
> - */
> -
> -#define LINK_TO_DCC(ptr) SPICE_CONTAINEROF(ptr, DisplayChannelClient,  \
> -                                      common.base.channel_link)
> -#define DCC_FOREACH_SAFE(link, next, dcc, channel)                       \
> -    SAFE_FOREACH(link, next, channel,  &(channel)->clients, dcc,
> LINK_TO_DCC(link))
> -
> -
> -#define FOREACH_DCC(display_channel, link, next, dcc)      \
> -    DCC_FOREACH_SAFE(link, next, dcc, RED_CHANNEL(display_channel))
> -
> +static void red_create_surface(DisplayChannel *display, uint32_t surface_id,
> uint32_t width,
> +                               uint32_t height, int32_t stride, uint32_t
> format,
> +                               void *line_0, int data_is_valid, int
> send_client);
>  
>  #define LINK_TO_DPI(ptr) SPICE_CONTAINEROF((ptr), DrawablePipeItem, base)
>  #define DRAWABLE_FOREACH_DPI_SAFE(drawable, link, next, dpi)          \
> @@ -464,38 +424,12 @@ static void
> display_channel_client_release_item_after_push(DisplayChannelClient
>      SAFE_FOREACH(link, next, drawable, &(drawable)->glz_ring, glz,
> LINK_TO_GLZ(link))
>  
>  
> -static int get_stream_id(DisplayChannel *display, Stream *stream)
> -{
> -    return (int)(stream - display->streams_buf);
> -}
> -
> -static void display_stream_free(DisplayChannel *display, Stream *stream)
> -{
> -    stream->next = display->free_streams;
> -    display->free_streams = stream;
> -}
> -
> -static void display_stream_unref(DisplayChannel *display, Stream *stream)
> -{
> -    if (--stream->refs != 0)
> -        return;
> -
> -    spice_warn_if_fail(!ring_item_is_linked(&stream->link));
> -    display_stream_free(display, stream);
> -    display->stream_count--;
> -}
> -
> -static void display_stream_agent_unref(DisplayChannel *display, StreamAgent
> *agent)
> -{
> -    display_stream_unref(display, agent->stream);
> -}
> -
>  static void display_stream_clip_unref(DisplayChannel *display, StreamClipItem
> *item)
>  {
>      if (--item->refs != 0)
>          return;
>  
> -    display_stream_agent_unref(display, item->stream_agent);
> +    stream_agent_unref(display, item->stream_agent);
>      free(item->rects);
>      free(item);
>  }
> @@ -560,40 +494,6 @@ void attach_stream(DisplayChannel *display, Drawable
> *drawable, Stream *stream)
>      }
>  }
>  
> -static void stop_stream(DisplayChannel *display, Stream *stream)
> -{
> -    DisplayChannelClient *dcc;
> -    RingItem *item, *next;
> -
> -    spice_assert(ring_item_is_linked(&stream->link));
> -    spice_assert(!stream->current);
> -    spice_debug("stream %d", get_stream_id(display, stream));
> -    FOREACH_DCC(display, item, next, dcc) {
> -        StreamAgent *stream_agent;
> -
> -        stream_agent = &dcc->stream_agents[get_stream_id(display, stream)];
> -        region_clear(&stream_agent->vis_region);
> -        region_clear(&stream_agent->clip);
> -        spice_assert(!pipe_item_is_linked(&stream_agent->destroy_item));
> -        if (stream_agent->mjpeg_encoder && dcc
> ->use_mjpeg_encoder_rate_control) {
> -            uint64_t stream_bit_rate =
> mjpeg_encoder_get_bit_rate(stream_agent->mjpeg_encoder);
> -
> -            if (stream_bit_rate > dcc->streams_max_bit_rate) {
> -                spice_debug("old max-bit-rate=%.2f new=%.2f",
> -                dcc->streams_max_bit_rate / 8.0 / 1024.0 / 1024.0,
> -                stream_bit_rate / 8.0 / 1024.0 / 1024.0);
> -                dcc->streams_max_bit_rate = stream_bit_rate;
> -            }
> -        }
> -        stream->refs++;
> -        red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &stream_agent
> ->destroy_item);
> -        stream_agent_stats_print(stream_agent);
> -    }
> -    display->streams_size_total -= stream->width * stream->height;
> -    ring_remove(&stream->link);
> -    display_stream_unref(display, stream);
> -}
> -
>  /* fixme: move to display channel */
>  DrawablePipeItem *drawable_pipe_item_new(DisplayChannelClient *dcc,
>                                           Drawable *drawable)
> @@ -639,14 +539,6 @@ QXLInstance* red_worker_get_qxl(RedWorker *worker)
>      return worker->qxl;
>  }
>  
> -static inline int is_primary_surface(DisplayChannel *display, uint32_t
> surface_id)
> -{
> -    if (surface_id == 0) {
> -        return TRUE;
> -    }
> -    return FALSE;
> -}
> -
>  static int validate_drawable_bbox(RedWorker *worker, RedDrawable *drawable)
>  {
>          DrawContext *context;
> @@ -655,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;
> @@ -674,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;
>      }
> @@ -695,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) {
> @@ -707,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);
>          }
>      }
> @@ -717,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);
>  }
>  
> @@ -742,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);
>      }
>  }
> @@ -765,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;
> @@ -782,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) {
> @@ -812,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;
> @@ -928,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) {
> -            stop_stream(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)
>  {
> @@ -1029,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);
>      }
>  }
>  
> @@ -1063,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;
> @@ -1089,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);
> @@ -1097,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;
> @@ -1108,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;
>      }
>  }
> @@ -1132,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;
> @@ -1146,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);
> @@ -1164,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;
>  
> @@ -1191,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;
> @@ -1205,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);
>      }
>  }
>  
> @@ -1296,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));
>          }
> @@ -1343,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
> @@ -1383,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);
>              }
> @@ -1414,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);
> @@ -1435,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);
>                  }
> @@ -1473,19 +1310,13 @@ static void exclude_region(RedWorker *worker, Ring
> *ring, RingItem *ring_item, Q
>      }
>  }
>  
> -static inline int is_opaque_item(TreeItem *item)
> +static void __current_add_drawable(DisplayChannel *display,
> +                                   Drawable *drawable, RingItem *pos)
>  {
> -    return item->type == TREE_ITEM_TYPE_CONTAINER ||
> -           (IS_DRAW_ITEM(item) && ((DrawItem *)item)->effect ==
> QXL_EFFECT_OPAQUE);
> -}
> -
> -static inline void __current_add_drawable(RedWorker *worker, 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);
> @@ -1493,87 +1324,6 @@ static inline void __current_add_drawable(RedWorker
> *worker, Drawable *drawable,
>      drawable->refs++;
>  }
>  
> -static int is_equal_path(RedWorker *worker, SpicePath *path1, SpicePath
> *path2)
> -{
> -    SpicePathSeg *seg1, *seg2;
> -    int i, j;
> -
> -    if (path1->num_segments != path2->num_segments)
> -        return FALSE;
> -
> -    for (i = 0; i < path1->num_segments; i++) {
> -        seg1 = path1->segments[i];
> -        seg2 = path2->segments[i];
> -
> -        if (seg1->flags != seg2->flags ||
> -            seg1->count != seg2->count) {
> -            return FALSE;
> -        }
> -        for (j = 0; j < seg1->count; j++) {
> -            if (seg1->points[j].x != seg2->points[j].x ||
> -                seg1->points[j].y != seg2->points[j].y) {
> -                return FALSE;
> -            }
> -        }
> -    }
> -
> -    return TRUE;
> -}
> -
> -// partial imp
> -static int is_equal_brush(SpiceBrush *b1, SpiceBrush *b2)
> -{
> -    return b1->type == b2->type &&
> -           b1->type == SPICE_BRUSH_TYPE_SOLID &&
> -           b1->u.color == b2->u.color;
> -}
> -
> -// partial imp
> -static int is_equal_line_attr(SpiceLineAttr *a1, SpiceLineAttr *a2)
> -{
> -    return a1->flags == a2->flags &&
> -           a1->style_nseg == a2->style_nseg &&
> -           a1->style_nseg == 0;
> -}
> -
> -// partial imp
> -static int is_same_geometry(RedWorker *worker, Drawable *d1, Drawable *d2)
> -{
> -    if (d1->red_drawable->type != d2->red_drawable->type) {
> -        return FALSE;
> -    }
> -
> -    switch (d1->red_drawable->type) {
> -    case QXL_DRAW_STROKE:
> -        return is_equal_line_attr(&d1->red_drawable->u.stroke.attr,
> -                                  &d2->red_drawable->u.stroke.attr) &&
> -               is_equal_path(worker, d1->red_drawable->u.stroke.path,
> -                             d2->red_drawable->u.stroke.path);
> -    case QXL_DRAW_FILL:
> -        return rect_is_equal(&d1->red_drawable->bbox, &d2->red_drawable
> ->bbox);
> -    default:
> -        return FALSE;
> -    }
> -}
> -
> -static int is_same_drawable(RedWorker *worker, Drawable *d1, Drawable *d2)
> -{
> -    if (!is_same_geometry(worker, d1, d2)) {
> -        return FALSE;
> -    }
> -
> -    switch (d1->red_drawable->type) {
> -    case QXL_DRAW_STROKE:
> -        return is_equal_brush(&d1->red_drawable->u.stroke.brush,
> -                              &d2->red_drawable->u.stroke.brush);
> -    case QXL_DRAW_FILL:
> -        return is_equal_brush(&d1->red_drawable->u.fill.brush,
> -                              &d2->red_drawable->u.fill.brush);
> -    default:
> -        return FALSE;
> -    }
> -}
> -
>  static void detach_stream(DisplayChannel *display, Stream *stream,
>                            int detach_sized)
>  {
> @@ -1662,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);
>      }
> @@ -1781,7 +1531,7 @@ static void
> display_channel_streams_timeout(DisplayChannel *display)
>          item = ring_next(ring, item);
>          if (now >= (stream->last_time + RED_STREAM_TIMEOUT)) {
>              detach_stream_gracefully(display, stream, NULL);
> -            stop_stream(display, stream);
> +            stream_stop(display, stream);
>          }
>      }
>  }
> @@ -2320,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;
> @@ -2342,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);
> @@ -2358,18 +2107,18 @@ static inline int red_current_add_equal(RedWorker
> *worker, DrawItem *item, TreeI
>  
>      switch (item->effect) {
>      case QXL_EFFECT_REVERT_ON_DUP:
> -        if (is_same_drawable(worker, drawable, other_drawable)) {
> +        if (is_same_drawable(drawable, other_drawable)) {
>  
>              DisplayChannelClient *dcc;
>              DrawablePipeItem *dpi;
>              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) {
> @@ -2378,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);
> @@ -2388,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);
>                  }
>              }
> @@ -2400,15 +2149,15 @@ static inline int red_current_add_equal(RedWorker
> *worker, DrawItem *item, TreeI
>          }
>          break;
>      case QXL_EFFECT_OPAQUE_BRUSH:
> -        if (is_same_geometry(worker, drawable, other_drawable)) {
> -            __current_add_drawable(worker, drawable, &other->siblings_link);
> -            remove_drawable(worker, other_drawable);
> -            red_pipes_add_drawable(worker, drawable);
> +        if (is_same_geometry(drawable, other_drawable)) {
> +            __current_add_drawable(display, drawable, &other->siblings_link);
> +            remove_drawable(display, other_drawable);
> +            red_pipes_add_drawable(display, drawable);
>              return TRUE;
>          }
>          break;
>      case QXL_EFFECT_NOP_ON_DUP:
> -        if (is_same_drawable(worker, drawable, other_drawable)) {
> +        if (is_same_drawable(drawable, other_drawable)) {
>              return TRUE;
>          }
>          break;
> @@ -2471,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
> @@ -2500,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;
>              }
> @@ -2512,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;
> @@ -2522,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;
> @@ -2534,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;
>                  }
> @@ -2565,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);
> @@ -2599,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;
> @@ -2627,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 {
> @@ -2687,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) {
> @@ -2715,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;
> @@ -2793,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;
>  
> @@ -2819,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
> @@ -2838,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;
> @@ -2856,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;
>  }
>  
> @@ -2872,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;
>      }
>  
> @@ -2909,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;
> @@ -2936,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) {
> @@ -2966,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;
> @@ -2977,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++;
>      }
>  }
> @@ -2996,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);
>  
> @@ -3008,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;
> @@ -3024,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: {
> @@ -3071,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
> @@ -3085,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");
> @@ -3104,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);
> @@ -3259,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;
> @@ -3291,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;
> @@ -3305,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
> @@ -3357,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;
> @@ -3387,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;
> @@ -3405,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;
>      }
>  
> @@ -3416,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)
> @@ -3540,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;
> @@ -3618,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) {
> @@ -3630,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.
> @@ -3644,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;
> @@ -3705,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);
>      SpiceRect area;
>      RedSurface *surface;
> -    RedWorker *worker;
>  
> -    if (!dcc) {
> -        return;
> -    }
> -    worker = DCC_TO_WORKER(dcc);
> -    surface = &worker->surfaces[surface_id];
> +    surface = &display->surfaces[surface_id];
>      if (!surface->context.canvas) {
>          return;
>      }
> @@ -5140,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;
> @@ -5164,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
> @@ -5176,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 {
> @@ -5193,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;
> @@ -5286,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);
>          }
> @@ -5328,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) {
> @@ -5421,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;
> @@ -5532,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)
> @@ -5565,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)
>  {
> @@ -5621,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;
>  
> @@ -5642,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)) {
> @@ -5654,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);
>          }
>      }
> @@ -5677,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);
>          }
> @@ -5691,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;
> @@ -5719,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;
> @@ -5752,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];
> @@ -5772,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;
> @@ -5811,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;
> @@ -5847,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];
> @@ -5872,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;
> @@ -5904,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;
> @@ -5920,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;
> @@ -5951,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;
> @@ -5965,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];
> @@ -5974,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);
> @@ -6005,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);
> @@ -6020,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;
> @@ -6029,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;
> @@ -6049,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);
> @@ -6063,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;
> @@ -6076,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);
> @@ -6105,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);
> @@ -6125,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];
> @@ -6143,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;
> @@ -6169,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;
> @@ -6205,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;
> @@ -6240,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);
> @@ -6278,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);
> @@ -6304,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];
> @@ -6329,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);
> @@ -6360,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)
>  {
> @@ -6386,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];
> @@ -6412,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);
> @@ -6443,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);
> @@ -6475,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];
> @@ -6494,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);
> @@ -6527,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);
> @@ -6567,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];
> @@ -6590,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");
> @@ -6993,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,
> @@ -7551,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;
> @@ -7623,7 +7309,7 @@ static void detach_and_stop_streams(DisplayChannel
> *display)
>          Stream *stream = SPICE_CONTAINEROF(stream_item, Stream, link);
>  
>          detach_stream_gracefully(display, stream, NULL);
> -        stop_stream(display, stream);
> +        stream_stop(display, stream);
>      }
>  }
>  
> @@ -7646,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;
>      }
>  
> @@ -7665,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;
> @@ -7675,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;
>      }
> @@ -7683,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;
>  
> @@ -7692,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;
>      }
> @@ -7701,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) {
> @@ -7713,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;
> @@ -7758,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 ||
>          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);
> @@ -7776,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);
> @@ -7828,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) {
> @@ -7836,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;
> @@ -8000,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));
> @@ -8014,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);
> @@ -8686,7 +8370,7 @@ static void
> display_channel_client_release_item_before_push(DisplayChannelClient
>      }
>      case PIPE_ITEM_TYPE_STREAM_CREATE: {
>          StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent,
> create_item);
> -        display_stream_agent_unref(display, agent);
> +        stream_agent_unref(display, agent);
>          break;
>      }
>      case PIPE_ITEM_TYPE_STREAM_CLIP:
> @@ -8694,7 +8378,7 @@ static void
> display_channel_client_release_item_before_push(DisplayChannelClient
>          break;
>      case PIPE_ITEM_TYPE_STREAM_DESTROY: {
>          StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent,
> destroy_item);
> -        display_stream_agent_unref(display, agent);
> +        stream_agent_unref(display, agent);
>          break;
>      }
>      case PIPE_ITEM_TYPE_UPGRADE:
> @@ -8749,20 +8433,7 @@ static void
> display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
>      }
>  }
>  
> -static void init_streams(DisplayChannel *display)
> -{
> -    int i;
> -
> -    ring_init(&display->streams);
> -    display->free_streams = NULL;
> -    for (i = 0; i < NUM_STREAMS; i++) {
> -        Stream *stream = &display->streams_buf[i];
> -        ring_item_init(&stream->link);
> -        display_stream_free(display, stream);
> -    }
> -}
> -
> -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 = {
> @@ -8804,13 +8475,16 @@ 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;
> -    init_streams(display_channel);
> -    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);
>  }
>  
>  static void guest_set_client_capabilities(RedWorker *worker)
> @@ -8943,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;
> @@ -8959,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;
> @@ -8971,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);
> +}
>  
> -    red_update_area(worker, rect, surface_id);
> -    free(rect);
> +static void handle_dev_update(void *opaque, void *payload)
> +{
> +    RedWorker *worker = opaque;
> +    RedWorkerMessageUpdate *msg = payload;
> +
> +    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)
> @@ -9044,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)
> @@ -9077,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,
> @@ -9143,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);
> @@ -9162,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;
>  
> @@ -9186,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
> @@ -9212,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);
>  }
> @@ -9241,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)
> @@ -9250,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);
>          }
>      }
>  }
> @@ -9267,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)
> @@ -9285,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
> @@ -9414,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)
> @@ -9935,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);
> @@ -9964,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);
> @@ -9977,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,
> diff --git a/server/stream.c b/server/stream.c
> index 6203f3d..0d8cbd9 100644
> --- a/server/stream.c
> +++ b/server/stream.c
> @@ -53,6 +53,76 @@ void stream_agent_stats_print(StreamAgent *agent)
>  #endif
>  }
>  
> +void stream_stop(DisplayChannel *display, Stream *stream)
> +{
> +    DisplayChannelClient *dcc;
> +    RingItem *item, *next;
> +
> +    spice_return_if_fail(ring_item_is_linked(&stream->link));
> +    spice_return_if_fail(!stream->current);
> +
> +    spice_debug("stream %d", get_stream_id(display, stream));
> +    FOREACH_DCC(display, item, next, dcc) {
> +        StreamAgent *stream_agent;
> +
> +        stream_agent = &dcc->stream_agents[get_stream_id(display, stream)];
> +        region_clear(&stream_agent->vis_region);
> +        region_clear(&stream_agent->clip);
> +        spice_assert(!pipe_item_is_linked(&stream_agent->destroy_item));
> +        if (stream_agent->mjpeg_encoder && dcc
> ->use_mjpeg_encoder_rate_control) {
> +            uint64_t stream_bit_rate =
> mjpeg_encoder_get_bit_rate(stream_agent->mjpeg_encoder);
> +
> +            if (stream_bit_rate > dcc->streams_max_bit_rate) {
> +                spice_debug("old max-bit-rate=%.2f new=%.2f",
> +                dcc->streams_max_bit_rate / 8.0 / 1024.0 / 1024.0,
> +                stream_bit_rate / 8.0 / 1024.0 / 1024.0);
> +                dcc->streams_max_bit_rate = stream_bit_rate;
> +            }
> +        }
> +        stream->refs++;
> +        red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &stream_agent
> ->destroy_item);
> +        stream_agent_stats_print(stream_agent);
> +    }
> +    display->streams_size_total -= stream->width * stream->height;
> +    ring_remove(&stream->link);
> +    stream_unref(display, stream);
> +}
> +
> +static void stream_free(DisplayChannel *display, Stream *stream)
> +{
> +    stream->next = display->free_streams;
> +    display->free_streams = stream;
> +}
> +
> +void stream_init(DisplayChannel *display)
> +{
> +    int i;
> +
> +    ring_init(&display->streams);
> +    display->free_streams = NULL;
> +    for (i = 0; i < NUM_STREAMS; i++) {
> +        Stream *stream = &display->streams_buf[i];
> +        ring_item_init(&stream->link);
> +        stream_free(display, stream);
> +    }
> +}
> +
> +void stream_unref(DisplayChannel *display, Stream *stream)
> +{
> +    if (--stream->refs != 0)
> +        return;
> +
> +    spice_warn_if_fail(!ring_item_is_linked(&stream->link));
> +
> +    stream_free(display, stream);
> +    display->stream_count--;
> +}
> +
> +void stream_agent_unref(DisplayChannel *display, StreamAgent *agent)
> +{
> +    stream_unref(display, agent->stream);
> +}
> +
>  StreamClipItem *stream_clip_item_new(DisplayChannelClient* dcc, StreamAgent
> *agent)
>  {
>      StreamClipItem *item = spice_new(StreamClipItem, 1);
> diff --git a/server/stream.h b/server/stream.h
> index f77fa96..4704937 100644
> --- a/server/stream.h
> +++ b/server/stream.h
> @@ -40,6 +40,9 @@
>  #define RED_STREAM_DEFAULT_HIGH_START_BIT_RATE (10 * 1024 * 1024) // 10Mbps
>  #define RED_STREAM_DEFAULT_LOW_START_BIT_RATE (2.5 * 1024 * 1024) // 2.5Mbps
>  
> +/* move back to display_channel once struct private */
> +typedef struct DisplayChannel DisplayChannel;
> +
>  typedef struct Stream Stream;
>  
>  typedef struct StreamActivateReportItem {
> @@ -132,6 +135,13 @@ struct Stream {
>      uint32_t input_fps;
>  };
>  
> -void stream_agent_stats_print(StreamAgent *agent);
> +void                  stream_init                                  
>  (DisplayChannel *display);
> +void                  stream_stop                                  
>  (DisplayChannel *display,
> +                                                                     Stream
> *stream);
> +void                  stream_unref                                 
>  (DisplayChannel *display,
> +                                                                     Stream
> *stream);
> +void                  stream_agent_unref                           
>  (DisplayChannel *display,
> +                                                                    
>  StreamAgent *agent);
> +void                  stream_agent_stats_print                     
>  (StreamAgent *agent);
>  
>  #endif /* STREAM_H */
> diff --git a/server/tree.h b/server/tree.h
> index 6e83f7a..6249c28 100644
> --- a/server/tree.h
> +++ b/server/tree.h
> @@ -73,6 +73,12 @@ struct DrawItem {
>  #define IS_DRAW_ITEM(item) ((item)->type == TREE_ITEM_TYPE_DRAWABLE)
>  #define DRAW_ITEM(item) ((DrawItem*)(item))
>  
> +static inline int is_opaque_item(TreeItem *item)
> +{
> +    return item->type == TREE_ITEM_TYPE_CONTAINER ||
> +        (IS_DRAW_ITEM(item) && ((DrawItem *)item)->effect ==
> QXL_EFFECT_OPAQUE);
> +}
> +
>  void       tree_item_dump                           (TreeItem *item);
>  Shadow*    shadow_new                               (DrawItem *item, const
> SpicePoint *delta);
>  Container* container_new                            (DrawItem *item);


More information about the Spice-devel mailing list