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

Alon Levy alevy at redhat.com
Tue Apr 26 03:54:49 PDT 2011


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.

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.

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.
---
 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



More information about the Spice-devel mailing list