[Spice-devel] [RFC v4 24/62] server/red_worker: split Surfaces from RedWorker

Alon Levy alevy at redhat.com
Thu May 5 01:31:38 PDT 2011


On Tue, May 03, 2011 at 01:52:12AM +0200, Marc-André Lureau wrote:
> On Tue, Apr 26, 2011 at 12:54 PM, Alon Levy <alevy at redhat.com> wrote:
> > Split the tree (current_list) and the surfaces out from RedWorker.
> > This patch is technical, basically a lot of propogation of "Surfaces
> > *surfaces" parameter, and otherwise changing s/worker/worker->surfaces/.
> >
> > Another possible name for Surfaces is RenderingState.
> 
> That sounds better. Why did you prefer Surfaces?

Because it appeared to contain that mainly at first. Bad name, I'll rename to
RenderingState. And the variables to render_state. Unless you have a shorter idea?

> 
> > In later patches there will be a multiplicity of surfaces:
> > 0        | 1
> > n >=1    | n
> >
> > The first instance is embedded in RedWorker. The later are embdedded
> > in the DisplayChannelClient which has not been introduced yet.
> 
> ok
> 
> > The surfaces backing store needs to be separate for the main Surfaces
> > instance and for the rest. For the main it needs to be vram, since
> > the guest will read from there after an UPDATE_AREA. For the others
> > it will be host memory.
> >
> > A multiplicity of rendering trees and surfaces makes having a separate
> > pipe easy, since we can replace a number of operations in the pipe with
> > their equivalent without effecting the other clients. Such a replacement
> > may require rendering the operations, so it requires the surfaces to be
> > in sync with the tree for that client.
> >
> > It might be possible to avoid some of this overhead later - in particular,
> > possibly having groups of clients associated with the same Surfaces, and
> > only create a copy on change. The current implementation is the simplest,
> > and it doesn't cost anything extra for a single client.
> >
> > Many function signatures are changed already to add Surfaces as an
> > additional paramater instead of using worker->surfaces, this is in
> > preparation for the next patches where Surfaces instances multiply.
> 
> Surfaces could reference the worker, that way we can make functions
> only take a "Surfaces"

Well, it does already ''slightly'' indirectly (the compiler will boil this down to two
dereferences, the rest are just offsets):
((CommonChannel*)surfaces->dcc->common.base.channel)->worker
and if dcc is NULL, then this is the embedded surfaces (render_state?)

> 
> 
> otherwise, ACK, the patch is straightforward.
> 
> > ---
> >  server/red_worker.c |  536 ++++++++++++++++++++++++++++-----------------------
> >  1 files changed, 295 insertions(+), 241 deletions(-)
> >
> > diff --git a/server/red_worker.c b/server/red_worker.c
> > index ebeb4af..275bfca 100644
> > --- a/server/red_worker.c
> > +++ b/server/red_worker.c
> > @@ -562,6 +562,7 @@ typedef struct CommonChannel {
> >     uint8_t recv_buf[RECIVE_BUF_SIZE];
> >  } CommonChannel;
> >
> > +typedef struct Surfaces Surfaces;
> >
> >  struct DisplayChannel {
> >     CommonChannel common; // Must be the first thing
> > @@ -806,6 +807,24 @@ typedef struct ItemTrace {
> >  #define NUM_DRAWABLES 1000
> >  #define NUM_CURSORS 100
> >
> > +struct Surfaces {
> > +    Ring current_list;
> > +    uint32_t current_size;
> > +    uint32_t drawable_count;
> > +    uint32_t transparent_count;
> > +
> > +    uint32_t shadows_count;
> > +    uint32_t containers_count;
> > +
> > +    RedSurface surfaces[NUM_SURFACES];
> > +    uint32_t n_surfaces;
> > +    SpiceImageSurfaces image_surfaces;
> > +
> > +#ifdef PIPE_DEBUG
> > +    uint32_t last_id;
> > +#endif
> > +};
> > +
> >  typedef struct RedWorker {
> >     EventListener dev_listener;
> >     DisplayChannel *display_channel;
> > @@ -823,17 +842,7 @@ typedef struct RedWorker {
> >     uint32_t renderers[RED_MAX_RENDERERS];
> >     uint32_t renderer;
> >
> > -    RedSurface surfaces[NUM_SURFACES];
> > -    uint32_t n_surfaces;
> > -    SpiceImageSurfaces image_surfaces;
> > -
> > -    Ring current_list;
> > -    uint32_t current_size;
> > -    uint32_t drawable_count;
> > -    uint32_t transparent_count;
> > -
> > -    uint32_t shadows_count;
> > -    uint32_t containers_count;
> > +    Surfaces surfaces;
> >
> >     uint32_t bits_unique;
> >
> > @@ -880,9 +889,6 @@ typedef struct RedWorker {
> >     ZlibData zlib_data;
> >     ZlibEncoder *zlib;
> >
> > -#ifdef PIPE_DEBUG
> > -    uint32_t last_id;
> > -#endif
> >  #ifdef RED_WORKER_STAT
> >     stat_info_t add_stat;
> >     stat_info_t exclude_stat;
> > @@ -911,17 +917,20 @@ typedef struct BitmapData {
> >     SpiceRect lossy_rect;
> >  } BitmapData;
> >
> > -static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable);
> > -static void red_current_flush(RedWorker *worker, int surface_id);
> > +static void red_draw_qxl_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *drawable);
> > +static void red_current_flush(RedWorker *worker, Surfaces *surfaces, int surface_id);
> >  #ifdef DRAW_ALL
> >  #define red_update_area(worker, rect, surface_id)
> > -#define red_draw_drawable(worker, item)
> > +#define red_update_area_surfaces(worker, surfaces, rect, surface_id)
> > +#define red_draw_drawable(worker, surfaces, item)
> >  #else
> > -static void red_draw_drawable(RedWorker *worker, Drawable *item);
> > +static void red_draw_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *item);
> >  static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id);
> > +static void red_update_area_surfaces(RedWorker *worker, Surfaces *surfaces,
> > +                            const SpiceRect *area, int surface_id);
> >  #endif
> >  static void red_release_cursor(RedWorker *worker, CursorItem *cursor);
> > -static inline void release_drawable(RedWorker *worker, Drawable *item);
> > +static inline void release_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *item);
> >  static void red_display_release_stream(DisplayChannel *display, StreamAgent *agent);
> >  static inline void red_detach_stream(RedWorker *worker, Stream *stream);
> >  static void red_stop_stream(RedWorker *worker, Stream *stream);
> > @@ -1023,7 +1032,7 @@ static void print_compress_stats(DisplayChannel *display_channel)
> >
> >  #endif
> >
> > -static inline int is_primary_surface(RedWorker *worker, uint32_t surface_id)
> > +static inline int is_primary_surface(uint32_t surface_id)
> >  {
> >     if (surface_id == 0) {
> >         return TRUE;
> > @@ -1031,15 +1040,15 @@ static inline int is_primary_surface(RedWorker *worker, uint32_t surface_id)
> >     return FALSE;
> >  }
> >
> > -static inline void __validate_surface(RedWorker *worker, uint32_t surface_id)
> > +static inline void __validate_surface(Surfaces *surfaces, uint32_t surface_id)
> >  {
> > -    PANIC_ON(surface_id >= worker->n_surfaces);
> > +    PANIC_ON(surface_id >= surfaces->n_surfaces);
> >  }
> >
> > -static inline void validate_surface(RedWorker *worker, uint32_t surface_id)
> > +static inline void validate_surface(Surfaces *surfaces, uint32_t surface_id)
> >  {
> > -    PANIC_ON(surface_id >= worker->n_surfaces);
> > -    PANIC_ON(!worker->surfaces[surface_id].context.canvas);
> > +    PANIC_ON(surface_id >= surfaces->n_surfaces);
> > +    PANIC_ON(!surfaces->surfaces[surface_id].context.canvas);
> >  }
> >
> >  char *draw_type_to_str(uint8_t type)
> > @@ -1159,7 +1168,7 @@ static inline void red_handle_drawable_surfaces_client_synced(RedWorker *worker,
> >                 continue;
> >             }
> >             red_create_surface_item(worker, surface_id);
> > -            red_current_flush(worker, surface_id);
> > +            red_current_flush(worker, &worker->surfaces, surface_id);
> >             red_add_surface_image(worker, surface_id);
> >         }
> >     }
> > @@ -1169,7 +1178,7 @@ static inline void red_handle_drawable_surfaces_client_synced(RedWorker *worker,
> >     }
> >
> >     red_create_surface_item(worker, drawable->surface_id);
> > -    red_current_flush(worker, drawable->surface_id);
> > +    red_current_flush(worker, &worker->surfaces, drawable->surface_id);
> >     red_add_surface_image(worker, drawable->surface_id);
> >  }
> >
> > @@ -1230,7 +1239,7 @@ static inline PipeItem *red_pipe_get_tail(RedWorker *worker)
> >     return (PipeItem*)ring_get_tail(&worker->display_channel->common.base.rcc->pipe);
> >  }
> >
> > -static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id);
> > +static inline void red_destroy_surface(RedWorker *worker, Surfaces *surfaces, uint32_t surface_id);
> >
> >  static inline void red_pipe_remove_drawable(RedWorker *worker, Drawable *drawable)
> >  {
> > @@ -1266,10 +1275,10 @@ static void release_image_item(ImageItem *item)
> >     }
> >  }
> >
> > -static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
> > +static void release_upgrade_item(RedWorker* worker, Surfaces *surfaces, UpgradeItem *item)
> >  {
> >     if (!--item->refs) {
> > -        release_drawable(worker, item->drawable);
> > +        release_drawable(worker, surfaces, item->drawable);
> >         free(item->rects);
> >         free(item);
> >     }
> > @@ -1337,7 +1346,7 @@ static void drawables_init(RedWorker *worker)
> >  }
> >
> >
> > -static void red_reset_stream_trace(RedWorker *worker);
> > +static void red_reset_stream_trace(RedWorker *worker, Surfaces *surfaces);
> >
> >  static SurfaceDestroyItem *get_surface_destroy_item(RedChannel *channel,
> >                                                     uint32_t surface_id)
> > @@ -1369,14 +1378,15 @@ static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_
> >     red_channel_client_pipe_add(channel->rcc, &destroy->pipe_item);
> >  }
> >
> > -static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
> > +static inline void red_destroy_surface(RedWorker *worker, Surfaces *surfaces,
> > +                                       uint32_t surface_id)
> >  {
> > -    RedSurface *surface = &worker->surfaces[surface_id];
> > +    RedSurface *surface = &surfaces->surfaces[surface_id];
> >
> >     if (!--surface->refs) {
> >         // only primary surface streams are supported
> >         if (surface_id == 0) {
> > -            red_reset_stream_trace(worker);
> > +            red_reset_stream_trace(worker, surfaces);
> >         }
> >         ASSERT(surface->context.canvas);
> >
> > @@ -1396,12 +1406,12 @@ static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
> >     }
> >  }
> >
> > -static inline void set_surface_release_info(RedWorker *worker, uint32_t surface_id, int is_create,
> > +static inline void set_surface_release_info(Surfaces *surfaces, uint32_t surface_id, int is_create,
> >                                             QXLReleaseInfo *release_info, uint32_t group_id)
> >  {
> >     RedSurface *surface;
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &surfaces->surfaces[surface_id];
> >
> >     if (is_create) {
> >         surface->create.info = release_info;
> > @@ -1435,7 +1445,8 @@ static void remove_depended_item(DependItem *item)
> >     ring_remove(&item->ring_item);
> >  }
> >
> > -static inline void red_dec_surfaces_drawable_dependencies(RedWorker *worker, Drawable *drawable)
> > +static inline void red_dec_surfaces_drawable_dependencies(RedWorker *worker,
> > +                                      Surfaces *surfaces, Drawable *drawable)
> >  {
> >     int x;
> >     int surface_id;
> > @@ -1445,7 +1456,7 @@ static inline void red_dec_surfaces_drawable_dependencies(RedWorker *worker, Dra
> >         if (surface_id == -1) {
> >             continue;
> >         }
> > -        red_destroy_surface(worker, surface_id);
> > +        red_destroy_surface(worker, surfaces, surface_id);
> >     }
> >  }
> >
> > @@ -1462,7 +1473,7 @@ static void remove_drawable_dependencies(RedWorker *worker, Drawable *drawable)
> >     }
> >  }
> >
> > -static inline void release_drawable(RedWorker *worker, Drawable *item)
> > +static inline void release_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *item)
> >  {
> >     if (!--item->refs) {
> >         ASSERT(!item->stream);
> > @@ -1470,8 +1481,8 @@ static inline void release_drawable(RedWorker *worker, Drawable *item)
> >         region_destroy(&item->tree_item.base.rgn);
> >
> >         remove_drawable_dependencies(worker, item);
> > -        red_dec_surfaces_drawable_dependencies(worker, item);
> > -        red_destroy_surface(worker, item->surface_id);
> > +        red_dec_surfaces_drawable_dependencies(worker, surfaces, item);
> > +        red_destroy_surface(worker, surfaces, item->surface_id);
> >
> >         if (item->red_glz_drawable) {
> >             item->red_glz_drawable->drawable = NULL;
> > @@ -1482,7 +1493,7 @@ static inline void release_drawable(RedWorker *worker, Drawable *item)
> >     }
> >  }
> >
> > -static inline void remove_shadow(RedWorker *worker, DrawItem *item)
> > +static inline void remove_shadow(Surfaces *surfaces, DrawItem *item)
> >  {
> >     Shadow *shadow;
> >
> > @@ -1495,19 +1506,19 @@ static inline void remove_shadow(RedWorker *worker, DrawItem *item)
> >     region_destroy(&shadow->base.rgn);
> >     region_destroy(&shadow->on_hold);
> >     free(shadow);
> > -    worker->shadows_count--;
> > +    surfaces->shadows_count--;
> >  }
> >
> > -static inline void current_remove_container(RedWorker *worker, Container *container)
> > +static inline void current_remove_container(Surfaces *surfaces, Container *container)
> >  {
> >     ASSERT(ring_is_empty(&container->items));
> > -    worker->containers_count--;
> > +    surfaces->containers_count--;
> >     ring_remove(&container->base.siblings_link);
> >     region_destroy(&container->base.rgn);
> >     free(container);
> >  }
> >
> > -static inline void container_cleanup(RedWorker *worker, Container *container)
> > +static inline void container_cleanup(Surfaces *surfaces, Container *container)
> >  {
> >     while (container && container->items.next == container->items.prev) {
> >         Container *next = container->base.container;
> > @@ -1518,7 +1529,7 @@ static inline void container_cleanup(RedWorker *worker, Container *container)
> >             ring_add_after(&item->siblings_link, &container->base.siblings_link);
> >             item->container = container->base.container;
> >         }
> > -        current_remove_container(worker, container);
> > +        current_remove_container(surfaces, container);
> >         container = next;
> >     }
> >  }
> > @@ -1541,12 +1552,12 @@ static inline void red_add_item_trace(RedWorker *worker, Drawable *item)
> >     trace->dest_area = item->red_drawable->bbox;
> >  }
> >
> > -static void surface_flush(RedWorker *worker, int surface_id, SpiceRect *rect)
> > +static void surface_flush(RedWorker *worker, Surfaces *surfaces, int surface_id, SpiceRect *rect)
> >  {
> > -    red_update_area(worker, rect, surface_id);
> > +    red_update_area_surfaces(worker, surfaces, rect, surface_id);
> >  }
> >
> > -static void red_flush_source_surfaces(RedWorker *worker, Drawable *drawable)
> > +static void red_flush_source_surfaces(RedWorker *worker, Surfaces *surfaces, Drawable *drawable)
> >  {
> >     int x;
> >     int surface_id;
> > @@ -1555,38 +1566,40 @@ static void red_flush_source_surfaces(RedWorker *worker, Drawable *drawable)
> >         surface_id = drawable->surfaces_dest[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(worker, surfaces, surface_id,
> > +                          &drawable->red_drawable->surfaces_rects[x]);
> >         }
> >     }
> >  }
> >
> > -static inline void current_remove_drawable(RedWorker *worker, Drawable *item)
> > +static inline void current_remove_drawable(RedWorker *worker, Surfaces *surfaces,
> > +                                           Drawable *item)
> >  {
> > -    worker->drawable_count--;
> > +    surfaces->drawable_count--;
> >
> >     if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
> > -        worker->transparent_count--;
> > +        surfaces->transparent_count--;
> >     }
> >     if (item->stream) {
> >         red_detach_stream(worker, item->stream);
> >     } else {
> >         red_add_item_trace(worker, item);
> >     }
> > -    remove_shadow(worker, &item->tree_item);
> > +    remove_shadow(surfaces, &item->tree_item);
> >     ring_remove(&item->tree_item.base.siblings_link);
> >     ring_remove(&item->list_link);
> >     ring_remove(&item->surface_list_link);
> > -    release_drawable(worker, item);
> > -    worker->current_size--;
> > +    release_drawable(worker, surfaces, item);
> > +    surfaces->current_size--;
> >  }
> >
> > -static void remove_drawable(RedWorker *worker, Drawable *item)
> > +static void remove_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *item)
> >  {
> >     red_pipe_remove_drawable(worker, item);
> > -    current_remove_drawable(worker, item);
> > +    current_remove_drawable(worker, surfaces, item);
> >  }
> >
> > -static inline void current_remove(RedWorker *worker, TreeItem *item)
> > +static inline void current_remove(RedWorker *worker, Surfaces *surfaces, TreeItem *item)
> >  {
> >     TreeItem *now = item;
> >
> > @@ -1596,7 +1609,7 @@ static inline void current_remove(RedWorker *worker, TreeItem *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(worker, surfaces, SPICE_CONTAINEROF(now, Drawable, tree_item));
> >         } else {
> >             Container *container = (Container *)now;
> >
> > @@ -1607,7 +1620,7 @@ static inline void current_remove(RedWorker *worker, TreeItem *item)
> >                 continue;
> >             }
> >             ring_item = now->siblings_link.prev;
> > -            current_remove_container(worker, container);
> > +            current_remove_container(surfaces, container);
> >         }
> >         if (now == item) {
> >             return;
> > @@ -1659,13 +1672,13 @@ static void current_tree_for_each(RedWorker *worker, Ring *ring, void (*f)(TreeI
> >     }
> >  }
> >
> > -static void red_current_clear(RedWorker *worker, int surface_id)
> > +static void red_current_clear(RedWorker *worker, Surfaces *surfaces, int surface_id)
> >  {
> >     RingItem *ring_item;
> >
> > -    while ((ring_item = ring_get_head(&worker->surfaces[surface_id].current))) {
> > +    while ((ring_item = ring_get_head(&surfaces->surfaces[surface_id].current))) {
> >         TreeItem *now = SPICE_CONTAINEROF(ring_item, TreeItem, siblings_link);
> > -        current_remove(worker, now);
> > +        current_remove(worker, surfaces, now);
> >     }
> >  }
> >
> > @@ -1923,7 +1936,8 @@ static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *ite
> >     stat_add(&worker->__exclude_stat, start_time);
> >  }
> >
> > -static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, QRegion *rgn,
> > +static void exclude_region(RedWorker *worker, Surfaces *surfaces, Ring *ring,
> > +                           RingItem *ring_item, QRegion *rgn,
> >                            TreeItem **last, Drawable *frame_candidate)
> >  {
> >  #ifdef RED_WORKER_STAT
> > @@ -1952,7 +1966,7 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
> >                 ASSERT(now->type != TREE_ITEM_TYPE_SHADOW);
> >                 ring_item = now->siblings_link.prev;
> >                 print_base_item("EXCLUDE_REMOVE", now);
> > -                current_remove(worker, now);
> > +                current_remove(worker, surfaces, now);
> >                 if (last && *last == now) {
> >                     *last = (TreeItem *)ring_next(ring, ring_item);
> >                 }
> > @@ -1985,12 +1999,12 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
> >     }
> >  }
> >
> > -static inline Container *__new_container(RedWorker *worker, DrawItem *item)
> > +static inline Container *__new_container(Surfaces *surfaces, DrawItem *item)
> >  {
> >     Container *container = spice_new(Container, 1);
> > -    worker->containers_count++;
> > +    surfaces->containers_count++;
> >  #ifdef PIPE_DEBUG
> > -    container->base.id = ++worker->last_id;
> > +    container->base.id = ++surfaces->last_id;
> >  #endif
> >     container->base.type = TREE_ITEM_TYPE_CONTAINER;
> >     container->base.container = item->base.container;
> > @@ -2012,15 +2026,16 @@ static inline int is_opaque_item(TreeItem *item)
> >            (IS_DRAW_ITEM(item) && ((DrawItem *)item)->effect == QXL_EFFECT_OPAQUE);
> >  }
> >
> > -static inline void __current_add_drawable(RedWorker *worker, Drawable *drawable, RingItem *pos)
> > +static inline void __current_add_drawable(RedWorker *worker, Surfaces *surfaces,
> > +                                          Drawable *drawable, RingItem *pos)
> >  {
> >     RedSurface *surface;
> >     uint32_t surface_id = drawable->surface_id;
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &surfaces->surfaces[surface_id];
> >     ring_add_after(&drawable->tree_item.base.siblings_link, pos);
> > -    ring_add(&worker->current_list, &drawable->list_link);
> > -    worker->drawable_count++;
> > +    ring_add(&surfaces->current_list, &drawable->list_link);
> > +    surfaces->drawable_count++;
> >     ring_add(&surface->current_list, &drawable->surface_list_link);
> >     drawable->refs++;
> >  }
> > @@ -2709,7 +2724,8 @@ static inline int is_drawable_independent_from_surfaces(Drawable *drawable)
> >     return TRUE;
> >  }
> >
> > -static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeItem *other)
> > +static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
> > +                                        DrawItem *item, TreeItem *other)
> >  {
> >     DrawItem *other_draw_item;
> >     Drawable *drawable;
> > @@ -2730,13 +2746,13 @@ 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);
> >         red_stream_maintenance(worker, drawable, other_drawable);
> > -        __current_add_drawable(worker, drawable, &other->siblings_link);
> > +        __current_add_drawable(worker, surfaces, drawable, &other->siblings_link);
> >         if (add_after) {
> >             red_pipe_add_drawable_after(worker, drawable, other_drawable);
> >         } else {
> >             red_pipe_add_drawable(worker, drawable);
> >         }
> > -        remove_drawable(worker, other_drawable);
> > +        remove_drawable(worker, surfaces, other_drawable);
> >         return TRUE;
> >     }
> >
> > @@ -2746,14 +2762,14 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
> >             if (!ring_item_is_linked(&other_drawable->pipe_item.link)) {
> >                 red_pipe_add_drawable(worker, drawable);
> >             }
> > -            remove_drawable(worker, other_drawable);
> > +            remove_drawable(worker, surfaces, other_drawable);
> >             return TRUE;
> >         }
> >         break;
> >     case QXL_EFFECT_OPAQUE_BRUSH:
> >         if (is_same_geometry(worker, drawable, other_drawable)) {
> > -            __current_add_drawable(worker, drawable, &other->siblings_link);
> > -            remove_drawable(worker, other_drawable);
> > +            __current_add_drawable(worker, surfaces, drawable, &other->siblings_link);
> > +            remove_drawable(worker, surfaces, other_drawable);
> >             red_pipe_add_drawable(worker, drawable);
> >             return TRUE;
> >         }
> > @@ -2812,7 +2828,7 @@ static inline void red_use_stream_trace(RedWorker *worker, Drawable *drawable)
> >     }
> >  }
> >
> > -static void red_reset_stream_trace(RedWorker *worker)
> > +static void red_reset_stream_trace(RedWorker *worker, Surfaces *surfaces)
> >  {
> >     Ring *ring = &worker->streams;
> >     RingItem *item = ring_get_head(ring);
> > @@ -2831,7 +2847,8 @@ static void red_reset_stream_trace(RedWorker *worker)
> >     memset(worker->items_trace, 0, sizeof(worker->items_trace));
> >  }
> >
> > -static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
> > +static inline int red_current_add(RedWorker *worker, Surfaces *surfaces,
> > +                                  Ring *ring, Drawable *drawable)
> >  {
> >     DrawItem *item = &drawable->tree_item;
> >  #ifdef RED_WORKER_STAT
> > @@ -2843,7 +2860,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
> >
> >     print_base_item("ADD", &item->base);
> >     ASSERT(!region_is_empty(&item->base.rgn));
> > -    worker->current_size++;
> > +    surfaces->current_size++;
> >     region_init(&exclude_rgn);
> >     now = ring_next(ring, ring);
> >
> > @@ -2863,8 +2880,8 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
> >             continue;
> >         } else if (sibling->type != TREE_ITEM_TYPE_SHADOW) {
> >             if (!(test_res & REGION_TEST_RIGHT_EXCLUSIVE) &&
> > -                                                   !(test_res & REGION_TEST_LEFT_EXCLUSIVE) &&
> > -                                                   red_current_add_equal(worker, item, sibling)) {
> > +                                       !(test_res & REGION_TEST_LEFT_EXCLUSIVE) &&
> > +                                       red_current_add_equal(worker, surfaces, item, sibling)) {
> >                 stat_add(&worker->add_stat, start_time);
> >                 return FALSE;
> >             }
> > @@ -2877,7 +2894,8 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
> >                 if ((shadow = __find_shadow(sibling))) {
> >                     if (exclude_base) {
> >                         TreeItem *next = sibling;
> > -                        exclude_region(worker, ring, exclude_base, &exclude_rgn, &next, NULL);
> > +                        exclude_region(worker, surfaces, ring, exclude_base,
> > +                                       &exclude_rgn, &next, NULL);
> >                         if (next != sibling) {
> >                             now = next ? &next->siblings_link : NULL;
> >                             exclude_base = NULL;
> > @@ -2887,7 +2905,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
> >                     region_or(&exclude_rgn, &shadow->on_hold);
> >                 }
> >                 now = now->prev;
> > -                current_remove(worker, sibling);
> > +                current_remove(worker, surfaces, sibling);
> >                 now = ring_next(ring, now);
> >                 if (shadow || skip) {
> >                     exclude_base = now;
> > @@ -2899,7 +2917,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
> >                 Container *container;
> >
> >                 if (exclude_base) {
> > -                    exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL, NULL);
> > +                    exclude_region(worker, surfaces, ring, exclude_base, &exclude_rgn, NULL, NULL);
> >                     region_clear(&exclude_rgn);
> >                     exclude_base = NULL;
> >                 }
> > @@ -2913,7 +2931,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
> >                 }
> >                 ASSERT(IS_DRAW_ITEM(sibling));
> >                 if (!((DrawItem *)sibling)->container_root) {
> > -                    container = __new_container(worker, (DrawItem *)sibling);
> > +                    container = __new_container(surfaces, (DrawItem *)sibling);
> >                     if (!container) {
> >                         red_printf("create new container failed");
> >                         region_destroy(&exclude_rgn);
> > @@ -2931,7 +2949,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
> >     }
> >     if (item->effect == QXL_EFFECT_OPAQUE) {
> >         region_or(&exclude_rgn, &item->base.rgn);
> > -        exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL, drawable);
> > +        exclude_region(worker, surfaces, ring, exclude_base, &exclude_rgn, NULL, drawable);
> >         red_use_stream_trace(worker, drawable);
> >         red_streams_update_clip(worker, drawable);
> >     } else {
> > @@ -2940,7 +2958,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
> >         }
> >     }
> >     region_destroy(&exclude_rgn);
> > -    __current_add_drawable(worker, drawable, ring);
> > +    __current_add_drawable(worker, surfaces, drawable, ring);
> >     stat_add(&worker->add_stat, start_time);
> >     return TRUE;
> >  }
> > @@ -2954,16 +2972,16 @@ static void add_clip_rects(QRegion *rgn, SpiceClipRects *data)
> >     }
> >  }
> >
> > -static inline Shadow *__new_shadow(RedWorker *worker, Drawable *item, SpicePoint *delta)
> > +static inline Shadow *__new_shadow(Surfaces *surfaces, Drawable *item, SpicePoint *delta)
> >  {
> >     if (!delta->x && !delta->y) {
> >         return NULL;
> >     }
> >
> >     Shadow *shadow = spice_new(Shadow, 1);
> > -    worker->shadows_count++;
> > +    surfaces->shadows_count++;
> >  #ifdef PIPE_DEBUG
> > -    shadow->base.id = ++worker->last_id;
> > +    shadow->base.id = ++surfaces->last_id;
> >  #endif
> >     shadow->base.type = TREE_ITEM_TYPE_SHADOW;
> >     shadow->base.container = NULL;
> > @@ -2976,19 +2994,20 @@ static inline Shadow *__new_shadow(RedWorker *worker, Drawable *item, SpicePoint
> >     return shadow;
> >  }
> >
> > -static inline int red_current_add_with_shadow(RedWorker *worker, Ring *ring, Drawable *item, SpicePoint *delta)
> > +static inline int red_current_add_with_shadow(RedWorker *worker, Surfaces *surfaces,
> > +                                            Ring *ring, Drawable *item, SpicePoint *delta)
> >  {
> >  #ifdef RED_WORKER_STAT
> >     stat_time_t start_time = stat_now();
> >  #endif
> >
> > -    Shadow *shadow = __new_shadow(worker, item, delta);
> > +    Shadow *shadow = __new_shadow(surfaces, item, delta);
> >     if (!shadow) {
> >         stat_add(&worker->add_stat, start_time);
> >         return FALSE;
> >     }
> >     print_base_item("ADDSHADOW", &item->tree_item.base);
> > -    worker->current_size++;
> > +    surfaces->current_size++;
> >     // item and his shadow must initially be placed in the same container.
> >     // for now putting them on root.
> >
> > @@ -2997,11 +3016,11 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Ring *ring, Dra
> >         red_detach_streams_behind(worker, &shadow->base.rgn);
> >     }
> >     ring_add(ring, &shadow->base.siblings_link);
> > -    __current_add_drawable(worker, item, ring);
> > +    __current_add_drawable(worker, surfaces, 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(worker, surfaces, ring, &shadow->base.siblings_link, &exclude_rgn, NULL, NULL);
> >         region_destroy(&exclude_rgn);
> >         red_streams_update_clip(worker, item);
> >     } else {
> > @@ -3058,7 +3077,8 @@ static inline void red_update_streamable(RedWorker *worker, Drawable *drawable,
> >     drawable->streamable = TRUE;
> >  }
> >
> > -static inline int red_current_add_qxl(RedWorker *worker, Ring *ring, Drawable *drawable,
> > +static inline int red_current_add_qxl(RedWorker *worker, Surfaces *surfaces,
> > +                                      Ring *ring, Drawable *drawable,
> >                                       RedDrawable *red_drawable)
> >  {
> >     int ret;
> > @@ -3071,10 +3091,10 @@ static inline int red_current_add_qxl(RedWorker *worker, Ring *ring, Drawable *d
> >  #endif
> >         delta.x = red_drawable->u.copy_bits.src_pos.x - red_drawable->bbox.left;
> >         delta.y = red_drawable->u.copy_bits.src_pos.y - red_drawable->bbox.top;
> > -        ret = red_current_add_with_shadow(worker, ring, drawable, &delta);
> > +        ret = red_current_add_with_shadow(worker, surfaces, ring, drawable, &delta);
> >     } else {
> >         red_update_streamable(worker, drawable, red_drawable);
> > -        ret = red_current_add(worker, ring, drawable);
> > +        ret = red_current_add(worker, surfaces, ring, drawable);
> >     }
> >  #ifdef RED_WORKER_STAT
> >     if ((++worker->add_count % 100) == 0) {
> > @@ -3103,15 +3123,16 @@ static inline int red_current_add_qxl(RedWorker *worker, Ring *ring, Drawable *d
> >     return ret;
> >  }
> >
> > -static void red_get_area(RedWorker *worker, int surface_id, const SpiceRect *area, uint8_t *dest,
> > +static void red_get_area(RedWorker *worker, Surfaces *surfaces,
> > +                         int surface_id, const SpiceRect *area, uint8_t *dest,
> >                          int dest_stride, int update)
> >  {
> >     SpiceCanvas *canvas;
> >     RedSurface *surface;
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &surfaces->surfaces[surface_id];
> >     if (update) {
> > -        red_update_area(worker, area, surface_id);
> > +        red_update_area_surfaces(worker, surfaces, area, surface_id);
> >     }
> >
> >     canvas = surface->context.canvas;
> > @@ -3161,7 +3182,8 @@ static int rgb32_data_has_alpha(int width, int height, size_t stride,
> >     return has_alpha;
> >  }
> >
> > -static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
> > +static inline int red_handle_self_bitmap(RedWorker *worker, Surfaces *surfaces,
> > +                                         Drawable *drawable)
> >  {
> >     SpiceImage *image;
> >     int32_t width;
> > @@ -3176,8 +3198,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
> >         return TRUE;
> >     }
> >
> > -
> > -    surface = &worker->surfaces[drawable->surface_id];
> > +    surface = &surfaces->surfaces[drawable->surface_id];
> >
> >     bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
> >
> > @@ -3201,12 +3222,12 @@ 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(worker, surfaces, drawable->surface_id,
> >                  &drawable->red_drawable->self_bitmap_area, dest, dest_stride, TRUE);
> >
> >     /* For 32bit non-primary surfaces we need to keep any non-zero
> >        high bytes as the surface may be used as source to an alpha_blend */
> > -    if (!is_primary_surface(worker, drawable->surface_id) &&
> > +    if (!is_primary_surface(drawable->surface_id) &&
> >         image->u.bitmap.format == SPICE_BITMAP_FMT_32BIT &&
> >         rgb32_data_has_alpha(width, height, dest_stride, dest, &all_set)) {
> >         if (all_set) {
> > @@ -3220,9 +3241,9 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
> >     return TRUE;
> >  }
> >
> > -static void free_one_drawable(RedWorker *worker, int force_glz_free)
> > +static void free_one_drawable(RedWorker *worker, Surfaces *surfaces, int force_glz_free)
> >  {
> > -    RingItem *ring_item = ring_get_tail(&worker->current_list);
> > +    RingItem *ring_item = ring_get_tail(&surfaces->current_list);
> >     Drawable *drawable;
> >     Container *container;
> >
> > @@ -3232,28 +3253,28 @@ static void free_one_drawable(RedWorker *worker, int force_glz_free)
> >         ASSERT(worker->display_channel);
> >         red_display_free_glz_drawable(worker->display_channel, drawable->red_glz_drawable);
> >     }
> > -    red_draw_drawable(worker, drawable);
> > +    red_draw_drawable(worker, surfaces, drawable);
> >     container = drawable->tree_item.base.container;
> >
> > -    current_remove_drawable(worker, drawable);
> > -    container_cleanup(worker, container);
> > +    current_remove_drawable(worker, surfaces, drawable);
> > +    container_cleanup(surfaces, container);
> >  }
> >
> > -static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *red_drawable,
> > +static Drawable *get_drawable(RedWorker *worker, Surfaces *surfaces, uint8_t effect, RedDrawable *red_drawable,
> >                               uint32_t group_id) {
> >     Drawable *drawable;
> >     struct timespec time;
> >     int x;
> >
> >     while (!(drawable = alloc_drawable(worker))) {
> > -        free_one_drawable(worker, FALSE);
> > +        free_one_drawable(worker, surfaces, FALSE);
> >     }
> >     memset(drawable, 0, sizeof(Drawable));
> >     drawable->refs = 1;
> >     clock_gettime(CLOCK_MONOTONIC, &time);
> >     drawable->creation_time = timespec_to_red_time(&time);
> >  #ifdef PIPE_DEBUG
> > -    drawable->tree_item.base.id = ++worker->last_id;
> > +    drawable->tree_item.base.id = ++surfaces->last_id;
> >  #endif
> >     ring_item_init(&drawable->list_link);
> >     ring_item_init(&drawable->surface_list_link);
> > @@ -3270,35 +3291,36 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
> >     drawable->group_id = group_id;
> >
> >     drawable->surface_id = red_drawable->surface_id;
> > -    validate_surface(worker, drawable->surface_id);
> > +    validate_surface(surfaces, drawable->surface_id);
> >     for (x = 0; x < 3; ++x) {
> >         drawable->surfaces_dest[x] = red_drawable->surfaces_dest[x];
> >         if (drawable->surfaces_dest[x] != -1) {
> > -            validate_surface(worker, drawable->surfaces_dest[x]);
> > +            validate_surface(surfaces, drawable->surfaces_dest[x]);
> >         }
> >     }
> >
> >     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(RedWorker *worker, Surfaces *surfaces,
> > +                                                       uint32_t surface_id)
> >  {
> >     RedSurface *surface;
> >     RingItem *ring_item;
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &surfaces->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(worker, surfaces, 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(Surfaces *surfaces, int depend_on_surface_id,
> >                                              DependItem *depend_item, Drawable *drawable)
> >  {
> >     RedSurface *surface;
> > @@ -3308,13 +3330,14 @@ static inline void add_to_surface_dependency(RedWorker *worker, int depend_on_su
> >         return;
> >     }
> >
> > -    surface = &worker->surfaces[depend_on_surface_id];
> > +    surface = &surfaces->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(RedWorker *worker,
> > +                               Surfaces *surfaces, Drawable *drawable)
> >  {
> >     int x;
> >
> > @@ -3322,7 +3345,7 @@ static inline int red_handle_surfaces_dependencies(RedWorker *worker, Drawable *
> >         // surface self dependency is handled by shadows in "current", or by
> >         // handle_self_bitmap
> >         if (drawable->surfaces_dest[x] != drawable->surface_id) {
> > -            add_to_surface_dependency(worker, drawable->surfaces_dest[x],
> > +            add_to_surface_dependency(surfaces, drawable->surfaces_dest[x],
> >                                       &drawable->depend_items[x], drawable);
> >
> >             if (drawable->surfaces_dest[x] == 0) {
> > @@ -3337,7 +3360,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(Surfaces *surfaces, Drawable *drawable)
> >  {
> >     int x;
> >     int surface_id;
> > @@ -3348,21 +3371,22 @@ static inline void red_inc_surfaces_drawable_dependencies(RedWorker *worker, Dra
> >         if (surface_id == -1) {
> >             continue;
> >         }
> > -        surface = &worker->surfaces[surface_id];
> > +        surface = &surfaces->surfaces[surface_id];
> >         surface->refs++;
> >     }
> >  }
> >
> > -static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable, uint32_t group_id)
> > +static inline void red_process_drawable_surfaces(RedWorker *worker,
> > +                    Surfaces *surfaces, RedDrawable *drawable, uint32_t group_id)
> >  {
> >     int surface_id;
> > -    Drawable *item = get_drawable(worker, drawable->effect, drawable, group_id);
> > +    Drawable *item = get_drawable(worker, surfaces, drawable->effect, drawable, group_id);
> >
> >     ASSERT(item);
> >
> >     surface_id = item->surface_id;
> >
> > -    worker->surfaces[surface_id].refs++;
> > +    surfaces->surfaces[surface_id].refs++;
> >
> >     region_add(&item->tree_item.base.rgn, &drawable->bbox);
> >  #ifdef PIPE_DEBUG
> > @@ -3387,42 +3411,49 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable
> >         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, item);
> > +    red_inc_surfaces_drawable_dependencies(surfaces, item);
> >
> >     if (region_is_empty(&item->tree_item.base.rgn)) {
> > -        release_drawable(worker, item);
> > +        release_drawable(worker, surfaces, item);
> >         return;
> >     }
> >
> > -    if (!red_handle_self_bitmap(worker, item)) {
> > -        release_drawable(worker, item);
> > +    if (!red_handle_self_bitmap(worker, surfaces, item)) {
> > +        release_drawable(worker, surfaces, item);
> >         return;
> >     }
> >
> > -    if (!red_handle_depends_on_target_surface(worker, surface_id)) {
> > -        release_drawable(worker, item);
> > +    if (!red_handle_depends_on_target_surface(worker, surfaces, surface_id)) {
> > +        release_drawable(worker, surfaces, item);
> >         return;
> >     }
> >
> > -    if (!red_handle_surfaces_dependencies(worker, item)) {
> > -        release_drawable(worker, item);
> > +    if (!red_handle_surfaces_dependencies(worker, surfaces, item)) {
> > +        release_drawable(worker, surfaces, item);
> >         return;
> >     }
> >
> > -    if (red_current_add_qxl(worker, &worker->surfaces[surface_id].current, item,
> > +    if (red_current_add_qxl(worker, surfaces,
> > +                            &surfaces->surfaces[surface_id].current, item,
> >                             drawable)) {
> >         if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
> > -            worker->transparent_count++;
> > +            surfaces->transparent_count++;
> >         }
> >         red_pipe_add_drawable(worker, item);
> >  #ifdef DRAW_ALL
> > -        red_draw_qxl_drawable(worker, item);
> > +        red_draw_qxl_drawable(worker, surfaces, item);
> >  #endif
> >     }
> > -    release_drawable(worker, item);
> > +    release_drawable(worker, surfaces, item);
> >  }
> >
> > -static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
> > +static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable, uint32_t group_id)
> > +{
> > +    red_process_drawable_surfaces(worker, &worker->surfaces, drawable, group_id);
> > +}
> > +
> > +static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
> > +                                      uint32_t surface_id, uint32_t width,
> >                                       uint32_t height, int32_t stride, uint32_t format,
> >                                       void *line_0, int data_is_valid);
> >
> > @@ -3431,11 +3462,12 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
> >     int surface_id;
> >     RedSurface *red_surface;
> >     uint8_t *data;
> > +    Surfaces *surfaces = &worker->surfaces;
> >
> >     surface_id = surface->surface_id;
> > -    __validate_surface(worker, surface_id);
> > +    __validate_surface(surfaces, surface_id);
> >
> > -    red_surface = &worker->surfaces[surface_id];
> > +    red_surface = &surfaces->surfaces[surface_id];
> >
> >     switch (surface->type) {
> >     case QXL_SURFACE_CMD_CREATE: {
> > @@ -3446,22 +3478,22 @@ 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, surfaces, surface_id, surface->u.surface_create.width,
> >                            height, stride, surface->u.surface_create.format, data,
> >                            data_is_valid);
> > -        set_surface_release_info(worker, surface_id, 1, surface->release_info, group_id);
> > +        set_surface_release_info(&worker->surfaces, surface_id, 1, surface->release_info, group_id);
> >         break;
> >     }
> >     case QXL_SURFACE_CMD_DESTROY:
> >         PANIC_ON(!red_surface->context.canvas);
> > -        set_surface_release_info(worker, surface_id, 0, surface->release_info, group_id);
> > -        red_handle_depends_on_target_surface(worker, surface_id);
> > +        set_surface_release_info(surfaces, surface_id, 0, surface->release_info, group_id);
> > +        red_handle_depends_on_target_surface(worker, surfaces, surface_id);
> >         /* note that red_handle_depends_on_target_surface must be called before red_current_clear.
> >            otherwise "current" will hold items that other drawables may depend on, and then
> >            red_current_clear will remove them from the pipe. */
> > -        red_current_clear(worker, surface_id);
> > +        red_current_clear(worker, surfaces, surface_id);
> >         red_clear_surface_drawables_from_pipe(worker, surface_id, FALSE);
> > -        red_destroy_surface(worker, surface_id);
> > +        red_destroy_surface(worker, surfaces, surface_id);
> >         break;
> >     default:
> >             red_error("unknown surface command");
> > @@ -3470,24 +3502,24 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
> >     free(surface);
> >  }
> >
> > -static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces,
> > +static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *image_surfaces,
> >                                        uint32_t surface_id)
> >  {
> > -    RedWorker *worker;
> > +    Surfaces *surfaces;
> >
> > -    worker = SPICE_CONTAINEROF(surfaces, RedWorker, image_surfaces);
> > -    validate_surface(worker, surface_id);
> > +    surfaces = SPICE_CONTAINEROF(image_surfaces, Surfaces, image_surfaces);
> > +    validate_surface(surfaces, surface_id);
> >
> > -    return worker->surfaces[surface_id].context.canvas;
> > +    return surfaces->surfaces[surface_id].context.canvas;
> >  }
> >
> > -static void image_surface_init(RedWorker *worker)
> > +static void image_surface_init(Surfaces *surfaces)
> >  {
> >     static SpiceImageSurfacesOps image_surfaces_ops = {
> >         image_surfaces_get,
> >     };
> >
> > -    worker->image_surfaces.ops = &image_surfaces_ops;
> > +    surfaces->image_surfaces.ops = &image_surfaces_ops;
> >  }
> >
> >  static ImageCacheItem *image_cache_find(ImageCache *cache, uint64_t id)
> > @@ -3680,13 +3712,13 @@ static void localize_mask(RedWorker *worker, SpiceQMask *mask, SpiceImage *image
> >     }
> >  }
> >
> > -static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
> > +static void red_draw_qxl_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *drawable)
> >  {
> >     RedSurface *surface;
> >     SpiceCanvas *canvas;
> >     SpiceClip clip = drawable->red_drawable->clip;
> >
> > -    surface = &worker->surfaces[drawable->surface_id];
> > +    surface = &surfaces->surfaces[drawable->surface_id];
> >     canvas = surface->context.canvas;
> >
> >     image_cache_eaging(&worker->image_cache);
> > @@ -3811,7 +3843,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
> >
> >  #ifndef DRAW_ALL
> >
> > -static void red_draw_drawable(RedWorker *worker, Drawable *drawable)
> > +static void red_draw_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *drawable)
> >  {
> >  #ifdef UPDATE_AREA_BY_TREE
> >     SpiceCanvas *canvas;
> > @@ -3821,8 +3853,8 @@ static void red_draw_drawable(RedWorker *worker, Drawable *drawable)
> >     canvas->ops->group_start(canvas,
> >                              &drawable->tree_item.base.rgn);
> >  #endif
> > -    red_flush_source_surfaces(worker, drawable);
> > -    red_draw_qxl_drawable(worker, drawable);
> > +    red_flush_source_surfaces(worker, surfaces, drawable);
> > +    red_draw_qxl_drawable(worker, surfaces, drawable);
> >  #ifdef UPDATE_AREA_BY_TREE
> >     canvas->ops->group_end(canvas);
> >  #endif
> > @@ -3832,7 +3864,7 @@ static void validate_area(RedWorker *worker, const SpiceRect *area, uint32_t sur
> >  {
> >     RedSurface *surface;
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &worker->surfaces.surfaces[surface_id];
> >     if (!surface->context.canvas_draws_on_surface) {
> >         SpiceCanvas *canvas = surface->context.canvas;
> >         int h;
> > @@ -3899,7 +3931,8 @@ static inline void __red_collect_for_update(RedWorker *worker, Ring *ring, RingI
> >     }
> >  }
> >
> > -static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id)
> > +static void red_update_area_surfaces(RedWorker *worker, Surfaces *surfaces,
> > +                                     const SpiceRect *area, int surface_id)
> >  {
> >     RedSurface *surface;
> >     Ring *ring;
> > @@ -3907,7 +3940,7 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
> >     Ring items;
> >     QRegion rgn;
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &surfaces->surfaces[surface_id];
> >     ring = &surface->current;
> >
> >     if (!(ring_item = ring_get_head(ring))) {
> > @@ -3930,7 +3963,7 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
> >         red_draw_drawable(worker, drawable);
> >         container = drawable->tree_item.base.container;
> >         current_remove_drawable(worker, drawable);
> > -        container_cleanup(worker, container);
> > +        container_cleanup(surfaces, container);
> >     }
> >     validate_area(worker, area, surface_id);
> >  }
> > @@ -3941,7 +3974,8 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
> >     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(RedWorker *worker, Surfaces *surfaces,
> > +                                 const SpiceRect *area, int surface_id,
> >                                  Drawable *last)
> >  {
> >     // TODO: if we use UPDATE_AREA_BY_TREE, a corresponding red_update_area_till
> > @@ -3957,11 +3991,11 @@ static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int s
> >     ASSERT(last);
> >     ASSERT(ring_item_is_linked(&last->list_link));
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &surfaces->surfaces[surface_id];
> >
> >     if (surface_id != last->surface_id) {
> >         // find the nearest older drawable from the appropriate surface
> > -        ring = &worker->current_list;
> > +        ring = &surfaces->current_list;
> >         ring_item = &last->list_link;
> >         while ((ring_item = ring_next(ring, ring_item))) {
> >             now = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
> > @@ -3987,7 +4021,7 @@ static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int s
> >     region_init(&rgn);
> >     region_add(&rgn, area);
> >
> > -    // find the first older drawable that intersects with the area
> > +    // find the first older drawable that intersects with the area
> >     do {
> >         now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
> >         if (region_intersects(&rgn, &now->tree_item.base.rgn)) {
> > @@ -3997,7 +4031,7 @@ static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int s
> >     } while ((ring_item = ring_next(ring, ring_item)));
> >
> >     region_destroy(&rgn);
> > -
> > +
> >     if (!surface_last) {
> >         return;
> >     }
> > @@ -4009,20 +4043,21 @@ static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int s
> >         now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
> >         now->refs++;
> >         container = now->tree_item.base.container;
> > -        current_remove_drawable(worker, now);
> > -        container_cleanup(worker, container);
> > +        current_remove_drawable(worker, surfaces, now);
> > +        container_cleanup(surfaces, 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_drawable */
> > -        red_draw_drawable(worker, now);
> > -        release_drawable(worker, now);
> > +        red_draw_drawable(worker, surfaces, now);
> > +        release_drawable(worker, surfaces, now);
> >     } while (now != surface_last);
> >     validate_area(worker, area, surface_id);
> >  }
> >
> > -static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id)
> > +static void red_update_area_surfaces(RedWorker *worker, Surfaces *surfaces,
> > +                            const SpiceRect *area, int surface_id)
> >  {
> >     RedSurface *surface;
> >     Ring *ring;
> > @@ -4034,7 +4069,7 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
> >     int gn;
> >  #endif
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &surfaces->surfaces[surface_id];
> >
> >     last = NULL;
> >  #ifdef ACYCLIC_SURFACE_DEBUG
> > @@ -4066,10 +4101,10 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
> >         now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
> >         now->refs++;
> >         container = now->tree_item.base.container;
> > -        current_remove_drawable(worker, now);
> > -        container_cleanup(worker, container);
> > -        red_draw_drawable(worker, now);
> > -        release_drawable(worker, now);
> > +        current_remove_drawable(worker, surfaces, now);
> > +        container_cleanup(surfaces, container);
> > +        red_draw_drawable(worker, surfaces, now);
> > +        release_drawable(worker, surfaces, now);
> >  #ifdef ACYCLIC_SURFACE_DEBUG
> >         if (gn != surface->current_gn) {
> >             red_error("cyclic surface dependencies");
> > @@ -4081,6 +4116,11 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
> >
> >  #endif
> >
> > +static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id)
> > +{
> > +    red_update_area_surfaces(worker, &worker->surfaces, area, surface_id);
> > +}
> > +
> >  #endif
> >
> >  static inline void free_cursor_item(RedWorker *worker, CursorItem *item);
> > @@ -4289,7 +4329,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
> >
> >             red_get_update_cmd(&worker->mem_slots, ext_cmd.group_id,
> >                                &update, ext_cmd.cmd.data);
> > -            validate_surface(worker, update.surface_id);
> > +            validate_surface(&worker->surfaces, update.surface_id);
> >             red_update_area(worker, &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;
> > @@ -4348,8 +4388,8 @@ static void red_free_some(RedWorker *worker)
> >         n = red_display_free_some_independent_glz_drawables(worker->display_channel);
> >     }
> >
> > -    while (!ring_is_empty(&worker->current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
> > -        free_one_drawable(worker, TRUE);
> > +    while (!ring_is_empty(&worker->surfaces.current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
> > +        free_one_drawable(worker, &worker->surfaces, TRUE);
> >     }
> >
> >     if (worker->display_channel && worker->display_channel->glz_dict) {
> > @@ -4357,12 +4397,12 @@ static void red_free_some(RedWorker *worker)
> >     }
> >  }
> >
> > -static void red_current_flush(RedWorker *worker, int surface_id)
> > +static void red_current_flush(RedWorker *worker, Surfaces *surfaces, int surface_id)
> >  {
> > -    while (!ring_is_empty(&worker->surfaces[surface_id].current_list)) {
> > -        free_one_drawable(worker, FALSE);
> > +    while (!ring_is_empty(&surfaces->surfaces[surface_id].current_list)) {
> > +        free_one_drawable(worker, surfaces, FALSE);
> >     }
> > -    red_current_clear(worker, surface_id);
> > +    red_current_clear(worker, surfaces, surface_id);
> >  }
> >
> >  // adding the pipe item after pos. If pos == NULL, adding to head.
> > @@ -4373,7 +4413,7 @@ static ImageItem *red_add_surface_area_image(RedWorker *worker, int surface_id,
> >     int stride;
> >     int width;
> >     int height;
> > -    RedSurface *surface = &worker->surfaces[surface_id];
> > +    RedSurface *surface = &worker->surfaces.surfaces[surface_id];
> >     SpiceCanvas *canvas = surface->context.canvas;
> >     int bpp;
> >     int all_set;
> > @@ -4407,7 +4447,7 @@ static ImageItem *red_add_surface_area_image(RedWorker *worker, int surface_id,
> >
> >     /* For 32bit non-primary surfaces we need to keep any non-zero
> >        high bytes as the surface may be used as source to an alpha_blend */
> > -    if (!is_primary_surface(worker, surface_id) &&
> > +    if (!is_primary_surface(surface_id) &&
> >         item->image_format == SPICE_BITMAP_FMT_32BIT &&
> >         rgb32_data_has_alpha(item->width, item->height, item->stride, item->data, &all_set)) {
> >         if (all_set) {
> > @@ -4433,7 +4473,7 @@ static void red_add_surface_image(RedWorker *worker, int surface_id)
> >     SpiceRect area;
> >     RedSurface *surface;
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &worker->surfaces.surfaces[surface_id];
> >
> >     if (!display_connected(worker) || !surface->context.canvas) {
> >         return;
> > @@ -5813,9 +5853,9 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
> >         RedSurface *surface;
> >
> >         surface_id = simage->u.surface.surface_id;
> > -        validate_surface(worker, surface_id);
> > +        validate_surface(&worker->surfaces, surface_id);
> >
> > -        surface = &worker->surfaces[surface_id];
> > +        surface = &worker->surfaces.surfaces[surface_id];
> >         image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
> >         image.descriptor.flags = 0;
> >         image.descriptor.width = surface->context.width;
> > @@ -5977,8 +6017,8 @@ static int is_surface_area_lossy(DisplayChannel *display_channel, uint32_t surfa
> >     QRegion *surface_lossy_region;
> >     QRegion lossy_region;
> >
> > -    validate_surface(display_channel->common.worker, surface_id);
> > -    surface = &display_channel->common.worker->surfaces[surface_id];
> > +    validate_surface(&display_channel->common.worker->surfaces, surface_id);
> > +    surface = &display_channel->common.worker->surfaces.surfaces[surface_id];
> >     surface_lossy_region = &display_channel->surface_client_lossy_region[surface_id];
> >
> >     if (!area) {
> > @@ -6298,7 +6338,8 @@ 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], deps_surfaces_ids[i], item);
> > +            red_update_area_till(worker, &worker->surfaces, deps_areas[i],
> > +                                 deps_surfaces_ids[i], item);
> >         }
> >     }
> >
> > @@ -8073,7 +8114,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
> >     case PIPE_ITEM_TYPE_DRAW: {
> >         Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
> >         marshall_qxl_drawable(rcc, m, drawable);
> > -        release_drawable(worker, drawable);
> > +        release_drawable(worker, &worker->surfaces, drawable);
> >         break;
> >     }
> >     case PIPE_ITEM_TYPE_INVAL_ONE:
> > @@ -8100,7 +8141,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
> >     }
> >     case PIPE_ITEM_TYPE_UPGRADE:
> >         red_display_marshall_upgrade(rcc, m, (UpgradeItem *)pipe_item);
> > -        release_upgrade_item(worker, (UpgradeItem *)pipe_item);
> > +        release_upgrade_item(worker, &worker->surfaces, (UpgradeItem *)pipe_item);
> >         break;
> >     case PIPE_ITEM_TYPE_VERB:
> >         red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
> > @@ -8269,8 +8310,8 @@ void red_show_tree(RedWorker *worker)
> >     show_tree_data.level = 0;
> >     show_tree_data.container = NULL;
> >     for (x = 0; x < NUM_SURFACES; ++x) {
> > -        if (worker->surfaces[x].context.canvas) {
> > -            current_tree_for_each(worker, &worker->surfaces[x].current, __show_tree_call,
> > +        if (worker->surfaces.surfaces[x].context.canvas) {
> > +            current_tree_for_each(worker, &worker->surfaces.surfaces[x].current, __show_tree_call,
> >                                   &show_tree_data);
> >         }
> >     }
> > @@ -8283,6 +8324,12 @@ static void red_disconnect_channel(RedChannel *channel)
> >     red_unref_channel(channel);
> >  }
> >
> > +static void init_surfaces(Surfaces *surfaces)
> > +{
> > +    ring_init(&surfaces->current_list);
> > +    image_surface_init(surfaces);
> > +}
> > +
> >  static void red_disconnect_display(RedChannelClient *rcc)
> >  {
> >     // TODO: MC: right now we assume single channel
> > @@ -8391,7 +8438,8 @@ 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(RedWorker *worker, Surfaces *surfaces,
> > +                                              RedSurface *surface,
> >                                               uint32_t renderer, uint32_t width, uint32_t height,
> >                                               int32_t stride, uint32_t format, void *line_0)
> >  {
> > @@ -8402,7 +8450,7 @@ static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *sur
> >         canvas = canvas_create_for_data(width, height, format,
> >                                         line_0, stride,
> >                                         &worker->image_cache.base,
> > -                                        &worker->image_surfaces, NULL, NULL, NULL);
> > +                                        &surfaces->image_surfaces, NULL, NULL, NULL);
> >         surface->context.top_down = TRUE;
> >         surface->context.canvas_draws_on_surface = TRUE;
> >         return canvas;
> > @@ -8453,7 +8501,7 @@ static inline void __red_create_surface_item(RedWorker *worker, int surface_id,
> >         return;
> >     }
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &worker->surfaces.surfaces[surface_id];
> >
> >     create = get_surface_create_item(&worker->display_channel->common.base,
> >             surface_id, surface->context.width, surface->context.height,
> > @@ -8466,19 +8514,20 @@ static inline void __red_create_surface_item(RedWorker *worker, int surface_id,
> >
> >  static inline void red_create_surface_item(RedWorker *worker, int surface_id)
> >  {
> > -    if (is_primary_surface(worker, surface_id)) {
> > +    if (is_primary_surface(surface_id)) {
> >         __red_create_surface_item(worker, surface_id, SPICE_SURFACE_FLAGS_PRIMARY);
> >     } else {
> >         __red_create_surface_item(worker, surface_id, 0);
> >     }
> >  }
> >
> > -static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width,
> > +static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
> > +                                      uint32_t surface_id, uint32_t width,
> >                                       uint32_t height, int32_t stride, uint32_t format,
> >                                       void *line_0, int data_is_valid)
> >  {
> >     uint32_t i;
> > -    RedSurface *surface = &worker->surfaces[surface_id];
> > +    RedSurface *surface = &surfaces->surfaces[surface_id];
> >     if (stride >= 0) {
> >         PANIC("Untested path stride >= 0");
> >     }
> > @@ -8501,7 +8550,8 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
> >     region_init(&surface->draw_dirty_region);
> >     surface->refs = 1;
> >     if (worker->renderer != RED_RENDERER_INVALID) {
> > -        surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderer,
> > +        surface->context.canvas = create_canvas_for_surface(worker, surfaces,
> > +                                                            surface, worker->renderer,
> >                                                             width, height, stride,
> >                                                             surface->context.format, line_0);
> >         if (!surface->context.canvas) {
> > @@ -8513,7 +8563,8 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
> >     }
> >
> >     for (i = 0; i < worker->num_renderers; i++) {
> > -        surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderers[i],
> > +        surface->context.canvas = create_canvas_for_surface(worker, surfaces,
> > +                                                            surface, worker->renderers[i],
> >                                                             width, height, stride,
> >                                                             surface->context.format, line_0);
> >         if (surface->context.canvas) { //no need canvas check
> > @@ -8678,8 +8729,8 @@ static void on_new_display_channel(RedWorker *worker)
> >         return;
> >     }
> >     red_channel_ack_zero_messages_window(&display_channel->common.base);
> > -    if (worker->surfaces[0].context.canvas) {
> > -        red_current_flush(worker, 0);
> > +    if (worker->surfaces.surfaces[0].context.canvas) {
> > +        red_current_flush(worker, &worker->surfaces, 0);
> >         push_new_primary_surface(worker);
> >         red_add_surface_image(worker, 0);
> >         if (red_channel_is_connected(&display_channel->common.base)) {
> > @@ -9167,18 +9218,20 @@ static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
> >  {
> >     RedChannel *channel = rcc->channel;
> >     CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> > +    RedWorker *worker = common->worker;
> >
> >     ASSERT(item);
> >     switch (item->type) {
> >     case PIPE_ITEM_TYPE_DRAW:
> >     case PIPE_ITEM_TYPE_STREAM_CREATE:
> > -        release_drawable(common->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
> > +        release_drawable(common->worker, &common->worker->surfaces,
> > +                         SPICE_CONTAINEROF(item, Drawable, pipe_item));
> >         break;
> >     case PIPE_ITEM_TYPE_STREAM_CLIP:
> >         red_display_release_stream_clip((DisplayChannel *)channel, (StreamClipItem *)item);
> >         break;
> >     case PIPE_ITEM_TYPE_UPGRADE:
> > -        release_upgrade_item(common->worker, (UpgradeItem *)item);
> > +        release_upgrade_item(worker, &worker->surfaces, (UpgradeItem *)item);
> >         break;
> >     case PIPE_ITEM_TYPE_IMAGE:
> >         release_image_item((ImageItem *)item);
> > @@ -9351,7 +9404,7 @@ static void on_new_cursor_channel(RedWorker *worker)
> >     ASSERT(channel);
> >     red_channel_ack_zero_messages_window(&channel->common.base);
> >     red_channel_push_set_ack(&channel->common.base);
> > -    if (worker->surfaces[0].context.canvas && !channel->common.base.migrate) {
> > +    if (worker->surfaces.surfaces[0].context.canvas && !channel->common.base.migrate) {
> >         red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_CURSOR_INIT);
> >     }
> >  }
> > @@ -9559,10 +9612,10 @@ static inline void handle_dev_update(RedWorker *worker)
> >
> >     ASSERT(worker->running);
> >
> > -    validate_surface(worker, surface_id);
> > +    validate_surface(&worker->surfaces, surface_id);
> >     red_update_area(worker, rect, surface_id);
> >
> > -    surface = &worker->surfaces[surface_id];
> > +    surface = &worker->surfaces.surfaces[surface_id];
> >     region_ret_rects(&surface->draw_dirty_region, dirty_rects, num_dirty_rects);
> >
> >     if (clear_dirty_region) {
> > @@ -9600,17 +9653,17 @@ static inline void handle_dev_del_memslot(RedWorker *worker)
> >     red_memslot_info_del_slot(&worker->mem_slots, slot_group_id, slot_id);
> >  }
> >
> > -static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
> > +static inline void destroy_surface_wait(RedWorker *worker, Surfaces *surfaces, int surface_id)
> >  {
> > -    if (!worker->surfaces[surface_id].context.canvas) {
> > +    if (!surfaces->surfaces[surface_id].context.canvas) {
> >         return;
> >     }
> >
> > -    red_handle_depends_on_target_surface(worker, surface_id);
> > +    red_handle_depends_on_target_surface(worker, surfaces, surface_id);
> >     /* note that red_handle_depends_on_target_surface must be called before red_current_clear.
> >        otherwise "current" will hold items that other drawables may depend on, and then
> >        red_current_clear will remove them from the pipe. */
> > -    red_current_clear(worker, surface_id);
> > +    red_current_clear(worker, surfaces, surface_id);
> >     red_clear_surface_drawables_from_pipe(worker, surface_id, TRUE);
> >     // in case that the pipe didn't contain any item that is dependent on the surface, but
> >     // there is one during sending.
> > @@ -9631,8 +9684,8 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
> >
> >     flush_all_qxl_commands(worker);
> >
> > -    if (worker->surfaces[0].context.canvas) {
> > -        destroy_surface_wait(worker, 0);
> > +    if (worker->surfaces.surfaces[0].context.canvas) {
> > +        destroy_surface_wait(worker, &worker->surfaces, 0);
> >     }
> >
> >     message = RED_WORKER_MESSAGE_READY;
> > @@ -9642,18 +9695,20 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
> >  /* called upon device reset */
> >  static inline void handle_dev_destroy_surfaces(RedWorker *worker)
> >  {
> > +    Surfaces *surfaces = &worker->surfaces;
> >     int i;
> >     RedWorkerMessage message;
> > +
> >     red_printf("");
> >     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_destroy_surface(worker, i);
> > +        if (surfaces->surfaces[i].context.canvas) {
> > +            destroy_surface_wait(worker, &worker->surfaces, i);
> > +            if (surfaces->surfaces[i].context.canvas) {
> > +                red_destroy_surface(worker, surfaces, i);
> >             }
> > -            ASSERT(!worker->surfaces[i].context.canvas);
> > +            ASSERT(!surfaces->surfaces[i].context.canvas);
> >         }
> >     }
> >     ASSERT(ring_is_empty(&worker->streams));
> > @@ -9703,7 +9758,8 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
> >         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(worker, &worker->surfaces, 0, surface.width,
> > +                       surface.height, surface.stride, surface.format,
> >                        line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA);
> >
> >     if (worker->display_channel) {
> > @@ -9727,7 +9783,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
> >     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
> >
> >     PANIC_ON(surface_id != 0);
> > -    PANIC_ON(!worker->surfaces[surface_id].context.canvas);
> > +    PANIC_ON(!worker->surfaces.surfaces[surface_id].context.canvas);
> >
> >     if (worker->cursor) {
> >         red_release_cursor(worker, worker->cursor);
> > @@ -9744,11 +9800,11 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
> >     }
> >
> >     flush_all_qxl_commands(worker);
> > -    destroy_surface_wait(worker, 0);
> > -    red_destroy_surface(worker, 0);
> > +    destroy_surface_wait(worker, &worker->surfaces, 0);
> > +    red_destroy_surface(worker, &worker->surfaces, 0);
> >     ASSERT(ring_is_empty(&worker->streams));
> >
> > -    ASSERT(!worker->surfaces[surface_id].context.canvas);
> > +    ASSERT(!worker->surfaces.surfaces[surface_id].context.canvas);
> >
> >     worker->cursor_visible = TRUE;
> >     worker->cursor_position.x = worker->cursor_position.y = 0;
> > @@ -9782,7 +9838,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> >             red_channel_push(&worker->display_channel->common.base);
> >         }
> >         if (worker->qxl->st->qif->flush_resources(worker->qxl) == 0) {
> > -            red_printf("oom current %u pipe %u", worker->current_size,
> > +            red_printf("oom current %u pipe %u", worker->surfaces.current_size,
> >                        worker->display_channel ?
> >                        display_red_channel->rcc->pipe_size : 0);
> >             red_free_some(worker);
> > @@ -9864,8 +9920,8 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> >         worker->running = FALSE;
> >         red_display_clear_glz_drawables(worker->display_channel);
> >         for (x = 0; x < NUM_SURFACES; ++x) {
> > -            if (worker->surfaces[x].context.canvas) {
> > -                red_current_flush(worker, x);
> > +            if (worker->surfaces.surfaces[x].context.canvas) {
> > +                red_current_flush(worker, &worker->surfaces, x);
> >             }
> >         }
> >         red_cursor_flush(worker);
> > @@ -10056,9 +10112,8 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
> >     worker->jpeg_state = init_data->jpeg_state;
> >     worker->zlib_glz_state = init_data->zlib_glz_state;
> >     worker->streaming_video = init_data->streaming_video;
> > -    ring_init(&worker->current_list);
> > +    init_surfaces(&worker->surfaces);
> >     image_cache_init(&worker->image_cache);
> > -    image_surface_init(worker);
> >     drawables_init(worker);
> >     cursor_items_init(worker);
> >     red_init_streams(worker);
> > @@ -10092,7 +10147,7 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
> >                           init_data->internal_groupslot_id);
> >
> >     PANIC_ON(init_data->n_surfaces > NUM_SURFACES);
> > -    worker->n_surfaces = init_data->n_surfaces;
> > +    worker->surfaces.n_surfaces = init_data->n_surfaces;
> >
> >     message = RED_WORKER_MESSAGE_READY;
> >     write_message(worker->channel, &message);
> > @@ -10320,4 +10375,3 @@ static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_i
> >  }
> >
> >  #endif
> > -
> > --
> > 1.7.4.4
> >
> > _______________________________________________
> > Spice-devel mailing list
> > Spice-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/spice-devel
> >
> 
> 
> 
> -- 
> Marc-André Lureau


More information about the Spice-devel mailing list