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

Frediano Ziglio fziglio at redhat.com
Wed Nov 18 03:12:46 PST 2015


> 
> Hi Frediano,
> 
> On Wed, 2015-11-18 at 05:39 -0500, Frediano Ziglio wrote:
> > It would be really helpful if somebody could finally ack or propose another
> > version.
> 
> looking into it right now, just noticed that there is unused function
> _show_tree(). I will send something after lunch.
> 
> Pavel
> 

Yes, was not used even before this patch (checked now).

I think we could remove instead of moving, I'll wait for your proposal.

Frediano

> > 
> > This patch is blocking a lot of others
> > 
> > Frediano
> > 
> > 
> > ----- Original Message -----
> > > From: "Frediano Ziglio" <fziglio at redhat.com>
> > > To: "Jonathon Jongsma" <jjongsma at redhat.com>
> > > Cc: spice-devel at lists.freedesktop.org
> > > Sent: Tuesday, November 17, 2015 9:20:36 AM
> > > Subject: Re: [Spice-devel] [PATCH 02/11] worker: move surfaces to
> > > DisplayChannel
> > > 
> > > 
> > > Ok. this one was painful.Note that in some cases, DCC_TO_DC should be
> > > made safer (there used to be a if !dcc guard in some places, although
> > > that looks wrong anyway)...
> > > ---
> > >  server/display-channel.c |   79 ++++
> > >  server/display-channel.h |   37 +-
> > >  server/red_worker.c      | 1118
> > >  ++++++++++++++++++++--------------------------
> > >  server/red_worker.h      |    2 +
> > >  4 files changed, 599 insertions(+), 637 deletions(-)
> > > 
> > > 
> > > Changes:
> > > - included proposed changes
> > > 
> > > 
> > > diff --git a/server/display-channel.c b/server/display-channel.c
> > > index 63d56b4..3b5a246 100644
> > > --- a/server/display-channel.c
> > > +++ b/server/display-channel.c
> > > @@ -320,3 +320,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 29df313..cae0343 100644
> > > --- a/server/display-channel.h
> > > +++ b/server/display-channel.h
> > > @@ -211,8 +211,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)
> > >  
> > >  
> > > @@ -281,6 +281,30 @@ void                       monitors_config_unref
> > > (MonitorsCo
> > >  #define NUM_TRACE_ITEMS (1 << TRACE_ITEMS_SHIFT)
> > >  #define ITEMS_TRACE_MASK (NUM_TRACE_ITEMS - 1)
> > >  
> > > +typedef struct DrawContext {
> > > +    SpiceCanvas *canvas;
> > > +    int canvas_draws_on_surface;
> > > +    int top_down;
> > > +    uint32_t width;
> > > +    uint32_t height;
> > > +    int32_t stride;
> > > +    uint32_t format;
> > > +    void *line_0;
> > > +} DrawContext;
> > > +
> > > +typedef struct RedSurface {
> > > +    uint32_t refs;
> > > +    Ring current;
> > > +    Ring current_list;
> > > +    DrawContext context;
> > > +
> > > +    Ring depend_on_me;
> > > +    QRegion draw_dirty_region;
> > > +
> > > +    //fix me - better handling here
> > > +    QXLReleaseInfoExt create, destroy;
> > > +} RedSurface;
> > > +
> > >  #define NUM_DRAWABLES 1000
> > >  typedef struct _Drawable _Drawable;
> > >  struct _Drawable {
> > > @@ -319,6 +343,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;
> > >  
> > > @@ -377,6 +405,11 @@ int
> > > display_channel_get_streams_timeout       (DisplayCha
> > >  void                       display_channel_compress_stats_print
> > >        (const
> > >  DisplayChannel *display);
> > >  void                       display_channel_compress_stats_reset
> > >  (DisplayChannel *display);
> > >  void                       display_channel_drawable_unref
> > >  (DisplayChannel *display, Drawable *drawable);
> > > +void                       display_channel_surface_unref
> > > (DisplayChannel *display,
> > > +
> > > uint32_t
> > > surface_id);
> > > +bool                       display_channel_surface_has_canvas
> > > (DisplayChannel *display,
> > > +
> > > uint32_t
> > > surface_id);
> > > +void                       display_channel_show_tree
> > > (DisplayChannel *display);
> > >  
> > >  static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
> > >  {
> > > diff --git a/server/red_worker.c b/server/red_worker.c
> > > index 73faeee..dba18ee 100644
> > > --- a/server/red_worker.c
> > > +++ b/server/red_worker.c
> > > @@ -209,30 +209,6 @@ typedef struct UpgradeItem {
> > >      SpiceClipRects *rects;
> > >  } UpgradeItem;
> > >  
> > > -typedef struct DrawContext {
> > > -    SpiceCanvas *canvas;
> > > -    int canvas_draws_on_surface;
> > > -    int top_down;
> > > -    uint32_t width;
> > > -    uint32_t height;
> > > -    int32_t stride;
> > > -    uint32_t format;
> > > -    void *line_0;
> > > -} DrawContext;
> > > -
> > > -typedef struct RedSurface {
> > > -    uint32_t refs;
> > > -    Ring current;
> > > -    Ring current_list;
> > > -    DrawContext context;
> > > -
> > > -    Ring depend_on_me;
> > > -    QRegion draw_dirty_region;
> > > -
> > > -    //fix me - better handling here
> > > -    QXLReleaseInfoExt create, destroy;
> > > -} RedSurface;
> > > -
> > >  struct RedWorker {
> > >      pthread_t thread;
> > >      clockid_t clockid;
> > > @@ -249,10 +225,6 @@ struct RedWorker {
> > >      CursorChannel *cursor_channel;
> > >      uint32_t cursor_poll_tries;
> > >  
> > > -    RedSurface surfaces[NUM_SURFACES];
> > > -    uint32_t n_surfaces;
> > > -    SpiceImageSurfaces image_surfaces;
> > > -
> > >      uint32_t red_drawable_count;
> > >      uint32_t glz_drawable_count;
> > >      uint32_t bits_unique;
> > > @@ -306,13 +278,13 @@ typedef struct BitmapData {
> > >      SpiceRect lossy_rect;
> > >  } BitmapData;
> > >  
> > > -static inline int validate_surface(RedWorker *worker, uint32_t
> > > surface_id);
> > > +static inline int validate_surface(DisplayChannel *display, uint32_t
> > > surface_id);
> > >  
> > > -static void red_draw_qxl_drawable(RedWorker *worker, Drawable
> > > *drawable);
> > > -static void red_current_flush(RedWorker *worker, int surface_id);
> > > -static void red_draw_drawable(RedWorker *worker, Drawable *item);
> > > -static void red_update_area(RedWorker *worker, const SpiceRect *area,
> > > int
> > > surface_id);
> > > -static void red_update_area_till(RedWorker *worker, const SpiceRect
> > > *area,
> > > int surface_id,
> > > +static void red_draw_qxl_drawable(DisplayChannel *display, Drawable
> > > *drawable);
> > > +static void red_current_flush(DisplayChannel *display, int surface_id);
> > > +static void red_draw_drawable(DisplayChannel *display, Drawable *item);
> > > +static void red_update_area(DisplayChannel *display, const SpiceRect
> > > *area,
> > > int surface_id);
> > > +static void red_update_area_till(DisplayChannel *display, const
> > > SpiceRect
> > > *area, int surface_id,
> > >                                   Drawable *last);
> > >  static void detach_stream(DisplayChannel *display, Stream *stream, int
> > >  detach_sized);
> > >  static inline void display_channel_stream_maintenance(DisplayChannel
> > >  *display, Drawable *candidate, Drawable *sect);
> > > @@ -329,6 +301,9 @@ static void
> > > display_channel_client_release_item_before_push(DisplayChannelClient
> > >                                                              PipeItem
> > > *item);
> > >  static void
> > >  display_channel_client_release_item_after_push(DisplayChannelClient
> > >  *dcc,
> > >                                                             PipeItem
> > >                                                             *item);
> > > +static void red_create_surface(DisplayChannel *display, uint32_t
> > > surface_id,
> > > uint32_t width,
> > > +                               uint32_t height, int32_t stride, uint32_t
> > > format,
> > > +                               void *line_0, int data_is_valid, int
> > > send_client);
> > >  
> > >  #define LINK_TO_DPI(ptr) SPICE_CONTAINEROF((ptr), DrawablePipeItem,
> > >  base)
> > >  #define DRAWABLE_FOREACH_DPI_SAFE(drawable, link, next, dpi)          \
> > > @@ -448,8 +423,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;
> > > @@ -467,15 +442,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;
> > >      }
> > > @@ -488,7 +463,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) {
> > > @@ -500,7 +475,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);
> > >          }
> > >      }
> > > @@ -510,7 +485,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);
> > >  }
> > >  
> > > @@ -535,13 +510,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);
> > >      }
> > >  }
> > > @@ -558,7 +533,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;
> > > @@ -575,13 +550,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) {
> > > @@ -605,8 +580,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;
> > > @@ -721,59 +694,6 @@ static void drawables_init(DisplayChannel *display)
> > >  }
> > >  
> > >  
> > > -static void stop_streams(DisplayChannel *display)
> > > -{
> > > -    Ring *ring = &display->streams;
> > > -    RingItem *item = ring_get_head(ring);
> > > -
> > > -    while (item) {
> > > -        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> > > -        item = ring_next(ring, item);
> > > -        if (!stream->current) {
> > > -            stream_stop(display, stream);
> > > -        } else {
> > > -            spice_info("attached stream");
> > > -        }
> > > -    }
> > > -
> > > -    display->next_item_trace = 0;
> > > -    memset(display->items_trace, 0, sizeof(display->items_trace));
> > > -}
> > > -
> > > -static void red_surface_unref(RedWorker *worker, uint32_t surface_id)
> > > -{
> > > -    DisplayChannel *display = worker->display_channel;
> > > -    RedSurface *surface = &worker->surfaces[surface_id];
> > > -    DisplayChannelClient *dcc;
> > > -    RingItem *link, *next;
> > > -
> > > -    if (--surface->refs != 0) {
> > > -        return;
> > > -    }
> > > -
> > > -    // only primary surface streams are supported
> > > -    if (is_primary_surface(worker->display_channel, surface_id)) {
> > > -        stop_streams(display);
> > > -    }
> > > -    spice_assert(surface->context.canvas);
> > > -
> > > -    surface->context.canvas->ops->destroy(surface->context.canvas);
> > > -    if (surface->create.info) {
> > > -        worker->qxl->st->qif->release_resource(worker->qxl,
> > > surface->create);
> > > -    }
> > > -    if (surface->destroy.info) {
> > > -        worker->qxl->st->qif->release_resource(worker->qxl,
> > > surface->destroy);
> > > -    }
> > > -
> > > -    region_destroy(&surface->draw_dirty_region);
> > > -    surface->context.canvas = NULL;
> > > -    FOREACH_DCC(worker->display_channel, link, next, dcc) {
> > > -        dcc_push_destroy_surface(dcc, surface_id);
> > > -    }
> > > -
> > > -    spice_warn_if(!ring_is_empty(&surface->depend_on_me));
> > > -}
> > > -
> > >  static inline void set_surface_release_info(QXLReleaseInfoExt
> > >  *release_info_ext,
> > >                                              QXLReleaseInfo
> > >                                              *release_info,
> > >                                              uint32_t group_id)
> > >  {
> > > @@ -822,7 +742,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);
> > >      }
> > >  }
> > >  
> > > @@ -856,7 +776,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;
> > > @@ -886,12 +806,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;
> > > @@ -900,15 +820,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);
> > >      draw_item_remove_shadow(&item->tree_item);
> > >      ring_remove(&item->tree_item.base.siblings_link);
> > > @@ -918,23 +836,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;
> > >  
> > > @@ -959,13 +878,14 @@ static inline void current_remove(RedWorker
> > > *worker,
> > > TreeItem *item)
> > >      }
> > >  }
> > >  
> > > -static void current_remove_all(RedWorker *worker, int surface_id)
> > > +static void current_remove_all(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);
> > >      }
> > >  }
> > >  
> > > @@ -1050,25 +970,26 @@ 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));
> > >          }
> > >      }
> > >  }
> > >  
> > > -static inline void __exclude_region(RedWorker *worker, Ring *ring,
> > > TreeItem
> > > *item, QRegion *rgn,
> > > -                                    Ring **top_ring, Drawable
> > > *frame_candidate)
> > > +static void __exclude_region(DisplayChannel *display, Ring *ring,
> > > TreeItem
> > > *item, QRegion *rgn,
> > > +                             Ring **top_ring, Drawable *frame_candidate)
> > >  {
> > >      QRegion and_rgn;
> > >  #ifdef RED_WORKER_STAT
> > > +    RedWorker *worker = COMMON_CHANNEL(display)->worker;
> > >      stat_time_t start_time = stat_now(worker->clockid);
> > >  #endif
> > >  
> > > @@ -1104,7 +1025,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);
> > >              }
> > > @@ -1132,13 +1053,14 @@ static inline void __exclude_region(RedWorker
> > > *worker, Ring *ring, TreeItem *ite
> > >          }
> > >      }
> > >      region_destroy(&and_rgn);
> > > -    stat_add(&worker->display_channel->__exclude_stat, start_time);
> > > +    stat_add(&display->__exclude_stat, start_time);
> > >  }
> > >  
> > > -static void exclude_region(RedWorker *worker, Ring *ring, RingItem
> > > *ring_item, QRegion *rgn,
> > > -                           TreeItem **last, Drawable *frame_candidate)
> > > +static void exclude_region(DisplayChannel *display, Ring *ring, RingItem
> > > *ring_item,
> > > +                           QRegion *rgn, TreeItem **last, Drawable
> > > *frame_candidate)
> > >  {
> > >  #ifdef RED_WORKER_STAT
> > > +    RedWorker *worker = COMMON_CHANNEL(display)->worker;
> > >      stat_time_t start_time = stat_now(worker->clockid);
> > >  #endif
> > >      Ring *top_ring;
> > > @@ -1156,12 +1078,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);
> > >                  }
> > > @@ -1176,7 +1098,7 @@ static void exclude_region(RedWorker *worker, Ring
> > > *ring, RingItem *ring_item, Q
> > >              }
> > >  
> > >              if (region_is_empty(rgn)) {
> > > -                stat_add(&worker->display_channel->exclude_stat,
> > > start_time);
> > > +                stat_add(&display->exclude_stat, start_time);
> > >                  return;
> > >              }
> > >          }
> > > @@ -1184,7 +1106,7 @@ static void exclude_region(RedWorker *worker, Ring
> > > *ring, RingItem *ring_item, Q
> > >          while ((last && *last == (TreeItem *)ring_item) ||
> > >                 !(ring_item = ring_next(ring, ring_item))) {
> > >              if (ring == top_ring) {
> > > -                stat_add(&worker->display_channel->exclude_stat,
> > > start_time);
> > > +                stat_add(&display->exclude_stat, start_time);
> > >                  return;
> > >              }
> > >              ring_item = &container->base.siblings_link;
> > > @@ -1194,13 +1116,13 @@ static void exclude_region(RedWorker *worker,
> > > Ring
> > > *ring, RingItem *ring_item, Q
> > >      }
> > >  }
> > >  
> > > -static inline void current_add_drawable(RedWorker *worker, Drawable
> > > *drawable, RingItem *pos)
> > > +static void current_add_drawable(DisplayChannel *display,
> > > +                                 Drawable *drawable, RingItem *pos)
> > >  {
> > > -    DisplayChannel *display = worker->display_channel;
> > >      RedSurface *surface;
> > >      uint32_t surface_id = drawable->surface_id;
> > >  
> > > -    surface = &worker->surfaces[surface_id];
> > > +    surface = &display->surfaces[surface_id];
> > >      ring_add_after(&drawable->tree_item.base.siblings_link, pos);
> > >      ring_add(&display->current_list, &drawable->list_link);
> > >      ring_add(&surface->current_list, &drawable->surface_list_link);
> > > @@ -1296,9 +1218,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);
> > >      }
> > > @@ -1941,9 +1863,8 @@ static void
> > > display_channel_stream_maintenance(DisplayChannel *display,
> > >      }
> > >  }
> > >  
> > > -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;
> > > @@ -1963,14 +1884,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);
> > > @@ -1986,11 +1907,11 @@ static inline int red_current_add_equal(RedWorker
> > > *worker, DrawItem *item, TreeI
> > >              RingItem *worker_ring_item, *dpi_ring_item;
> > >  
> > >              other_drawable->refs++;
> > > -            current_remove_drawable(worker, other_drawable);
> > > +            current_remove_drawable(display, other_drawable);
> > >  
> > >              /* sending the drawable to clients that already received
> > >               * (or will receive) other_drawable */
> > > -            worker_ring_item =
> > > ring_get_head(&RED_CHANNEL(worker->display_channel)->clients);
> > > +            worker_ring_item =
> > > ring_get_head(&RED_CHANNEL(display)->clients);
> > >              dpi_ring_item = ring_get_head(&other_drawable->pipes);
> > >              /* dpi contains a sublist of dcc's, ordered the same */
> > >              while (worker_ring_item) {
> > > @@ -1999,7 +1920,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);
> > > @@ -2009,7 +1930,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);
> > >                  }
> > >              }
> > > @@ -2022,9 +1943,9 @@ static inline int red_current_add_equal(RedWorker
> > > *worker, DrawItem *item, TreeI
> > >          break;
> > >      case QXL_EFFECT_OPAQUE_BRUSH:
> > >          if (is_same_geometry(drawable, other_drawable)) {
> > > -            current_add_drawable(worker, drawable,
> > > &other->siblings_link);
> > > -            remove_drawable(worker, other_drawable);
> > > -            red_pipes_add_drawable(worker, drawable);
> > > +            current_add_drawable(display, drawable,
> > > &other->siblings_link);
> > > +            remove_drawable(display, other_drawable);
> > > +            red_pipes_add_drawable(display, drawable);
> > >              return TRUE;
> > >          }
> > >          break;
> > > @@ -2092,10 +2013,11 @@ static void red_use_stream_trace(DisplayChannel
> > > *display, Drawable *drawable)
> > >      }
> > >  }
> > >  
> > > -static inline int current_add(RedWorker *worker, Ring *ring, Drawable
> > > *drawable)
> > > +static int current_add(DisplayChannel *display, Ring *ring, Drawable
> > > *drawable)
> > >  {
> > >      DrawItem *item = &drawable->tree_item;
> > >  #ifdef RED_WORKER_STAT
> > > +    RedWorker *worker = COMMON_CHANNEL(display)->worker;
> > >      stat_time_t start_time = stat_now(worker->clockid);
> > >  #endif
> > >      RingItem *now;
> > > @@ -2121,8 +2043,8 @@ static inline int current_add(RedWorker *worker,
> > > Ring
> > > *ring, Drawable *drawable)
> > >          } else if (sibling->type != TREE_ITEM_TYPE_SHADOW) {
> > >              if (!(test_res & REGION_TEST_RIGHT_EXCLUSIVE) &&
> > >                                                     !(test_res &
> > >                                                     REGION_TEST_LEFT_EXCLUSI
> > > VE)
> > >                                                     &&
> > > -
> > > red_current_add_equal(worker,
> > > item, sibling)) {
> > > -                stat_add(&worker->display_channel->add_stat,
> > > start_time);
> > > +
> > > red_current_add_equal(display,
> > > item, sibling)) {
> > > +                stat_add(&display->add_stat, start_time);
> > >                  return FALSE;
> > >              }
> > >  
> > > @@ -2133,7 +2055,7 @@ static inline int current_add(RedWorker *worker,
> > > Ring
> > > *ring, Drawable *drawable)
> > >                  if ((shadow = tree_item_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;
> > > @@ -2143,7 +2065,7 @@ static inline int current_add(RedWorker *worker,
> > > Ring
> > > *ring, Drawable *drawable)
> > >                      region_or(&exclude_rgn, &shadow->on_hold);
> > >                  }
> > >                  now = now->prev;
> > > -                current_remove(worker, sibling);
> > > +                current_remove(display, sibling);
> > >                  now = ring_next(ring, now);
> > >                  if (shadow || skip) {
> > >                      exclude_base = now;
> > > @@ -2155,7 +2077,7 @@ static inline int current_add(RedWorker *worker,
> > > Ring
> > > *ring, Drawable *drawable)
> > >                  Container *container;
> > >  
> > >                  if (exclude_base) {
> > > -                    exclude_region(worker, ring, exclude_base,
> > > &exclude_rgn,
> > > NULL, NULL);
> > > +                    exclude_region(display, ring, exclude_base,
> > > &exclude_rgn, NULL, NULL);
> > >                      region_clear(&exclude_rgn);
> > >                      exclude_base = NULL;
> > >                  }
> > > @@ -2186,35 +2108,35 @@ static inline int current_add(RedWorker *worker,
> > > Ring
> > > *ring, Drawable *drawable)
> > >      }
> > >      if (item->effect == QXL_EFFECT_OPAQUE) {
> > >          region_or(&exclude_rgn, &item->base.rgn);
> > > -        exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL,
> > > drawable);
> > > -        red_use_stream_trace(worker->display_channel, drawable);
> > > -        streams_update_visible_region(worker->display_channel,
> > > drawable);
> > > +        exclude_region(display, ring, exclude_base, &exclude_rgn, NULL,
> > > drawable);
> > > +        red_use_stream_trace(display, drawable);
> > > +        streams_update_visible_region(display, drawable);
> > >          /*
> > >           * Performing the insertion after exclude_region for
> > >           * safety (todo: Not sure if exclude_region can affect the
> > >           drawable
> > >           * if it is added to the tree before calling exclude_region).
> > >           */
> > > -        current_add_drawable(worker, drawable, ring);
> > > +        current_add_drawable(display, drawable, ring);
> > >      } else {
> > >          /*
> > >           * red_detach_streams_behind can affect the current tree since
> > >           it
> > >           may
> > >           * trigger calls to update_area. Thus, the drawable should be
> > >           added
> > >           to the tree
> > >           * before calling red_detach_streams_behind
> > >           */
> > > -        current_add_drawable(worker, drawable, ring);
> > > -        if (is_primary_surface(worker->display_channel,
> > > drawable->surface_id)) {
> > > -            detach_streams_behind(worker->display_channel,
> > > &drawable->tree_item.base.rgn, drawable);
> > > +        current_add_drawable(display, drawable, ring);
> > > +        if (is_primary_surface(display, drawable->surface_id)) {
> > > +            detach_streams_behind(display,
> > > &drawable->tree_item.base.rgn,
> > > drawable);
> > >          }
> > >      }
> > >      region_destroy(&exclude_rgn);
> > > -    stat_add(&worker->display_channel->add_stat, start_time);
> > > +    stat_add(&display->add_stat, start_time);
> > >      return TRUE;
> > >  }
> > >  
> > > -static inline int current_add_with_shadow(RedWorker *worker, Ring *ring,
> > > Drawable *item)
> > > +static int current_add_with_shadow(DisplayChannel *display, Ring *ring,
> > > Drawable *item)
> > >  {
> > > -    DisplayChannel *display = worker->display_channel;
> > >  #ifdef RED_WORKER_STAT
> > > +    RedWorker *worker = COMMON_CHANNEL(display)->worker;
> > >      stat_time_t start_time = stat_now(worker->clockid);
> > >      ++display->add_with_shadow_count;
> > >  #endif
> > > @@ -2239,11 +2161,11 @@ static inline int
> > > current_add_with_shadow(RedWorker
> > > *worker, Ring *ring, Drawabl
> > >      }
> > >  
> > >      ring_add(ring, &shadow->base.siblings_link);
> > > -    current_add_drawable(worker, item, ring);
> > > +    current_add_drawable(display, item, ring);
> > >      if (item->tree_item.effect == QXL_EFFECT_OPAQUE) {
> > >          QRegion exclude_rgn;
> > >          region_clone(&exclude_rgn, &item->tree_item.base.rgn);
> > > -        exclude_region(worker, ring, &shadow->base.siblings_link,
> > > &exclude_rgn, NULL, NULL);
> > > +        exclude_region(display, ring, &shadow->base.siblings_link,
> > > &exclude_rgn, NULL, NULL);
> > >          region_destroy(&exclude_rgn);
> > >          streams_update_visible_region(display, item);
> > >      } else {
> > > @@ -2320,18 +2242,17 @@ void print_stats(DisplayChannel *display)
> > >  #endif
> > >  }
> > >  
> > > -static int red_add_drawable(RedWorker *worker, Drawable *drawable)
> > > + static int red_add_drawable(DisplayChannel *display, Drawable
> > > *drawable)
> > >  {
> > > -    DisplayChannel *display = worker->display_channel;
> > >      int ret = FALSE, surface_id = drawable->surface_id;
> > >      RedDrawable *red_drawable = drawable->red_drawable;
> > > -    Ring *ring = &worker->surfaces[surface_id].current;
> > > +    Ring *ring = &display->surfaces[surface_id].current;
> > >  
> > >      if (has_shadow(red_drawable)) {
> > > -        ret = current_add_with_shadow(worker, ring, drawable);
> > > +        ret = current_add_with_shadow(display, ring, drawable);
> > >      } else {
> > >          drawable_update_streamable(display, drawable);
> > > -        ret = current_add(worker, ring, drawable);
> > > +        ret = current_add(display, ring, drawable);
> > >      }
> > >  
> > >  #ifdef RED_WORKER_STAT
> > > @@ -2341,15 +2262,15 @@ static int red_add_drawable(RedWorker *worker,
> > > Drawable *drawable)
> > >      return ret;
> > >  }
> > >  
> > > -static void red_get_area(RedWorker *worker, int surface_id, const
> > > SpiceRect
> > > *area, uint8_t *dest,
> > > -                         int dest_stride, int update)
> > > +static void red_get_area(DisplayChannel *display, int surface_id, const
> > > SpiceRect *area,
> > > +                         uint8_t *dest, int dest_stride, int update)
> > >  {
> > >      SpiceCanvas *canvas;
> > >      RedSurface *surface;
> > >  
> > > -    surface = &worker->surfaces[surface_id];
> > > +    surface = &display->surfaces[surface_id];
> > >      if (update) {
> > > -        red_update_area(worker, area, surface_id);
> > > +        red_update_area(display, area, surface_id);
> > >      }
> > >  
> > >      canvas = surface->context.canvas;
> > > @@ -2401,7 +2322,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;
> > >  
> > > @@ -2427,7 +2348,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
> > > @@ -2446,9 +2367,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;
> > > @@ -2464,12 +2384,11 @@ static bool free_one_drawable(RedWorker *worker,
> > > int
> > > force_glz_free)
> > >              red_display_free_glz_drawable(glz->dcc, glz);
> > >          }
> > >      }
> > > -    red_draw_drawable(worker, drawable);
> > > +    red_draw_drawable(display, drawable);
> > >      container = drawable->tree_item.base.container;
> > >  
> > > -    current_remove_drawable(worker, drawable);
> > > +    current_remove_drawable(display, drawable);
> > >      container_cleanup(container);
> > > -
> > >      return TRUE;
> > >  }
> > >  
> > > @@ -2480,19 +2399,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;
> > >      }
> > >  
> > > @@ -2517,24 +2436,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;
> > > @@ -2544,22 +2463,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) {
> > > @@ -2574,7 +2492,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;
> > > @@ -2585,7 +2503,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++;
> > >      }
> > >  }
> > > @@ -2604,7 +2522,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);
> > >  
> > > @@ -2616,13 +2534,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;
> > > @@ -2632,38 +2551,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: {
> > > @@ -2679,7 +2596,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
> > > @@ -2693,13 +2610,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);
> > > +        red_handle_depends_on_target_surface(display, surface_id);
> > >          /* note that red_handle_depends_on_target_surface must be called
> > >          before current_remove_all.
> > >             otherwise "current" will hold items that other drawables may
> > >             depend on, and then
> > >             current_remove_all will remove them from the pipe. */
> > > -        current_remove_all(worker, surface_id);
> > > -        red_clear_surface_drawables_from_pipes(worker, surface_id,
> > > FALSE);
> > > -        red_surface_unref(worker, surface_id);
> > > +        current_remove_all(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");
> > > @@ -2712,31 +2629,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);
> > > @@ -2867,17 +2783,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;
> > > @@ -2899,10 +2815,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;
> > > @@ -2913,7 +2828,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
> > > @@ -2965,22 +2880,21 @@ static void red_update_area_till(RedWorker
> > > *worker,
> > > const SpiceRect *area, int s
> > >          now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
> > >          now->refs++;
> > >          container = now->tree_item.base.container;
> > > -        current_remove_drawable(worker, now);
> > > +        current_remove_drawable(display, now);
> > >          container_cleanup(container);
> > >          /* red_draw_drawable may call red_update_area for the surfaces
> > > 'now'
> > >          depends on. Notice,
> > >             that it is valid to call red_update_area in this case and not
> > >             red_update_area_till:
> > >             It is impossible that there was newer item then 'last' in one
> > >             of
> > >             the surfaces
> > >             that red_update_area is called for, Otherwise, 'now' would
> > >             have
> > >             already been rendered.
> > >             See the call for red_handle_depends_on_target_surface in
> > >             red_process_draw */
> > > -        red_draw_drawable(worker, now);
> > > +        red_draw_drawable(display, now);
> > >          display_channel_drawable_unref(display, now);
> > >      } while (now != surface_last);
> > > -    validate_area(worker, area, surface_id);
> > > +    validate_area(display, area, surface_id);
> > >  }
> > >  
> > > -static void red_update_area(RedWorker *worker, const SpiceRect *area,
> > > int
> > > surface_id)
> > > +static void red_update_area(DisplayChannel *display, const SpiceRect
> > > *area,
> > > int surface_id)
> > >  {
> > > -    DisplayChannel *display = worker->display_channel;
> > >      RedSurface *surface;
> > >      Ring *ring;
> > >      RingItem *ring_item;
> > > @@ -2995,7 +2909,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;
> > > @@ -3013,7 +2927,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;
> > >      }
> > >  
> > > @@ -3024,12 +2938,12 @@ static void red_update_area(RedWorker *worker,
> > > const
> > > SpiceRect *area, int surfac
> > >          now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
> > >          now->refs++;
> > >          container = now->tree_item.base.container;
> > > -        current_remove_drawable(worker, now);
> > > +        current_remove_drawable(display, now);
> > >          container_cleanup(container);
> > > -        red_draw_drawable(worker, now);
> > > +        red_draw_drawable(display, now);
> > >          display_channel_drawable_unref(display, now);
> > >      } while (now != last);
> > > -    validate_area(worker, area, surface_id);
> > > +    validate_area(display, area, surface_id);
> > >  }
> > >  
> > >  static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size,
> > > int
> > >  *ring_is_empty)
> > > @@ -3148,11 +3062,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;
> > > @@ -3226,7 +3140,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) {
> > > @@ -3238,12 +3152,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);
> > >      }
> > > -    current_remove_all(worker, surface_id);
> > > +    current_remove_all(display, surface_id);
> > >  }
> > >  
> > >  // adding the pipe item after pos. If pos == NULL, adding to head.
> > > @@ -3252,8 +3166,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;
> > > @@ -3313,15 +3226,16 @@ static ImageItem
> > > *red_add_surface_area_image(DisplayChannelClient *dcc, int surf
> > >  
> > >  static void red_push_surface_image(DisplayChannelClient *dcc, int
> > >  surface_id)
> > >  {
> > > +    DisplayChannel *display;
> > >      SpiceRect area;
> > >      RedSurface *surface;
> > > -    RedWorker *worker;
> > >  
> > >      if (!dcc) {
> > >          return;
> > >      }
> > > -    worker = DCC_TO_WORKER(dcc);
> > > -    surface = &worker->surfaces[surface_id];
> > > +
> > > +    display = DCC_TO_DC(dcc);
> > > +    surface = &display->surfaces[surface_id];
> > >      if (!surface->context.canvas) {
> > >          return;
> > >      }
> > > @@ -4751,8 +4665,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;
> > > @@ -4775,7 +4688,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
> > > @@ -4787,7 +4700,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 {
> > > @@ -4804,13 +4717,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;
> > > @@ -4897,16 +4810,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);
> > >          }
> > > @@ -4939,10 +4852,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) {
> > > @@ -5032,7 +4945,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;
> > > @@ -5143,8 +5056,7 @@ static inline int
> > > drawable_depends_on_areas(Drawable
> > > *drawable,
> > >  }
> > >  
> > >  
> > > -static int pipe_rendered_drawables_intersect_with_areas(RedWorker
> > > *worker,
> > > -
> > >                                                         DisplayChannelClien
> > > t
> > > *dcc,
> > > +static int
> > > pipe_rendered_drawables_intersect_with_areas(DisplayChannelClient
> > > *dcc,
> > >                                                          int
> > >                                                          surface_ids[],
> > >                                                          SpiceRect
> > >                                                          *surface_areas[],
> > >                                                          int
> > >                                                          num_surfaces)
> > > @@ -5176,8 +5088,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_i
> > > d,
> > >                                                              SpiceRect
> > >                                                              *first_area)
> > >  {
> > > @@ -5232,15 +5143,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;
> > >  
> > > @@ -5253,7 +5164,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))
> > >                                                               {
> > > @@ -5265,7 +5176,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);
> > >          }
> > >      }
> > > @@ -5288,11 +5199,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_i
> > > d,
> > >                                                           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);
> > >          }
> > > @@ -5302,10 +5213,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;
> > > @@ -5330,13 +5240,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;
> > > @@ -5363,9 +5272,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];
> > > @@ -5383,18 +5292,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;
> > > @@ -5422,13 +5330,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;
> > > @@ -5458,14 +5365,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];
> > > @@ -5483,19 +5390,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;
> > > @@ -5515,13 +5421,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;
> > > @@ -5531,23 +5436,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;
> > > @@ -5562,10 +5466,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;
> > > @@ -5576,7 +5479,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];
> > > @@ -5585,16 +5488,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);
> > > @@ -5616,10 +5518,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);
> > > @@ -5631,7 +5532,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;
> > > @@ -5640,14 +5541,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;
> > > @@ -5660,10 +5560,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);
> > > @@ -5674,7 +5573,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;
> > > @@ -5687,14 +5586,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);
> > > @@ -5716,10 +5613,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);
> > > @@ -5736,7 +5632,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];
> > > @@ -5754,15 +5650,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;
> > > @@ -5780,25 +5675,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;
> > > @@ -5816,25 +5709,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;
> > > @@ -5851,18 +5742,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);
> > > @@ -5889,10 +5778,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);
> > > @@ -5915,8 +5803,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];
> > > @@ -5940,15 +5828,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);
> > > @@ -5971,8 +5858,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)
> > >  {
> > > @@ -5997,8 +5883,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];
> > > @@ -6023,15 +5909,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);
> > > @@ -6054,10 +5939,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);
> > > @@ -6086,7 +5970,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];
> > > @@ -6105,15 +5989,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);
> > > @@ -6138,10 +6021,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);
> > > @@ -6178,7 +6060,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];
> > > @@ -6201,111 +6083,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");
> > > @@ -6604,9 +6487,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,
> > > @@ -7162,24 +7045,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;
> > > @@ -7257,15 +7122,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;
> > >      }
> > >  
> > > @@ -7276,8 +7141,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;
> > > @@ -7286,7 +7151,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;
> > >      }
> > > @@ -7294,8 +7159,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;
> > >  
> > > @@ -7303,7 +7169,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;
> > >      }
> > > @@ -7312,11 +7178,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) {
> > > @@ -7324,18 +7189,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;
> > > @@ -7369,17 +7234,24 @@ static SurfaceCreateItem
> > > *get_surface_create_item(
> > >  
> > >  static inline void red_create_surface_item(DisplayChannelClient *dcc,
> > >  int
> > >  surface_id)
> > >  {
> > > +    DisplayChannel *display;
> > >      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;
> > > +    uint32_t flags;
> > > +
> > > +    if (!dcc) {
> > > +        return;
> > > +    }
> > > +
> > > +    display = DCC_TO_DC(dcc);
> > > +    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 (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);
> > > @@ -7387,33 +7259,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);
> > > @@ -7439,7 +7310,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) {
> > > @@ -7447,24 +7318,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;
> > > @@ -7611,8 +7482,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));
> > > @@ -7625,8 +7495,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);
> > > @@ -8360,7 +8230,8 @@ static void
> > > display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
> > >      }
> > >  }
> > >  
> > > -static void display_channel_create(RedWorker *worker, int migrate, int
> > > stream_video)
> > > +static void display_channel_create(RedWorker *worker, int migrate, int
> > > stream_video,
> > > +                                   uint32_t n_surfaces)
> > >  {
> > >      DisplayChannel *display_channel;
> > >      ChannelCbs cbs = {
> > > @@ -8405,12 +8276,15 @@ static void display_channel_create(RedWorker
> > > *worker,
> > > int migrate, int stream_vi
> > >      stat_compress_init(&display_channel->jpeg_alpha_stat, "jpeg_alpha");
> > >      stat_compress_init(&display_channel->lz4_stat, "lz4");
> > >  
> > > +    display_channel->n_surfaces = n_surfaces;
> > >      display_channel->num_renderers = num_renderers;
> > >      memcpy(display_channel->renderers, renderers,
> > >      sizeof(display_channel->renderers));
> > >      display_channel->renderer = RED_RENDERER_INVALID;
> > > -    image_cache_init(&display_channel->image_cache);
> > > +
> > >      ring_init(&display_channel->current_list);
> > > +    image_surface_init(display_channel);
> > >      drawables_init(display_channel);
> > > +    image_cache_init(&display_channel->image_cache);
> > >      display_channel->stream_video = stream_video;
> > >      display_channel_init_streams(display_channel);
> > >  }
> > > @@ -8545,14 +8419,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;
> > > @@ -8561,9 +8434,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;
> > > @@ -8573,67 +8443,60 @@ static void
> > > surface_dirty_region_to_rects(RedSurface
> > > *surface,
> > >      free(dirty_rects);
> > >  }
> > >  
> > > -static void handle_dev_update_async(void *opaque, void *payload)
> > > +void display_channel_update(DisplayChannel *display,
> > > +                            uint32_t surface_id, const QXLRect *area,
> > > uint32_t clear_dirty,
> > > +                            QXLRect **qxl_dirty_rects, uint32_t
> > > *num_dirty_rects)
> > >  {
> > > -    RedWorker *worker = opaque;
> > > -    RedWorkerMessageUpdateAsync *msg = payload;
> > >      SpiceRect rect;
> > > -    QXLRect *qxl_dirty_rects;
> > > -    uint32_t num_dirty_rects;
> > >      RedSurface *surface;
> > > -    uint32_t surface_id = msg->surface_id;
> > > -    QXLRect qxl_area = msg->qxl_area;
> > > -    uint32_t clear_dirty_region = msg->clear_dirty_region;
> > >  
> > > -    red_get_rect_ptr(&rect, &qxl_area);
> > > -    flush_display_commands(worker);
> > > +    spice_return_if_fail(validate_surface(display, surface_id));
> > >  
> > > -    spice_assert(worker->running);
> > > +    red_get_rect_ptr(&rect, area);
> > > +    red_update_area(display, &rect, surface_id);
> > >  
> > > -    VALIDATE_SURFACE_RET(worker, surface_id);
> > > -    red_update_area(worker, &rect, surface_id);
> > > -    if (!worker->qxl->st->qif->update_area_complete) {
> > > -        return;
> > > -    }
> > > -    surface = &worker->surfaces[surface_id];
> > > -    num_dirty_rects =
> > > pixman_region32_n_rects(&surface->draw_dirty_region);
> > > -    if (num_dirty_rects == 0) {
> > > -        return;
> > > +    surface = &display->surfaces[surface_id];
> > > +    if (!*qxl_dirty_rects) {
> > > +        *num_dirty_rects =
> > > pixman_region32_n_rects(&surface->draw_dirty_region);
> > > +        *qxl_dirty_rects = spice_new0(QXLRect, *num_dirty_rects);
> > >      }
> > > -    qxl_dirty_rects = spice_new0(QXLRect, num_dirty_rects);
> > > -    surface_dirty_region_to_rects(surface, qxl_dirty_rects,
> > > num_dirty_rects,
> > > -                                  clear_dirty_region);
> > > -    worker->qxl->st->qif->update_area_complete(worker->qxl, surface_id,
> > > -                                          qxl_dirty_rects,
> > > num_dirty_rects);
> > > -    free(qxl_dirty_rects);
> > > +
> > > +    surface_dirty_region_to_rects(surface, *qxl_dirty_rects,
> > > *num_dirty_rects);
> > > +    if (clear_dirty)
> > > +        region_clear(&surface->draw_dirty_region);
> > >  }
> > >  
> > > -static void handle_dev_update(void *opaque, void *payload)
> > > +static void handle_dev_update_async(void *opaque, void *payload)
> > >  {
> > >      RedWorker *worker = opaque;
> > > -    RedWorkerMessageUpdate *msg = payload;
> > > -    SpiceRect *rect;
> > > -    RedSurface *surface;
> > > -    uint32_t surface_id = msg->surface_id;
> > > -    const QXLRect *qxl_area = msg->qxl_area;
> > > -    uint32_t num_dirty_rects = msg->num_dirty_rects;
> > > -    QXLRect *qxl_dirty_rects = msg->qxl_dirty_rects;
> > > -    uint32_t clear_dirty_region = msg->clear_dirty_region;
> > > +    RedWorkerMessageUpdateAsync *msg = payload;
> > > +    QXLRect *qxl_dirty_rects = NULL;
> > > +    uint32_t num_dirty_rects = 0;
> > >  
> > > -    VALIDATE_SURFACE_RET(worker, surface_id);
> > > +    spice_return_if_fail(worker->running);
> > > +    spice_return_if_fail(worker->qxl->st->qif->update_area_complete);
> > >  
> > > -    rect = spice_new0(SpiceRect, 1);
> > > -    surface = &worker->surfaces[surface_id];
> > > -    red_get_rect_ptr(rect, qxl_area);
> > >      flush_display_commands(worker);
> > > +    display_channel_update(worker->display_channel,
> > > +                           msg->surface_id, &msg->qxl_area,
> > > msg->clear_dirty_region,
> > > +                           &qxl_dirty_rects, &num_dirty_rects);
> > >  
> > > -    spice_assert(worker->running);
> > > +    worker->qxl->st->qif->update_area_complete(worker->qxl, msg-
> > > >surface_id,
> > > +                                                qxl_dirty_rects,
> > > num_dirty_rects);
> > > +    free(qxl_dirty_rects);
> > > +}
> > > +
> > > +static void handle_dev_update(void *opaque, void *payload)
> > > +{
> > > +    RedWorker *worker = opaque;
> > > +    RedWorkerMessageUpdate *msg = payload;
> > >  
> > > -    red_update_area(worker, rect, surface_id);
> > > -    free(rect);
> > > +    spice_return_if_fail(worker->running);
> > >  
> > > -    surface_dirty_region_to_rects(surface, qxl_dirty_rects,
> > > num_dirty_rects,
> > > -                                  clear_dirty_region);
> > > +    flush_display_commands(worker);
> > > +    display_channel_update(worker->display_channel,
> > > +                           msg->surface_id, msg->qxl_area,
> > > msg->clear_dirty_region,
> > > +                           &msg->qxl_dirty_rects,
> > > &msg->num_dirty_rects);
> > >  }
> > >  
> > >  static void handle_dev_del_memslot(void *opaque, void *payload)
> > > @@ -8646,32 +8509,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);
> > > +    red_handle_depends_on_target_surface(display, surface_id);
> > >      /* note that red_handle_depends_on_target_surface must be called
> > >      before
> > >      current_remove_all.
> > >         otherwise "current" will hold items that other drawables may
> > >         depend
> > >         on, and then
> > >         current_remove_all will remove them from the pipe. */
> > > -    current_remove_all(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_remove_all(display, surface_id);
> > > +    red_clear_surface_drawables_from_pipes(display, surface_id, TRUE);
> > >  }
> > >  
> > >  static void handle_dev_destroy_surface_wait(void *opaque, void *payload)
> > > @@ -8679,48 +8528,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,
> > > @@ -8745,13 +8593,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);
> > > @@ -8764,6 +8611,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;
> > >  
> > > @@ -8788,9 +8636,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
> > > @@ -8814,25 +8662,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);
> > >  }
> > > @@ -8843,7 +8691,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)
> > > @@ -8852,16 +8700,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);
> > >          }
> > >      }
> > >  }
> > > @@ -8869,7 +8717,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)
> > > @@ -8887,7 +8735,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
> > > @@ -9016,14 +8864,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)
> > > @@ -9537,7 +9387,6 @@ RedWorker* red_worker_new(QXLInstance *qxl,
> > > RedDispatcher *red_dispatcher)
> > >      worker->jpeg_state = jpeg_state;
> > >      worker->zlib_glz_state = zlib_glz_state;
> > >      worker->driver_cap_monitors_config = 0;
> > > -    image_surface_init(worker);
> > >  #ifdef RED_STATISTICS
> > >      char worker_str[20];
> > >      sprintf(worker_str, "display[%d]", worker->qxl->id);
> > > @@ -9563,7 +9412,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);
> > > @@ -9576,7 +9424,7 @@ RedWorker* red_worker_new(QXLInstance *qxl,
> > > RedDispatcher *red_dispatcher)
> > >  
> > >      worker->cursor_channel = cursor_channel_new(worker);
> > >      // TODO: handle seemless migration. Temp, setting migrate to FALSE
> > > -    display_channel_create(worker, FALSE, streaming_video);
> > > +    display_channel_create(worker, FALSE, streaming_video,
> > > init_info.n_surfaces);
> > >  
> > >      return worker;
> > >  }
> > > diff --git a/server/red_worker.h b/server/red_worker.h
> > > index 2995b8f..3604dfd 100644
> > > --- a/server/red_worker.h
> > > +++ b/server/red_worker.h
> > > @@ -22,6 +22,7 @@
> > >  #include <errno.h>
> > >  #include "red_common.h"
> > >  #include "red_dispatcher.h"
> > > +#include "red_parse_qxl.h"
> > >  
> > >  typedef struct RedWorker RedWorker;
> > >  
> > > @@ -108,6 +109,7 @@ bool       red_worker_run(RedWorker *worker);
> > >  QXLInstance* red_worker_get_qxl(RedWorker *worker);
> > >  RedChannel* red_worker_get_cursor_channel(RedWorker *worker);
> > >  RedChannel* red_worker_get_display_channel(RedWorker *worker);
> > > +void red_worker_print_stats(RedWorker *worker);
> > >  
> > >  RedChannel *red_worker_new_channel(RedWorker *worker, int size,
> > >                                     const char *name,
> > > --
> > > 2.4.3
> > > 
> > > _______________________________________________
> > > Spice-devel mailing list
> > > Spice-devel at lists.freedesktop.org
> > > http://lists.freedesktop.org/mailman/listinfo/spice-devel
> > > 
> > _______________________________________________
> > Spice-devel mailing list
> > Spice-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/spice-devel
> 


More information about the Spice-devel mailing list