[Spice-devel] [RFCv5 23/47] server/red_worker: split RedRender from RedWorker

Alon Levy alevy at redhat.com
Sun May 8 06:11:19 PDT 2011


Split the operations list, the surfaces and the streams out from RedWorker
into a RedRender struct that has a reference to RedWorker.
This patch is technical, changing signatures to use RedRender *render
instead of RedWorker *worker, and changing s/worker/worker->surfaces/.

In later patches there will be a multiplicity of RedRender:
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 RedRender
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 RedRender, 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 use RedRender as the first
parameter instead of using worker, this is in preparation for the next patches
where RedRender instances multiply.
---
 server/red_worker.c |  731 ++++++++++++++++++++++++++++-----------------------
 1 files changed, 406 insertions(+), 325 deletions(-)

diff --git a/server/red_worker.c b/server/red_worker.c
index dfc934c..f3de49f 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -565,6 +565,7 @@ typedef struct CommonChannel {
     uint8_t recv_buf[RECIVE_BUF_SIZE];
 } CommonChannel;
 
+typedef struct RedRender RedRender;
 
 struct DisplayChannel {
     CommonChannel common; // Must be the first thing
@@ -809,7 +810,32 @@ typedef struct ItemTrace {
 #define NUM_DRAWABLES 1000
 #define NUM_CURSORS 100
 
-typedef struct RedWorker {
+typedef struct RedWorker RedWorker;
+
+struct RedRender {
+    RedWorker *worker;
+    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;
+
+    Stream streams_buf[NUM_STREAMS];
+    Stream *free_streams;
+    Ring streams;
+
+#ifdef PIPE_DEBUG
+    uint32_t last_id;
+#endif
+};
+
+struct RedWorker {
     EventListener dev_listener;
     DisplayChannel *display_channel;
     CursorChannel *cursor_channel;
@@ -826,17 +852,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;
+    RedRender render;
 
     uint32_t bits_unique;
 
@@ -865,9 +881,6 @@ typedef struct RedWorker {
     uint32_t mouse_mode;
 
     uint32_t streaming_video;
-    Stream streams_buf[NUM_STREAMS];
-    Stream *free_streams;
-    Ring streams;
     ItemTrace items_trace[NUM_TRACE_ITEMS];
     uint32_t next_item_trace;
 
@@ -883,9 +896,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;
@@ -898,7 +908,7 @@ typedef struct RedWorker {
     uint64_t *wakeup_counter;
     uint64_t *command_counter;
 #endif
-} RedWorker;
+};
 
 typedef enum {
     BITMAP_DATA_TYPE_INVALID,
@@ -914,22 +924,25 @@ 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(RedRender *render, Drawable *drawable);
+static void red_current_flush(RedRender *render, int surface_id);
 #ifdef DRAW_ALL
 #define red_update_area(worker, rect, surface_id)
-#define red_draw_drawable(worker, item)
+#define red_render_update_area(render, rect, surface_id)
+#define red_draw_drawable(render, item)
 #else
-static void red_draw_drawable(RedWorker *worker, Drawable *item);
+static void red_draw_drawable(RedRender *render, Drawable *item);
 static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id);
+static void red_render_update_area(RedRender *render, 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(RedRender *render, 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);
-static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *sect);
-static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarshaller *base_marshaller);
+static inline void red_detach_stream(RedRender *render, Stream *stream);
+static void red_stop_stream(RedRender *render, Stream *stream);
+static inline void red_stream_maintenance(RedRender *render, Drawable *candidate, Drawable *sect);
+static inline void display_begin_send_message(RedChannelClient *rcc,
+                                              SpiceMarshaller *base_marshaller);
 static void red_release_pixmap_cache(DisplayChannel *channel);
 static void red_release_glz(DisplayChannel *channel);
 static void red_freeze_glz(DisplayChannel *channel);
@@ -1026,7 +1039,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;
@@ -1034,15 +1047,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(RedRender *render, uint32_t surface_id)
 {
-    PANIC_ON(surface_id >= worker->n_surfaces);
+    PANIC_ON(surface_id >= render->n_surfaces);
 }
 
-static inline void validate_surface(RedWorker *worker, uint32_t surface_id)
+static inline void validate_surface(RedRender *render, uint32_t surface_id)
 {
-    PANIC_ON(surface_id >= worker->n_surfaces);
-    PANIC_ON(!worker->surfaces[surface_id].context.canvas);
+    PANIC_ON(surface_id >= render->n_surfaces);
+    PANIC_ON(!render->surfaces[surface_id].context.canvas);
 }
 
 static char *draw_type_to_str(uint8_t type)
@@ -1171,7 +1184,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->render, surface_id);
             red_add_surface_image(worker, surface_id);
         }
     }
@@ -1181,7 +1194,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->render, drawable->surface_id);
     red_add_surface_image(worker, drawable->surface_id);
 }
 
@@ -1242,7 +1255,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(RedRender *render, uint32_t surface_id);
 
 static inline void red_pipe_remove_drawable(RedWorker *worker, Drawable *drawable)
 {
@@ -1278,10 +1291,10 @@ static void release_image_item(ImageItem *item)
     }
 }
 
-static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
+static void release_upgrade_item(RedRender *render, UpgradeItem *item)
 {
     if (!--item->refs) {
-        release_drawable(worker, item->drawable);
+        release_drawable(render, item->drawable);
         free(item->rects);
         free(item);
     }
@@ -1349,7 +1362,7 @@ static void drawables_init(RedWorker *worker)
 }
 
 
-static void red_reset_stream_trace(RedWorker *worker);
+static void red_reset_stream_trace(RedRender *render);
 
 static SurfaceDestroyItem *get_surface_destroy_item(RedChannel *channel,
                                                     uint32_t surface_id)
@@ -1381,14 +1394,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(RedRender *render, uint32_t surface_id)
 {
-    RedSurface *surface = &worker->surfaces[surface_id];
+    RedWorker *worker = render->worker;
+    RedSurface *surface = &render->surfaces[surface_id];
 
     if (!--surface->refs) {
         // only primary surface streams are supported
-        if (is_primary_surface(worker, surface_id)) {
-            red_reset_stream_trace(worker);
+        if (is_primary_surface(surface_id)) {
+            red_reset_stream_trace(render);
         }
         ASSERT(surface->context.canvas);
 
@@ -1408,12 +1422,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(RedRender *render, uint32_t surface_id, int is_create,
                                             QXLReleaseInfo *release_info, uint32_t group_id)
 {
     RedSurface *surface;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &render->surfaces[surface_id];
 
     if (is_create) {
         surface->create.info = release_info;
@@ -1447,7 +1461,7 @@ 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(RedRender *render, Drawable *drawable)
 {
     int x;
     int surface_id;
@@ -1457,7 +1471,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(render, surface_id);
     }
 }
 
@@ -1474,16 +1488,18 @@ static void remove_drawable_dependencies(RedWorker *worker, Drawable *drawable)
     }
 }
 
-static inline void release_drawable(RedWorker *worker, Drawable *item)
+static inline void release_drawable(RedRender *render, Drawable *item)
 {
+    RedWorker *worker = render->worker;
+
     if (!--item->refs) {
         ASSERT(!item->stream);
         ASSERT(!item->tree_item.shadow);
         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(render, item);
+        red_destroy_surface(render, item->surface_id);
 
         if (item->red_glz_drawable) {
             item->red_glz_drawable->drawable = NULL;
@@ -1494,7 +1510,7 @@ static inline void release_drawable(RedWorker *worker, Drawable *item)
     }
 }
 
-static inline void remove_shadow(RedWorker *worker, DrawItem *item)
+static inline void remove_shadow(RedRender *render, DrawItem *item)
 {
     Shadow *shadow;
 
@@ -1507,19 +1523,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--;
+    render->shadows_count--;
 }
 
-static inline void current_remove_container(RedWorker *worker, Container *container)
+static inline void current_remove_container(RedRender *render, Container *container)
 {
     ASSERT(ring_is_empty(&container->items));
-    worker->containers_count--;
+    render->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(RedRender *render, Container *container)
 {
     while (container && container->items.next == container->items.prev) {
         Container *next = container->base.container;
@@ -1530,7 +1546,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(render, container);
         container = next;
     }
 }
@@ -1553,12 +1569,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(RedRender *render, int surface_id, SpiceRect *rect)
 {
-    red_update_area(worker, rect, surface_id);
+    red_render_update_area(render, rect, surface_id);
 }
 
-static void red_flush_source_surfaces(RedWorker *worker, Drawable *drawable)
+static void red_flush_source_surfaces(RedRender *render, Drawable *drawable)
 {
     int x;
     int surface_id;
@@ -1567,38 +1583,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(render, surface_id,
+                          &drawable->red_drawable->surfaces_rects[x]);
         }
     }
 }
 
-static inline void current_remove_drawable(RedWorker *worker, Drawable *item)
+static inline void current_remove_drawable(RedRender *render, Drawable *item)
 {
-    worker->drawable_count--;
+    RedWorker *worker = render->worker;
 
+    render->drawable_count--;
     if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
-        worker->transparent_count--;
+        render->transparent_count--;
     }
     if (item->stream) {
-        red_detach_stream(worker, item->stream);
+        red_detach_stream(render, item->stream);
     } else {
         red_add_item_trace(worker, item);
     }
-    remove_shadow(worker, &item->tree_item);
+    remove_shadow(render, &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(render, item);
+    render->current_size--;
 }
 
-static void remove_drawable(RedWorker *worker, Drawable *item)
+static void remove_drawable(RedRender *render, Drawable *item)
 {
-    red_pipe_remove_drawable(worker, item);
-    current_remove_drawable(worker, item);
+    red_pipe_remove_drawable(render->worker, item);
+    current_remove_drawable(render, item);
 }
 
-static inline void current_remove(RedWorker *worker, TreeItem *item)
+static inline void current_remove(RedRender *render, TreeItem *item)
 {
     TreeItem *now = item;
 
@@ -1608,7 +1626,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(render, SPICE_CONTAINEROF(now, Drawable, tree_item));
         } else {
             Container *container = (Container *)now;
 
@@ -1619,7 +1637,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(render, container);
         }
         if (now == item) {
             return;
@@ -1671,13 +1689,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(RedRender *render, int surface_id)
 {
     RingItem *ring_item;
 
-    while ((ring_item = ring_get_head(&worker->surfaces[surface_id].current))) {
+    while ((ring_item = ring_get_head(&render->surfaces[surface_id].current))) {
         TreeItem *now = SPICE_CONTAINEROF(ring_item, TreeItem, siblings_link);
-        current_remove(worker, now);
+        current_remove(render, now);
     }
 }
 
@@ -1768,6 +1786,7 @@ static void print_draw_item(const char* prefix, const DrawItem *draw_item)
 {
     const TreeItem *base = &draw_item->base;
     const Drawable *drawable = SPICE_CONTAINEROF(draw_item, Drawable, tree_item);
+
     printf("TEST: %s: draw id %u container %u effect %u",
            prefix,
            base->id, base->container ? base->container->base.id : 0,
@@ -1864,9 +1883,11 @@ static inline int __contained_by(RedWorker *worker, TreeItem *item, Ring *ring)
     return FALSE;
 }
 
-static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *item, QRegion *rgn,
+static inline void __exclude_region(RedRender *render,
+                                    Ring *ring, TreeItem *item, QRegion *rgn,
                                     Ring **top_ring, Drawable *frame_candidate)
 {
+    RedWorker *worker = render->worker;
     QRegion and_rgn;
 #ifdef RED_WORKER_STAT
     stat_time_t start_time = stat_now();
@@ -1904,7 +1925,7 @@ static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *ite
             } else {
                 if (frame_candidate) {
                     Drawable *drawable = SPICE_CONTAINEROF(draw, Drawable, tree_item);
-                    red_stream_maintenance(worker, frame_candidate, drawable);
+                    red_stream_maintenance(render, frame_candidate, drawable);
                 }
                 region_exclude(&draw->base.rgn, &and_rgn);
             }
@@ -1935,7 +1956,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(RedRender *render, Ring *ring,
+                           RingItem *ring_item, QRegion *rgn,
                            TreeItem **last, Drawable *frame_candidate)
 {
 #ifdef RED_WORKER_STAT
@@ -1957,14 +1979,14 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
 
         if (region_intersects(rgn, &now->rgn)) {
             print_base_item("EXCLUDE2", now);
-            __exclude_region(worker, ring, now, rgn, &top_ring, frame_candidate);
+            __exclude_region(render, ring, now, rgn, &top_ring, frame_candidate);
             print_base_item("EXCLUDE3", now);
 
             if (region_is_empty(&now->rgn)) {
                 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(render, now);
                 if (last && *last == now) {
                     *last = (TreeItem *)ring_next(ring, ring_item);
                 }
@@ -1997,12 +2019,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(RedRender *render, DrawItem *item)
 {
     Container *container = spice_new(Container, 1);
-    worker->containers_count++;
+    render->containers_count++;
 #ifdef PIPE_DEBUG
-    container->base.id = ++worker->last_id;
+    container->base.id = ++render->last_id;
 #endif
     container->base.type = TREE_ITEM_TYPE_CONTAINER;
     container->base.container = item->base.container;
@@ -2024,15 +2046,15 @@ 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(RedRender *render, Drawable *drawable, RingItem *pos)
 {
     RedSurface *surface;
     uint32_t surface_id = drawable->surface_id;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &render->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(&render->current_list, &drawable->list_link);
+    render->drawable_count++;
     ring_add(&surface->current_list, &drawable->surface_list_link);
     drawable->refs++;
 }
@@ -2114,24 +2136,24 @@ static int is_same_drawable(RedWorker *worker, Drawable *d1, Drawable *d2)
     }
 }
 
-static inline void red_free_stream(RedWorker *worker, Stream *stream)
+static inline void red_free_stream(RedRender *render, Stream *stream)
 {
-    stream->next = worker->free_streams;
-    worker->free_streams = stream;
+    stream->next = render->free_streams;
+    render->free_streams = stream;
 }
 
-static void red_release_stream(RedWorker *worker, Stream *stream)
+static void red_release_stream(RedRender *render, Stream *stream)
 {
     if (!--stream->refs) {
         ASSERT(!ring_item_is_linked(&stream->link));
         if (stream->mjpeg_encoder) {
             mjpeg_encoder_destroy(stream->mjpeg_encoder);
         }
-        red_free_stream(worker, stream);
+        red_free_stream(render, stream);
     }
 }
 
-static inline void red_detach_stream(RedWorker *worker, Stream *stream)
+static inline void red_detach_stream(RedRender *render, Stream *stream)
 {
     ASSERT(stream->current && stream->current->stream);
     ASSERT(stream->current->stream == stream);
@@ -2205,9 +2227,11 @@ static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipI
     }
 }
 
-static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *stream)
+static void red_attach_stream(RedRender *render, Drawable *drawable, Stream *stream)
 {
+    RedWorker *worker = render->worker;
     DisplayChannel *channel;
+
     ASSERT(!drawable->stream && !stream->current);
     ASSERT(drawable && stream);
     stream->current = drawable;
@@ -2215,7 +2239,7 @@ static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *str
     stream->last_time = drawable->creation_time;
 
     if ((channel = worker->display_channel)) {
-        StreamAgent *agent = &channel->stream_agents[stream - worker->streams_buf];
+        StreamAgent *agent = &channel->stream_agents[stream - render->streams_buf];
         if (!region_is_equal(&agent->vis_region, &drawable->tree_item.base.rgn)) {
             region_destroy(&agent->vis_region);
             region_clone(&agent->vis_region, &drawable->tree_item.base.rgn);
@@ -2224,22 +2248,23 @@ static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *str
     }
 }
 
-static void red_stop_stream(RedWorker *worker, Stream *stream)
+static void red_stop_stream(RedRender *render, Stream *stream)
 {
+    RedWorker *worker = render->worker;
     DisplayChannel *channel;
     ASSERT(ring_item_is_linked(&stream->link));
     ASSERT(!stream->current);
 
     if ((channel = worker->display_channel)) {
         StreamAgent *stream_agent;
-        stream_agent = &channel->stream_agents[stream - worker->streams_buf];
+        stream_agent = &channel->stream_agents[stream - render->streams_buf];
         region_clear(&stream_agent->vis_region);
         ASSERT(!pipe_item_is_linked(&stream_agent->destroy_item));
         stream->refs++;
         red_channel_client_pipe_add(channel->common.base.rcc, &stream_agent->destroy_item);
     }
     ring_remove(&stream->link);
-    red_release_stream(worker, stream);
+    red_release_stream(render, stream);
 }
 
 static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *stream)
@@ -2263,13 +2288,14 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
         region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn, upgrade_item->rects->rects, n_rects);
         red_channel_client_pipe_add(channel->common.base.rcc, &upgrade_item->base);
     }
-    red_detach_stream(worker, stream);
+    red_detach_stream(&worker->render, stream);
 }
 
 // region should be a primary surface region
 static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
 {
-    Ring *ring = &worker->streams;
+    RedRender *render = &worker->render;
+    Ring *ring = &render->streams;
     RingItem *item = ring_get_head(ring);
     DisplayChannel *channel = worker->display_channel;
 
@@ -2278,7 +2304,7 @@ static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
         item = ring_next(ring, item);
 
         if (channel) {
-            StreamAgent *agent = &channel->stream_agents[stream - worker->streams_buf];
+            StreamAgent *agent = &channel->stream_agents[stream - render->streams_buf];
             if (region_intersects(&agent->vis_region, region)) {
                 region_clear(&agent->vis_region);
                 push_stream_clip(channel, agent);
@@ -2288,7 +2314,7 @@ static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
             }
         } else if (stream->current && region_intersects(&stream->current->tree_item.base.rgn,
                                                         region)) {
-            red_detach_stream(worker, stream);
+            red_detach_stream(render, stream);
         }
     }
 }
@@ -2296,6 +2322,7 @@ static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
 static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
 {
     DisplayChannel *channel = worker->display_channel;
+    RedRender *render = &worker->render;
     Ring *ring;
     RingItem *item;
 
@@ -2303,11 +2330,11 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
         return;
     }
 
-    if (!is_primary_surface(worker, drawable->surface_id)) {
+    if (!is_primary_surface(drawable->surface_id)) {
         return;
     }
 
-    ring = &worker->streams;
+    ring = &render->streams;
     item = ring_get_head(ring);
 
     while (item) {
@@ -2316,7 +2343,7 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
 
         item = ring_next(ring, item);
 
-        agent = &channel->stream_agents[stream - worker->streams_buf];
+        agent = &channel->stream_agents[stream - render->streams_buf];
 
         if (stream->current == drawable) {
             continue;
@@ -2329,10 +2356,10 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
     }
 }
 
-static inline unsigned int red_get_streams_timout(RedWorker *worker)
+static inline unsigned int red_get_streams_timout(RedRender *render)
 {
     unsigned int timout = -1;
-    Ring *ring = &worker->streams;
+    Ring *ring = &render->streams;
     RingItem *item = ring;
     struct timespec time;
 
@@ -2352,9 +2379,10 @@ static inline unsigned int red_get_streams_timout(RedWorker *worker)
     return timout;
 }
 
-static inline void red_handle_streams_timout(RedWorker *worker)
+static inline void red_handle_streams_timout(RedRender *render)
 {
-    Ring *ring = &worker->streams;
+    RedWorker *worker = render->worker;
+    Ring *ring = &render->streams;
     struct timespec time;
     RingItem *item;
 
@@ -2368,7 +2396,7 @@ static inline void red_handle_streams_timout(RedWorker *worker)
             if (stream->current) {
                 red_detach_stream_gracefully(worker, stream);
             }
-            red_stop_stream(worker, stream);
+            red_stop_stream(&worker->render, stream);
         }
     }
 }
@@ -2376,17 +2404,17 @@ static inline void red_handle_streams_timout(RedWorker *worker)
 static void red_display_release_stream(DisplayChannel *display, StreamAgent *agent)
 {
     ASSERT(agent->stream);
-    red_release_stream(display->common.worker, agent->stream);
+    red_release_stream(&display->common.worker->render, agent->stream);
 }
 
-static inline Stream *red_alloc_stream(RedWorker *worker)
+static inline Stream *red_alloc_stream(RedRender *render)
 {
     Stream *stream;
-    if (!worker->free_streams) {
+    if (!render->free_streams) {
         return NULL;
     }
-    stream = worker->free_streams;
-    worker->free_streams = worker->free_streams->next;
+    stream = render->free_streams;
+    render->free_streams = render->free_streams->next;
     return stream;
 }
 
@@ -2411,7 +2439,7 @@ static int get_bit_rate(RedWorker *worker,
 
 static void red_display_create_stream(DisplayChannel *display, Stream *stream)
 {
-    StreamAgent *agent = &display->stream_agents[stream - display->common.worker->streams_buf];
+    StreamAgent *agent = &display->stream_agents[stream - display->common.worker->render.streams_buf];
     stream->refs++;
     ASSERT(region_is_empty(&agent->vis_region));
     if (stream->current) {
@@ -2428,6 +2456,7 @@ static void red_display_create_stream(DisplayChannel *display, Stream *stream)
 
 static void red_create_stream(RedWorker *worker, Drawable *drawable)
 {
+    RedRender *render = &worker->render;
     Stream *stream;
     SpiceRect* src_rect;
     int stream_width;
@@ -2435,7 +2464,7 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
 
     ASSERT(!drawable->stream);
 
-    if (!(stream = red_alloc_stream(worker))) {
+    if (!(stream = red_alloc_stream(render))) {
         return;
     }
 
@@ -2446,7 +2475,7 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
 
     stream->mjpeg_encoder = mjpeg_encoder_new(stream_width, stream_height);
 
-    ring_add(&worker->streams, &stream->link);
+    ring_add(&render->streams, &stream->link);
     stream->current = drawable;
     stream->last_time = drawable->creation_time;
     stream->width = src_rect->right - src_rect->left;
@@ -2467,7 +2496,7 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
 
 static void red_disply_start_streams(DisplayChannel *display_channel)
 {
-    Ring *ring = &display_channel->common.worker->streams;
+    Ring *ring = &display_channel->common.worker->render.streams;
     RingItem *item = ring;
 
     while ((item = ring_next(ring, item))) {
@@ -2481,7 +2510,7 @@ static void red_display_init_streams(DisplayChannel *display)
     int i;
     for (i = 0; i < NUM_STREAMS; i++) {
         StreamAgent *agent = &display->stream_agents[i];
-        agent->stream = &display->common.worker->streams_buf[i];
+        agent->stream = &display->common.worker->render.streams_buf[i];
         region_init(&agent->vis_region);
         red_channel_pipe_item_init(&display->common.base,
                     &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
@@ -2499,16 +2528,17 @@ static void red_display_destroy_streams(DisplayChannel *display)
     }
 }
 
-static void red_init_streams(RedWorker *worker)
+static void red_init_streams(RedRender *render)
 {
     int i;
 
-    ring_init(&worker->streams);
-    worker->free_streams = NULL;
+    ASSERT(render);
+    ring_init(&render->streams);
+    render->free_streams = NULL;
     for (i = 0; i < NUM_STREAMS; i++) {
-        Stream *stream = &worker->streams_buf[i];
+        Stream *stream = &render->streams_buf[i];
         ring_item_init(&stream->link);
-        red_free_stream(worker, stream);
+        red_free_stream(render, stream);
     }
 }
 
@@ -2586,15 +2616,17 @@ static int display_channel_is_low_bandwidth(DisplayChannel *display_channel)
     return FALSE;
 }
 
-static inline void pre_stream_item_swap(RedWorker *worker, Stream *stream)
+static inline void pre_stream_item_swap(RedRender *render, Stream *stream)
 {
-    ASSERT(stream->current);
+    RedWorker *worker = render->worker;
 
-    if (!display_is_connected(worker) || !display_channel_is_low_bandwidth(worker->display_channel)) {
+    ASSERT(stream->current);
+    if (!display_is_connected(worker) ||
+        !display_channel_is_low_bandwidth(worker->display_channel)) {
         return;
     }
 
-    int index = stream - worker->streams_buf;
+    int index = stream - render->streams_buf;
     StreamAgent *agent = &worker->display_channel->stream_agents[index];
 
     if (pipe_item_is_linked(&stream->current->pipe_item)) {
@@ -2683,8 +2715,9 @@ static int red_stream_add_frame(RedWorker* worker, Drawable *frame_drawable,
     return FALSE;
 }
 
-static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *prev)
+static inline void red_stream_maintenance(RedRender *render, Drawable *candidate, Drawable *prev)
 {
+    RedWorker *worker = render->worker;
     Stream *stream;
 
     if (candidate->stream) {
@@ -2696,10 +2729,10 @@ static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate
     }
 
     if ((stream = prev->stream)) {
-        pre_stream_item_swap(worker, stream);
-        red_detach_stream(worker, stream);
+        pre_stream_item_swap(render, stream);
+        red_detach_stream(render, stream);
         prev->streamable = FALSE; //prevent item trace
-        red_attach_stream(worker, candidate, stream);
+        red_attach_stream(render, candidate, stream);
     } else {
         red_stream_add_frame(worker, candidate,
                              prev->frames_count,
@@ -2720,8 +2753,9 @@ 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(RedRender *render, DrawItem *item, TreeItem *other)
 {
+    RedWorker *worker = render->worker;
     DrawItem *other_draw_item;
     Drawable *drawable;
     Drawable *other_drawable;
@@ -2740,14 +2774,14 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
 
     if (item->effect == QXL_EFFECT_OPAQUE) {
         int add_after = !!other_drawable->stream && is_drawable_independent_from_surfaces(drawable);
-        red_stream_maintenance(worker, drawable, other_drawable);
-        __current_add_drawable(worker, drawable, &other->siblings_link);
+        red_stream_maintenance(render, drawable, other_drawable);
+        __current_add_drawable(render, 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(render, other_drawable);
         return TRUE;
     }
 
@@ -2757,14 +2791,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(render, 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(render, drawable, &other->siblings_link);
+            remove_drawable(render, other_drawable);
             red_pipe_add_drawable(worker, drawable);
             return TRUE;
         }
@@ -2778,8 +2812,9 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
     return FALSE;
 }
 
-static inline void red_use_stream_trace(RedWorker *worker, Drawable *drawable)
+static inline void red_use_stream_trace(RedRender *render, Drawable *drawable)
 {
+    RedWorker *worker = render->worker;
     ItemTrace *trace;
     ItemTrace *trace_end;
     Ring *ring;
@@ -2789,8 +2824,7 @@ static inline void red_use_stream_trace(RedWorker *worker, Drawable *drawable)
         return;
     }
 
-
-    ring = &worker->streams;
+    ring = &render->streams;
     item = ring_get_head(ring);
 
     while (item) {
@@ -2802,7 +2836,7 @@ static inline void red_use_stream_trace(RedWorker *worker, Drawable *drawable)
                                                            &stream->dest_area,
                                                            stream->last_time,
                                                            stream)) {
-            red_attach_stream(worker, drawable, stream);
+            red_attach_stream(render, drawable, stream);
             return;
         }
         item = ring_next(ring, item);
@@ -2823,16 +2857,17 @@ 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(RedRender *render)
 {
-    Ring *ring = &worker->streams;
+    RedWorker *worker = render->worker;
+    Ring *ring = &render->streams;
     RingItem *item = ring_get_head(ring);
 
     while (item) {
         Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
         item = ring_next(ring, item);
         if (!stream->current) {
-            red_stop_stream(worker, stream);
+            red_stop_stream(render, stream);
         } else {
             red_printf("attached stream");
         }
@@ -2842,8 +2877,9 @@ 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(RedRender *render, Ring *ring, Drawable *drawable)
 {
+    RedWorker *worker = render->worker;
     DrawItem *item = &drawable->tree_item;
 #ifdef RED_WORKER_STAT
     stat_time_t start_time = stat_now();
@@ -2854,7 +2890,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++;
+    render->current_size++;
     region_init(&exclude_rgn);
     now = ring_next(ring, ring);
 
@@ -2874,8 +2910,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(render, item, sibling)) {
                 stat_add(&worker->add_stat, start_time);
                 return FALSE;
             }
@@ -2888,7 +2924,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(render, ring, exclude_base,
+                                       &exclude_rgn, &next, NULL);
                         if (next != sibling) {
                             now = next ? &next->siblings_link : NULL;
                             exclude_base = NULL;
@@ -2898,7 +2935,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(render, sibling);
                 now = ring_next(ring, now);
                 if (shadow || skip) {
                     exclude_base = now;
@@ -2910,7 +2947,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(render, ring, exclude_base, &exclude_rgn, NULL, NULL);
                     region_clear(&exclude_rgn);
                     exclude_base = NULL;
                 }
@@ -2924,7 +2961,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(render, (DrawItem *)sibling);
                     if (!container) {
                         red_printf("create new container failed");
                         region_destroy(&exclude_rgn);
@@ -2942,8 +2979,8 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
     }
     if (item->effect == QXL_EFFECT_OPAQUE) {
         region_or(&exclude_rgn, &item->base.rgn);
-        exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL, drawable);
-        red_use_stream_trace(worker, drawable);
+        exclude_region(render, ring, exclude_base, &exclude_rgn, NULL, drawable);
+        red_use_stream_trace(render, drawable);
         red_streams_update_clip(worker, drawable);
     } else {
         if (drawable->surface_id == 0) {
@@ -2951,7 +2988,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(render, drawable, ring);
     stat_add(&worker->add_stat, start_time);
     return TRUE;
 }
@@ -2965,16 +3002,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(RedRender *render, Drawable *item, SpicePoint *delta)
 {
     if (!delta->x && !delta->y) {
         return NULL;
     }
 
     Shadow *shadow = spice_new(Shadow, 1);
-    worker->shadows_count++;
+    render->shadows_count++;
 #ifdef PIPE_DEBUG
-    shadow->base.id = ++worker->last_id;
+    shadow->base.id = ++render->last_id;
 #endif
     shadow->base.type = TREE_ITEM_TYPE_SHADOW;
     shadow->base.container = NULL;
@@ -2987,31 +3024,33 @@ 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(RedRender *render, Ring *ring, Drawable *item,
+                                              SpicePoint *delta)
 {
+    RedWorker *worker = render->worker;
 #ifdef RED_WORKER_STAT
     stat_time_t start_time = stat_now();
 #endif
 
-    Shadow *shadow = __new_shadow(worker, item, delta);
+    Shadow *shadow = __new_shadow(render, item, delta);
     if (!shadow) {
         stat_add(&worker->add_stat, start_time);
         return FALSE;
     }
     print_base_item("ADDSHADOW", &item->tree_item.base);
-    worker->current_size++;
+    render->current_size++;
     // item and his shadow must initially be placed in the same container.
     // for now putting them on root.
 
-    if (is_primary_surface(worker, item->surface_id)) {
+    if (is_primary_surface(item->surface_id)) {
         red_detach_streams_behind(worker, &shadow->base.rgn);
     }
     ring_add(ring, &shadow->base.siblings_link);
-    __current_add_drawable(worker, item, ring);
+    __current_add_drawable(render, 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(render, ring, &shadow->base.siblings_link, &exclude_rgn, NULL, NULL);
         region_destroy(&exclude_rgn);
         red_streams_update_clip(worker, item);
     } else {
@@ -3037,7 +3076,7 @@ static inline void red_update_streamable(RedWorker *worker, Drawable *drawable,
         return;
     }
 
-    if (!is_primary_surface(worker, drawable->surface_id)) {
+    if (!is_primary_surface(drawable->surface_id)) {
         return;
     }
 
@@ -3067,9 +3106,10 @@ 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(RedRender *render, Ring *ring, Drawable *drawable,
                                       RedDrawable *red_drawable)
 {
+    RedWorker *worker = render->worker;
     int ret;
 
     if (has_shadow(red_drawable)) {
@@ -3080,10 +3120,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(render, ring, drawable, &delta);
     } else {
         red_update_streamable(worker, drawable, red_drawable);
-        ret = red_current_add(worker, ring, drawable);
+        ret = red_current_add(render, ring, drawable);
     }
 #ifdef RED_WORKER_STAT
     if ((++worker->add_count % 100) == 0) {
@@ -3112,15 +3152,15 @@ 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(RedRender *render, int surface_id, const SpiceRect *area, uint8_t *dest,
                          int dest_stride, int update)
 {
     SpiceCanvas *canvas;
     RedSurface *surface;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &render->surfaces[surface_id];
     if (update) {
-        red_update_area(worker, area, surface_id);
+        red_render_update_area(render, area, surface_id);
     }
 
     canvas = surface->context.canvas;
@@ -3170,8 +3210,9 @@ 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(RedRender *render, Drawable *drawable)
 {
+    RedWorker *worker = render->worker;
     SpiceImage *image;
     int32_t width;
     int32_t height;
@@ -3185,8 +3226,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
         return TRUE;
     }
 
-
-    surface = &worker->surfaces[drawable->surface_id];
+    surface = &render->surfaces[drawable->surface_id];
 
     bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
 
@@ -3210,12 +3250,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(render, 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) {
@@ -3229,9 +3269,10 @@ 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(RedRender *render, int force_glz_free)
 {
-    RingItem *ring_item = ring_get_tail(&worker->current_list);
+    RedWorker *worker = render->worker;
+    RingItem *ring_item = ring_get_tail(&render->current_list);
     Drawable *drawable;
     Container *container;
 
@@ -3241,28 +3282,29 @@ 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(render, drawable);
     container = drawable->tree_item.base.container;
 
-    current_remove_drawable(worker, drawable);
-    container_cleanup(worker, container);
+    current_remove_drawable(render, drawable);
+    container_cleanup(render, container);
 }
 
-static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *red_drawable,
+static Drawable *get_drawable(RedRender *render, uint8_t effect, RedDrawable *red_drawable,
                               uint32_t group_id) {
+    RedWorker *worker = render->worker;
     Drawable *drawable;
     struct timespec time;
     int x;
 
     while (!(drawable = alloc_drawable(worker))) {
-        free_one_drawable(worker, FALSE);
+        free_one_drawable(render, 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 = ++render->last_id;
 #endif
     ring_item_init(&drawable->list_link);
     ring_item_init(&drawable->surface_list_link);
@@ -3279,35 +3321,35 @@ 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(render, 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(render, 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(RedRender *render, uint32_t surface_id)
 {
     RedSurface *surface;
     RingItem *ring_item;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &render->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(render, 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(RedRender *render, int depend_on_surface_id,
                                              DependItem *depend_item, Drawable *drawable)
 {
     RedSurface *surface;
@@ -3317,13 +3359,13 @@ static inline void add_to_surface_dependency(RedWorker *worker, int depend_on_su
         return;
     }
 
-    surface = &worker->surfaces[depend_on_surface_id];
+    surface = &render->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(RedRender *render, Drawable *drawable)
 {
     int x;
 
@@ -3331,14 +3373,14 @@ 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(render, drawable->surfaces_dest[x],
                                       &drawable->depend_items[x], drawable);
 
             if (drawable->surfaces_dest[x] == 0) {
                 QRegion depend_region;
                 region_init(&depend_region);
                 region_add(&depend_region, &drawable->red_drawable->surfaces_rects[x]);
-                red_detach_streams_behind(worker, &depend_region);
+                red_detach_streams_behind(render->worker, &depend_region);
             }
         }
     }
@@ -3346,7 +3388,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(RedRender *render, Drawable *drawable)
 {
     int x;
     int surface_id;
@@ -3357,21 +3399,22 @@ static inline void red_inc_surfaces_drawable_dependencies(RedWorker *worker, Dra
         if (surface_id == -1) {
             continue;
         }
-        surface = &worker->surfaces[surface_id];
+        surface = &render->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(RedRender *render, RedDrawable *drawable,
+                                                 uint32_t group_id)
 {
     int surface_id;
-    Drawable *item = get_drawable(worker, drawable->effect, drawable, group_id);
+    Drawable *item = get_drawable(render, drawable->effect, drawable, group_id);
 
     ASSERT(item);
 
     surface_id = item->surface_id;
 
-    worker->surfaces[surface_id].refs++;
+    render->surfaces[surface_id].refs++;
 
     region_add(&item->tree_item.base.rgn, &drawable->bbox);
 #ifdef PIPE_DEBUG
@@ -3396,42 +3439,48 @@ 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(render, item);
 
     if (region_is_empty(&item->tree_item.base.rgn)) {
-        release_drawable(worker, item);
+        release_drawable(render, item);
         return;
     }
 
-    if (!red_handle_self_bitmap(worker, item)) {
-        release_drawable(worker, item);
+    if (!red_handle_self_bitmap(render, item)) {
+        release_drawable(render, item);
         return;
     }
 
-    if (!red_handle_depends_on_target_surface(worker, surface_id)) {
-        release_drawable(worker, item);
+    if (!red_handle_depends_on_target_surface(render, surface_id)) {
+        release_drawable(render, item);
         return;
     }
 
-    if (!red_handle_surfaces_dependencies(worker, item)) {
-        release_drawable(worker, item);
+    if (!red_handle_surfaces_dependencies(render, item)) {
+        release_drawable(render, item);
         return;
     }
 
-    if (red_current_add_qxl(worker, &worker->surfaces[surface_id].current, item,
+    if (red_current_add_qxl(render,
+                            &render->surfaces[surface_id].current, item,
                             drawable)) {
         if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
-            worker->transparent_count++;
+            render->transparent_count++;
         }
-        red_pipe_add_drawable(worker, item);
+        red_pipe_add_drawable(render->worker, item);
 #ifdef DRAW_ALL
-        red_draw_qxl_drawable(worker, item);
+        red_draw_qxl_drawable(render, item);
 #endif
     }
-    release_drawable(worker, item);
+    release_drawable(render, item);
+}
+
+static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable, uint32_t group_id)
+{
+    red_process_drawable_surfaces(&worker->render, drawable, group_id);
 }
 
-static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
+static inline void red_create_surface(RedRender *render, uint32_t surface_id, uint32_t width,
                                       uint32_t height, int32_t stride, uint32_t format,
                                       void *line_0, int data_is_valid);
 
@@ -3440,11 +3489,12 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
     int surface_id;
     RedSurface *red_surface;
     uint8_t *data;
+    RedRender *render = &worker->render;
 
     surface_id = surface->surface_id;
-    __validate_surface(worker, surface_id);
+    __validate_surface(render, surface_id);
 
-    red_surface = &worker->surfaces[surface_id];
+    red_surface = &render->surfaces[surface_id];
 
     switch (surface->type) {
     case QXL_SURFACE_CMD_CREATE: {
@@ -3455,22 +3505,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(render, 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->render, 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(render, surface_id, 0, surface->release_info, group_id);
+        red_handle_depends_on_target_surface(render, 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(render, surface_id);
         red_clear_surface_drawables_from_pipe(worker, surface_id, FALSE);
-        red_destroy_surface(worker, surface_id);
+        red_destroy_surface(render, surface_id);
         break;
     default:
             red_error("unknown surface command");
@@ -3479,24 +3529,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;
+    RedRender *render;
 
-    worker = SPICE_CONTAINEROF(surfaces, RedWorker, image_surfaces);
-    validate_surface(worker, surface_id);
+    render = SPICE_CONTAINEROF(image_surfaces, RedRender, image_surfaces);
+    validate_surface(render, surface_id);
 
-    return worker->surfaces[surface_id].context.canvas;
+    return render->surfaces[surface_id].context.canvas;
 }
 
-static void image_surface_init(RedWorker *worker)
+static void image_surface_init(RedRender *render)
 {
     static SpiceImageSurfacesOps image_surfaces_ops = {
         image_surfaces_get,
     };
 
-    worker->image_surfaces.ops = &image_surfaces_ops;
+    render->image_surfaces.ops = &image_surfaces_ops;
 }
 
 static ImageCacheItem *image_cache_find(ImageCache *cache, uint64_t id)
@@ -3689,13 +3739,14 @@ 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(RedRender *render, Drawable *drawable)
 {
+    RedWorker *worker = render->worker;
     RedSurface *surface;
     SpiceCanvas *canvas;
     SpiceClip clip = drawable->red_drawable->clip;
 
-    surface = &worker->surfaces[drawable->surface_id];
+    surface = &render->surfaces[drawable->surface_id];
     canvas = surface->context.canvas;
 
     image_cache_eaging(&worker->image_cache);
@@ -3820,7 +3871,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(RedRender *render, Drawable *drawable)
 {
 #ifdef UPDATE_AREA_BY_TREE
     SpiceCanvas *canvas;
@@ -3830,8 +3881,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(render, drawable);
+    red_draw_qxl_drawable(render, drawable);
 #ifdef UPDATE_AREA_BY_TREE
     canvas->ops->group_end(canvas);
 #endif
@@ -3841,7 +3892,7 @@ static void validate_area(RedWorker *worker, const SpiceRect *area, uint32_t sur
 {
     RedSurface *surface;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &worker->render.surfaces[surface_id];
     if (!surface->context.canvas_draws_on_surface) {
         SpiceCanvas *canvas = surface->context.canvas;
         int h;
@@ -3908,7 +3959,7 @@ 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_render_update_area(RedRender *render, const SpiceRect *area, int surface_id)
 {
     RedSurface *surface;
     Ring *ring;
@@ -3916,7 +3967,7 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
     Ring items;
     QRegion rgn;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &render->surfaces[surface_id];
     ring = &surface->current;
 
     if (!(ring_item = ring_get_head(ring))) {
@@ -3939,7 +3990,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(render, container);
     }
     validate_area(worker, area, surface_id);
 }
@@ -3950,12 +4001,13 @@ 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(RedRender *render, const SpiceRect *area, int surface_id,
                                  Drawable *last)
 {
     // TODO: if we use UPDATE_AREA_BY_TREE, a corresponding red_update_area_till
     // should be implemented
 
+    RedWorker *worker = render->worker;
     RedSurface *surface;
     Drawable *surface_last = NULL;
     Ring *ring;
@@ -3966,11 +4018,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 = &render->surfaces[surface_id];
 
     if (surface_id != last->surface_id) {
         // find the nearest older drawable from the appropriate surface
-        ring = &worker->current_list;
+        ring = &render->current_list;
         ring_item = &last->list_link;
         while ((ring_item = ring_next(ring, ring_item))) {
             now = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
@@ -4018,21 +4070,22 @@ 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(render, now);
+        container_cleanup(render, 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(render, now);
+        release_drawable(render, 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_render_update_area(RedRender *render, const SpiceRect *area, int surface_id)
 {
+    RedWorker *worker = render->worker;
     RedSurface *surface;
     Ring *ring;
     RingItem *ring_item;
@@ -4043,7 +4096,7 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
     int gn;
 #endif
 
-    surface = &worker->surfaces[surface_id];
+    surface = &render->surfaces[surface_id];
 
     last = NULL;
 #ifdef ACYCLIC_SURFACE_DEBUG
@@ -4075,10 +4128,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(render, now);
+        container_cleanup(render, container);
+        red_draw_drawable(render, now);
+        release_drawable(render, now);
 #ifdef ACYCLIC_SURFACE_DEBUG
         if (gn != surface->current_gn) {
             red_error("cyclic surface dependencies");
@@ -4090,6 +4143,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_render_update_area(&worker->render, area, surface_id);
+}
+
 #endif
 
 static inline void free_cursor_item(RedWorker *worker, CursorItem *item);
@@ -4298,7 +4356,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->render, 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;
@@ -4357,8 +4415,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->render.current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
+        free_one_drawable(&worker->render, TRUE);
     }
 
     if (worker->display_channel && worker->display_channel->glz_dict) {
@@ -4366,12 +4424,12 @@ static void red_free_some(RedWorker *worker)
     }
 }
 
-static void red_current_flush(RedWorker *worker, int surface_id)
+static void red_current_flush(RedRender *render, int surface_id)
 {
-    while (!ring_is_empty(&worker->surfaces[surface_id].current_list)) {
-        free_one_drawable(worker, FALSE);
+    while (!ring_is_empty(&render->surfaces[surface_id].current_list)) {
+        free_one_drawable(render, FALSE);
     }
-    red_current_clear(worker, surface_id);
+    red_current_clear(render, surface_id);
 }
 
 // adding the pipe item after pos. If pos == NULL, adding to head.
@@ -4382,7 +4440,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->render.surfaces[surface_id];
     SpiceCanvas *canvas = surface->context.canvas;
     int bpp;
     int all_set;
@@ -4416,7 +4474,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) {
@@ -4442,7 +4500,7 @@ static void red_add_surface_image(RedWorker *worker, int surface_id)
     SpiceRect area;
     RedSurface *surface;
 
-    surface = &worker->surfaces[surface_id];
+    surface = &worker->render.surfaces[surface_id];
 
     if (!display_is_connected(worker) || !surface->context.canvas) {
         return;
@@ -5822,9 +5880,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->render, surface_id);
 
-        surface = &worker->surfaces[surface_id];
+        surface = &worker->render.surfaces[surface_id];
         image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
         image.descriptor.flags = 0;
         image.descriptor.width = surface->context.width;
@@ -5986,8 +6044,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->render, surface_id);
+    surface = &display_channel->common.worker->render.surfaces[surface_id];
     surface_lossy_region = &display_channel->surface_client_lossy_region[surface_id];
 
     if (!area) {
@@ -6307,7 +6365,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->render, deps_areas[i],
+                                 deps_surfaces_ids[i], item);
         }
     }
 
@@ -7511,6 +7570,7 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
     Stream *stream = drawable->stream;
     SpiceImage *image;
     RedWorker* worker;
+    RedRender *render;
     uint8_t *frame;
     size_t frame_stride;
     int n;
@@ -7519,13 +7579,14 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
     ASSERT(drawable->red_drawable->type == QXL_DRAW_COPY);
 
     worker = display_channel->common.worker;
+    render = &worker->render;
     image = drawable->red_drawable->u.copy.src_bitmap;
 
     if (image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) {
         return FALSE;
     }
 
-    StreamAgent *agent = &display_channel->stream_agents[stream - worker->streams_buf];
+    StreamAgent *agent = &display_channel->stream_agents[stream - render->streams_buf];
     uint64_t time_now = red_now();
     if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) {
         agent->frames--;
@@ -7539,21 +7600,21 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
     case SPICE_BITMAP_FMT_32BIT:
         if (!red_rgb32bpp_to_24(worker, &drawable->red_drawable->u.copy.src_area,
                                 &image->u.bitmap, frame, frame_stride,
-                                stream - worker->streams_buf, stream)) {
+                                stream - render->streams_buf, stream)) {
             return FALSE;
         }
         break;
     case SPICE_BITMAP_FMT_16BIT:
         if (!red_rgb16bpp_to_24(worker, &drawable->red_drawable->u.copy.src_area,
                                 &image->u.bitmap, frame, frame_stride,
-                                stream - worker->streams_buf, stream)) {
+                                stream - render->streams_buf, stream)) {
             return FALSE;
         }
         break;
     case SPICE_BITMAP_FMT_24BIT:
         if (!red_rgb24bpp_to_24(worker, &drawable->red_drawable->u.copy.src_area,
                                 &image->u.bitmap, frame, frame_stride,
-                                stream - worker->streams_buf, stream)) {
+                                stream - render->streams_buf, stream)) {
             return FALSE;
         }
         break;
@@ -7582,7 +7643,7 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
 
     SpiceMsgDisplayStreamData stream_data;
 
-    stream_data.id = stream - worker->streams_buf;
+    stream_data.id = stream - render->streams_buf;
     stream_data.multi_media_time = drawable->red_drawable->mm_time;
     stream_data.data_size = n;
     spice_marshall_msg_display_stream_data(base_marshaller, &stream_data);
@@ -8082,7 +8143,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->render, drawable);
         break;
     }
     case PIPE_ITEM_TYPE_INVAL_ONE:
@@ -8109,7 +8170,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->render, (UpgradeItem *)pipe_item);
         break;
     case PIPE_ITEM_TYPE_VERB:
         red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
@@ -8278,8 +8339,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->render.surfaces[x].context.canvas) {
+            current_tree_for_each(worker, &worker->render.surfaces[x].current, __show_tree_call,
                                   &show_tree_data);
         }
     }
@@ -8292,6 +8353,13 @@ static void red_disconnect_channel(RedChannel *channel)
     red_unref_channel(channel);
 }
 
+static void init_render(RedRender *render, RedWorker *worker)
+{
+    ring_init(&render->current_list);
+    image_surface_init(render);
+    render->worker = worker;
+}
+
 static void red_disconnect_display(RedChannelClient *rcc)
 {
     // TODO: MC: right now we assume single channel
@@ -8401,10 +8469,11 @@ 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(RedRender *render, RedSurface *surface,
                                               uint32_t renderer, uint32_t width, uint32_t height,
                                               int32_t stride, uint32_t format, void *line_0)
 {
+    RedWorker *worker = render->worker;
     SpiceCanvas *canvas;
 
     switch (renderer) {
@@ -8412,7 +8481,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);
+                                        &render->image_surfaces, NULL, NULL, NULL);
         surface->context.top_down = TRUE;
         surface->context.canvas_draws_on_surface = TRUE;
         return canvas;
@@ -8463,7 +8532,7 @@ static inline void __red_create_surface_item(RedWorker *worker, int surface_id,
         return;
     }
 
-    surface = &worker->surfaces[surface_id];
+    surface = &worker->render.surfaces[surface_id];
 
     create = get_surface_create_item(&worker->display_channel->common.base,
             surface_id, surface->context.width, surface->context.height,
@@ -8476,19 +8545,21 @@ 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(RedRender *render, uint32_t surface_id, uint32_t width,
                                       uint32_t height, int32_t stride, uint32_t format,
                                       void *line_0, int data_is_valid)
 {
+    RedWorker *worker = render->worker;
+    RedSurface *surface = &render->surfaces[surface_id];
     uint32_t i;
-    RedSurface *surface = &worker->surfaces[surface_id];
+
     if (stride >= 0) {
         PANIC("Untested path stride >= 0");
     }
@@ -8511,7 +8582,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(render,
+                                                            surface, worker->renderer,
                                                             width, height, stride,
                                                             surface->context.format, line_0);
         if (!surface->context.canvas) {
@@ -8523,7 +8595,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(render,
+                                                            surface, worker->renderers[i],
                                                             width, height, stride,
                                                             surface->context.format, line_0);
         if (surface->context.canvas) { //no need canvas check
@@ -8688,8 +8761,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->render.surfaces[0].context.canvas) {
+        red_current_flush(&worker->render, 0);
         push_new_primary_surface(worker);
         red_add_surface_image(worker, 0);
         if (red_channel_is_connected(&display_channel->common.base)) {
@@ -8893,7 +8966,8 @@ static int display_channel_init_cache(DisplayChannel *channel, SpiceMsgcDisplayI
                                                            init_info->pixmap_cache_size));
 }
 
-static int display_channel_init_glz_dictionary(DisplayChannel *channel, SpiceMsgcDisplayInit *init_info)
+static int display_channel_init_glz_dictionary(DisplayChannel *channel,
+                                               SpiceMsgcDisplayInit *init_info)
 {
     ASSERT(!channel->glz_dict);
     ring_init(&channel->glz_drawables);
@@ -8952,7 +9026,8 @@ static uint64_t display_channel_handle_migrate_data_get_serial(
     return migrate_data->message_serial;
 }
 
-static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
+static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size,
+                                                    void *message)
 {
     DisplayChannelMigrateData *migrate_data;
     int i;
@@ -9003,7 +9078,8 @@ static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint3
     return TRUE;
 }
 
-static int display_channel_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
+static int display_channel_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type,
+                                          void *message)
 {
     switch (type) {
     case SPICE_MSGC_DISPLAY_INIT:
@@ -9177,18 +9253,19 @@ 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->render, 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->render, (UpgradeItem *)item);
         break;
     case PIPE_ITEM_TYPE_IMAGE:
         release_image_item((ImageItem *)item);
@@ -9363,7 +9440,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->render.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);
     }
 }
@@ -9571,10 +9648,10 @@ static inline void handle_dev_update(RedWorker *worker)
 
     ASSERT(worker->running);
 
-    validate_surface(worker, surface_id);
+    validate_surface(&worker->render, surface_id);
     red_update_area(worker, rect, surface_id);
 
-    surface = &worker->surfaces[surface_id];
+    surface = &worker->render.surfaces[surface_id];
     region_ret_rects(&surface->draw_dirty_region, dirty_rects, num_dirty_rects);
 
     if (clear_dirty_region) {
@@ -9612,17 +9689,18 @@ 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(RedRender *render, int surface_id)
 {
-    if (!worker->surfaces[surface_id].context.canvas) {
+    RedWorker *worker = render->worker;
+
+    if (!render->surfaces[surface_id].context.canvas) {
         return;
     }
-
-    red_handle_depends_on_target_surface(worker, surface_id);
+    red_handle_depends_on_target_surface(render, 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(render, 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.
@@ -9643,8 +9721,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->render.surfaces[0].context.canvas) {
+        destroy_surface_wait(&worker->render, 0);
     }
 
     message = RED_WORKER_MESSAGE_READY;
@@ -9654,21 +9732,23 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
 /* called upon device reset */
 static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 {
+    RedRender *render = &worker->render;
     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 (render->surfaces[i].context.canvas) {
+            destroy_surface_wait(render, i);
+            if (render->surfaces[i].context.canvas) {
+                red_destroy_surface(render, i);
             }
-            ASSERT(!worker->surfaces[i].context.canvas);
+            ASSERT(!render->surfaces[i].context.canvas);
         }
     }
-    ASSERT(ring_is_empty(&worker->streams));
+    ASSERT(ring_is_empty(&render->streams));
 
     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
     if (worker->cursor_channel) {
@@ -9715,7 +9795,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->render, 0, surface.width,
+                       surface.height, surface.stride, surface.format,
                        line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA);
 
     if (display_is_connected(worker)) {
@@ -9737,11 +9818,12 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
 {
     RedWorkerMessage message;
     uint32_t surface_id;
+    RedRender *render = &worker->render;
 
     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->render.surfaces[surface_id].context.canvas);
 
     if (worker->cursor) {
         red_release_cursor(worker, worker->cursor);
@@ -9758,11 +9840,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);
-    ASSERT(ring_is_empty(&worker->streams));
+    destroy_surface_wait(render, 0);
+    red_destroy_surface(render, 0);
+    ASSERT(ring_is_empty(&render->streams));
 
-    ASSERT(!worker->surfaces[surface_id].context.canvas);
+    ASSERT(!worker->render.surfaces[surface_id].context.canvas);
 
     worker->cursor_visible = TRUE;
     worker->cursor_position.x = worker->cursor_position.y = 0;
@@ -9796,7 +9878,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->render.current_size,
                        worker->display_channel ?
                        display_red_channel->rcc->pipe_size : 0);
             red_free_some(worker);
@@ -9878,8 +9960,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->render.surfaces[x].context.canvas) {
+                red_current_flush(&worker->render, x);
             }
         }
         red_cursor_flush(worker);
@@ -10070,12 +10152,11 @@ 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_render(&worker->render, worker);
     image_cache_init(&worker->image_cache);
-    image_surface_init(worker);
     drawables_init(worker);
     cursor_items_init(worker);
-    red_init_streams(worker);
+    red_init_streams(&worker->render);
     stat_init(&worker->add_stat, add_stat_name);
     stat_init(&worker->exclude_stat, exclude_stat_name);
     stat_init(&worker->__exclude_stat, __exclude_stat_name);
@@ -10106,7 +10187,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->render.n_surfaces = init_data->n_surfaces;
 
     message = RED_WORKER_MESSAGE_READY;
     write_message(worker->channel, &message);
@@ -10138,9 +10219,9 @@ void *red_worker_main(void *arg)
         struct epoll_event *event;
         struct epoll_event *end;
 
-        worker.epoll_timeout = MIN(red_get_streams_timout(&worker), worker.epoll_timeout);
+        worker.epoll_timeout = MIN(red_get_streams_timout(&worker.render), worker.epoll_timeout);
         num_events = epoll_wait(worker.epoll, events, MAX_EPOLL_SOURCES, worker.epoll_timeout);
-        red_handle_streams_timout(&worker);
+        red_handle_streams_timout(&worker.render);
 
         if (worker.display_channel && worker.display_channel->glz_dict) {
             /* during migration, in the dest, the display channel can be initialized
-- 
1.7.5.1



More information about the Spice-devel mailing list