[Spice-devel] [PATCH 07/16] worker: move stream to display channel

Jonathon Jongsma jjongsma at redhat.com
Tue Nov 10 08:12:35 PST 2015


Still has the same logic issue mentioned in the previous review and a
couple of comments that refer to the old function name. comments
inline.


On Tue, 2015-11-10 at 14:16 +0000, Frediano Ziglio wrote:
> From: Marc-André Lureau <marcandre.lureau at gmail.com>
> 
> ---
>  server/display-channel.c |  44 ++++
>  server/display-channel.h |  22 +-
>  server/red_worker.c      | 557 +++++++++++++++++++++----------------
> ----------
>  server/stream.c          |   4 +-
>  4 files changed, 315 insertions(+), 312 deletions(-)
> 
> diff --git a/server/display-channel.c b/server/display-channel.c
> index 6aefe09..8775496 100644
> --- a/server/display-channel.c
> +++ b/server/display-channel.c
> @@ -225,3 +225,47 @@ void
> dcc_push_monitors_config(DisplayChannelClient *dcc)
>      red_monitors_config_item_add(dcc);
>      red_channel_client_push(&dcc->common.base);
>  }
> +
> +int display_channel_get_streams_timeout(DisplayChannel *display)
> +{
> +    int timeout = INT_MAX;
> +    Ring *ring = &display->streams;
> +    RingItem *item = ring;
> +
> +    red_time_t now = red_get_monotonic_time();
> +    while ((item = ring_next(ring, item))) {
> +        Stream *stream;
> +
> +        stream = SPICE_CONTAINEROF(item, Stream, link);
> +        red_time_t delta = (stream->last_time + RED_STREAM_TIMEOUT) 
> - now;
> +
> +        if (delta < 1000 * 1000) {
> +            return 0;
> +        }
> +        timeout = MIN(timeout, (unsigned int)(delta / (1000 *
> 1000)));
> +    }
> +    return timeout;
> +}
> +
> +void display_channel_set_stream_video(DisplayChannel *display, int
> stream_video)
> +{
> +    spice_return_if_fail(display);
> +    spice_return_if_fail(stream_video !=
> SPICE_STREAM_VIDEO_INVALID);
> +
> +    switch (stream_video) {
> +    case SPICE_STREAM_VIDEO_ALL:
> +        spice_info("sv all");
> +        break;
> +    case SPICE_STREAM_VIDEO_FILTER:
> +        spice_info("sv filter");
> +        break;
> +    case SPICE_STREAM_VIDEO_OFF:
> +        spice_info("sv off");
> +        break;
> +    default:
> +        spice_warn_if_reached();
> +        return;
> +    }
> +
> +    display->stream_video = stream_video;
> +}
> diff --git a/server/display-channel.h b/server/display-channel.h
> index 7173c6e..24fb354 100644
> --- a/server/display-channel.h
> +++ b/server/display-channel.h
> @@ -57,9 +57,6 @@
>  #include "stream.h"
>  
>  typedef struct DisplayChannel DisplayChannel;
> -typedef struct DisplayChannelClient DisplayChannelClient;
> -
> -typedef struct Drawable Drawable;
>  
>  #define PALETTE_CACHE_HASH_SHIFT 8
>  #define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT)
> @@ -270,6 +267,10 @@ MonitorsConfig*            monitors_config_new  
>                      (QXLHead *h
>  MonitorsConfig *           monitors_config_ref                      
>  (MonitorsConfig *config);
>  void                       monitors_config_unref                    
>  (MonitorsConfig *config);
>  
> +#define TRACE_ITEMS_SHIFT 3
> +#define NUM_TRACE_ITEMS (1 << TRACE_ITEMS_SHIFT)
> +#define ITEMS_TRACE_MASK (NUM_TRACE_ITEMS - 1)
> +
>  struct DisplayChannel {
>      CommonChannel common; // Must be the first thing
>  
> @@ -286,6 +287,15 @@ struct DisplayChannel {
>  
>      RedCompressBuf *free_compress_bufs;
>  
> +    int stream_video;
> +    uint32_t stream_count;
> +    Stream streams_buf[NUM_STREAMS];
> +    Stream *free_streams;
> +    Ring streams;
> +    ItemTrace items_trace[NUM_TRACE_ITEMS];
> +    uint32_t next_item_trace;
> +    uint64_t streams_size_total;
> +
>      ImageCache image_cache;
>  
>  #ifdef RED_STATISTICS
> @@ -304,6 +314,12 @@ struct DisplayChannel {
>  #endif
>  };
>  
> +void                       display_channel_set_stream_video         
>  (DisplayChannel *display,
> +                                                                    
>   int stream_video);
> +void                       display_channel_attach_stream            
>  (DisplayChannel *display,
> +                                                                    
>   Drawable *drawable,
> +                                                                    
>   Stream *stream);
> +int                        display_channel_get_streams_timeout      
>  (DisplayChannel *display);
>  void                       display_channel_compress_stats_print     
>  (const DisplayChannel *display);
>  void                       display_channel_compress_stats_reset     
>  (DisplayChannel *display);
>  
> diff --git a/server/red_worker.c b/server/red_worker.c
> index 1284e44..9e544c2 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -349,10 +349,6 @@ typedef struct RedSurface {
>      QXLReleaseInfoExt create, destroy;
>  } RedSurface;
>  
> -#define TRACE_ITEMS_SHIFT 3
> -#define NUM_TRACE_ITEMS (1 << TRACE_ITEMS_SHIFT)
> -#define ITEMS_TRACE_MASK (NUM_TRACE_ITEMS - 1)
> -
>  #define NUM_DRAWABLES 1000
>  
>  typedef struct RedWorker {
> @@ -380,9 +376,6 @@ typedef struct RedWorker {
>      uint32_t drawable_count;
>      uint32_t red_drawable_count;
>      uint32_t glz_drawable_count;
> -
> -    uint32_t stream_count;
> -
>      uint32_t bits_unique;
>  
>      _Drawable drawables[NUM_DRAWABLES];
> @@ -394,14 +387,6 @@ typedef struct RedWorker {
>      spice_wan_compression_t jpeg_state;
>      spice_wan_compression_t zlib_glz_state;
>  
> -    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;
> -    uint64_t streams_size_total;
> -
>      QuicData quic_data;
>      QuicContext *quic;
>  
> @@ -470,16 +455,13 @@ static void red_update_area(RedWorker *worker,
> const SpiceRect *area, int surfac
>  static void red_update_area_till(RedWorker *worker, const SpiceRect
> *area, int surface_id,
>                                   Drawable *last);
>  static void red_worker_drawable_unref(RedWorker *worker, Drawable
> *drawable);
> -static void red_display_release_stream(RedWorker *worker,
> StreamAgent *agent);
> -static inline void red_detach_stream(RedWorker *worker, Stream
> *stream, int detach_sized);
> -static void red_stop_stream(RedWorker *worker, Stream *stream);
> -static inline void red_stream_maintenance(RedWorker *worker,
> Drawable *candidate, Drawable *sect);
> +static void detach_stream(DisplayChannel *display, Stream *stream,
> int detach_sized);
> +static inline void display_channel_stream_maintenance(DisplayChannel
> *display, Drawable *candidate, Drawable *sect);
>  static inline void display_begin_send_message(RedChannelClient
> *rcc);
>  static void red_release_glz(DisplayChannelClient *dcc);
>  static void red_freeze_glz(DisplayChannelClient *dcc);
>  static void display_channel_push_release(DisplayChannelClient *dcc,
> uint8_t type, uint64_t id,
>                                           uint64_t* sync_data);
> -static void red_display_release_stream_clip(RedWorker *worker,
> StreamClipItem *item);
>  static int
> red_display_free_some_independent_glz_drawables(DisplayChannelClient
> *dcc);
>  static void red_display_free_glz_drawable(DisplayChannelClient *dcc,
> RedGlzDrawable *drawable);
>  static ImageItem *red_add_surface_area_image(DisplayChannelClient
> *dcc, int surface_id,
> @@ -516,39 +498,40 @@ static void
> display_channel_client_release_item_after_push(DisplayChannelClient
>      SAFE_FOREACH(link, next, drawable, &(drawable)->glz_ring, glz,
> LINK_TO_GLZ(link))
>  
>  
> -static inline int get_stream_id(RedWorker *worker, Stream *stream)
> +static int get_stream_id(DisplayChannel *display, Stream *stream)
>  {
> -    return (int)(stream - worker->streams_buf);
> +    return (int)(stream - display->streams_buf);
>  }
>  
> -static inline void red_free_stream(RedWorker *worker, Stream
> *stream)
> +static void display_stream_free(DisplayChannel *display, Stream
> *stream)
>  {
> -    stream->next = worker->free_streams;
> -    worker->free_streams = stream;
> +    stream->next = display->free_streams;
> +    display->free_streams = stream;
>  }
>  
> -static void red_release_stream(RedWorker *worker, Stream *stream)
> +static void display_stream_unref(DisplayChannel *display, Stream
> *stream)
>  {
> -    if (!--stream->refs) {
> -        spice_assert(!ring_item_is_linked(&stream->link));
> -        red_free_stream(worker, stream);
> -        worker->stream_count--;
> -    }
> +    if (--stream->refs != 0)
> +        return;
> +
> +    spice_warn_if_fail(!ring_item_is_linked(&stream->link));
> +    display_stream_free(display, stream);
> +    display->stream_count--;
>  }
>  
> -static void red_display_release_stream(RedWorker *worker,
> StreamAgent *agent)
> +static void display_stream_agent_unref(DisplayChannel *display,
> StreamAgent *agent)
>  {
> -    spice_assert(agent->stream);
> -    red_release_stream(worker, agent->stream);
> +    display_stream_unref(display, agent->stream);
>  }
>  
> -static void red_display_release_stream_clip(RedWorker *worker,
> StreamClipItem *item)
> +static void display_stream_clip_unref(DisplayChannel *display,
> StreamClipItem *item)
>  {
> -    if (!--item->refs) {
> -        red_display_release_stream(worker, item->stream_agent);
> -        free(item->rects);
> -        free(item);
> -    }
> +    if (--item->refs != 0)
> +        return;
> +
> +    display_stream_agent_unref(display, item->stream_agent);
> +    free(item->rects);
> +    free(item);
>  }
>  
>  static void dcc_push_stream_agent_clip(DisplayChannelClient* dcc,
> StreamAgent *agent)
> @@ -556,21 +539,18 @@ static void
> dcc_push_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *a
>      StreamClipItem *item = stream_clip_item_new(dcc, agent);
>      int n_rects;
>  
> -    if (!item) {
> -        spice_critical("alloc failed");
> -    }
>      item->clip_type = SPICE_CLIP_TYPE_RECTS;
>  
>      n_rects = pixman_region32_n_rects(&agent->clip);
> -
>      item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect),
> sizeof(SpiceClipRects));
>      item->rects->num_rects = n_rects;
>      region_ret_rects(&agent->clip, item->rects->rects, n_rects);
> +
>      red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), (PipeItem
> *)item);
>  }
>  
>  
> -static void red_attach_stream(RedWorker *worker, Drawable *drawable,
> Stream *stream)
> +void attach_stream(DisplayChannel *display, Drawable *drawable,
> Stream *stream)
>  {
>      DisplayChannelClient *dcc;
>      RingItem *item, *next;
> @@ -592,11 +572,11 @@ static void red_attach_stream(RedWorker
> *worker, Drawable *drawable, Stream *str
>          stream->num_input_frames++;
>      }
>  
> -    FOREACH_DCC(worker->display_channel, item, next, dcc) {
> +    FOREACH_DCC(display, item, next, dcc) {
>          StreamAgent *agent;
>          QRegion clip_in_draw_dest;
>  
> -        agent = &dcc->stream_agents[get_stream_id(worker, stream)];
> +        agent = &dcc->stream_agents[get_stream_id(display, stream)];
>          region_or(&agent->vis_region, &drawable
> ->tree_item.base.rgn);
>  
>          region_init(&clip_in_draw_dest);
> @@ -614,18 +594,18 @@ static void red_attach_stream(RedWorker
> *worker, Drawable *drawable, Stream *str
>      }
>  }
>  
> -static void red_stop_stream(RedWorker *worker, Stream *stream)
> +static void stop_stream(DisplayChannel *display, Stream *stream)
>  {
>      DisplayChannelClient *dcc;
>      RingItem *item, *next;
>  
>      spice_assert(ring_item_is_linked(&stream->link));
>      spice_assert(!stream->current);
> -    spice_debug("stream %d", get_stream_id(worker, stream));
> -    FOREACH_DCC(worker->display_channel, item, next, dcc) {
> +    spice_debug("stream %d", get_stream_id(display, stream));
> +    FOREACH_DCC(display, item, next, dcc) {
>          StreamAgent *stream_agent;
>  
> -        stream_agent = &dcc->stream_agents[get_stream_id(worker,
> stream)];
> +        stream_agent = &dcc->stream_agents[get_stream_id(display,
> stream)];
>          region_clear(&stream_agent->vis_region);
>          region_clear(&stream_agent->clip);
>          spice_assert(!pipe_item_is_linked(&stream_agent
> ->destroy_item));
> @@ -643,9 +623,9 @@ static void red_stop_stream(RedWorker *worker,
> Stream *stream)
>          red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc),
> &stream_agent->destroy_item);
>          stream_agent_stats_print(stream_agent);
>      }
> -    worker->streams_size_total -= stream->width * stream->height;
> +    display->streams_size_total -= stream->width * stream->height;
>      ring_remove(&stream->link);
> -    red_release_stream(worker, stream);
> +    display_stream_unref(display, stream);
>  }
>  
>  /* fixme: move to display channel */
> @@ -693,7 +673,7 @@ QXLInstance* red_worker_get_qxl(RedWorker
> *worker)
>      return worker->qxl;
>  }
>  
> -static inline int is_primary_surface(RedWorker *worker, uint32_t
> surface_id)
> +static inline int is_primary_surface(DisplayChannel *display,
> uint32_t surface_id)
>  {
>      if (surface_id == 0) {
>          return TRUE;
> @@ -979,8 +959,6 @@ static void drawables_init(RedWorker *worker)
>  }
>  
>  
> -static void red_reset_stream_trace(RedWorker *worker);
> -
>  static SurfaceDestroyItem *get_surface_destroy_item(RedChannel
> *channel,
>                                                      uint32_t
> surface_id)
>  {
> @@ -1012,27 +990,28 @@ static inline void
> red_destroy_surface_item(RedWorker *worker,
>      red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy
> ->pipe_item);
>  }
>  
> -static void red_reset_stream_trace(RedWorker *worker)
> +static void stop_streams(DisplayChannel *display)
>  {
> -    Ring *ring = &worker->streams;
> +    Ring *ring = &display->streams;
>      RingItem *item = ring_get_head(ring);
>  
>      while (item) {
>          Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
>          item = ring_next(ring, item);
>          if (!stream->current) {
> -            red_stop_stream(worker, stream);
> +            stop_stream(display, stream);
>          } else {
>              spice_info("attached stream");
>          }
>      }
>  
> -    worker->next_item_trace = 0;
> -    memset(worker->items_trace, 0, sizeof(worker->items_trace));
> +    display->next_item_trace = 0;
> +    memset(display->items_trace, 0, sizeof(display->items_trace));
>  }
>  
>  static void red_surface_unref(RedWorker *worker, uint32_t
> surface_id)
>  {
> +    DisplayChannel *display = worker->display_channel;
>      RedSurface *surface = &worker->surfaces[surface_id];
>      DisplayChannelClient *dcc;
>      RingItem *link, *next;
> @@ -1042,8 +1021,8 @@ static void red_surface_unref(RedWorker
> *worker, uint32_t surface_id)
>      }
>  
>      // only primary surface streams are supported
> -    if (is_primary_surface(worker, surface_id)) {
> -        red_reset_stream_trace(worker);
> +    if (is_primary_surface(worker->display_channel, surface_id)) {
> +        stop_streams(display);
>      }
>      spice_assert(surface->context.canvas);
>  
> @@ -1140,7 +1119,7 @@ static void red_worker_drawable_unref(RedWorker
> *worker, Drawable *drawable)
>      spice_warn_if_fail(ring_is_empty(&drawable->pipes));
>  
>      if (drawable->stream) {
> -        red_detach_stream(worker, drawable->stream, TRUE);
> +        detach_stream(worker->display_channel, drawable->stream,
> TRUE);
>      }
>      region_destroy(&drawable->tree_item.base.rgn);
>  
> @@ -1196,14 +1175,15 @@ static inline void
> container_cleanup(RedWorker *worker, Container *container)
>      }
>  }
>  
> -static inline void red_add_item_trace(RedWorker *worker, Drawable
> *item)
> +static void display_stream_trace_add_drawable(DisplayChannel
> *display, Drawable *item)
>  {
>      ItemTrace *trace;
> -    if (!item->streamable) {
> +
> +    if (!item->stream || !item->streamable) {
>          return;
>      }

Here we change so that we're *NOT* calling this function when !item
->stream


>  
> -    trace = &worker->items_trace[worker->next_item_trace++ &
> ITEMS_TRACE_MASK];
> +    trace = &display->items_trace[display->next_item_trace++ &
> ITEMS_TRACE_MASK];
>      trace->time = item->creation_time;
>      trace->frames_count = item->frames_count;
>      trace->gradual_frames_count = item->gradual_frames_count;
> @@ -1235,9 +1215,7 @@ static void red_flush_source_surfaces(RedWorker
> *worker, Drawable *drawable)
>  
>  static inline void current_remove_drawable(RedWorker *worker,
> Drawable *item)
>  {
> -    if (!item->stream) {
> -        red_add_item_trace(worker, item);
> -    }
> +    display_stream_trace_add_drawable(worker->display_channel,
> item);


Here we previously *WERE* calling that function when !item->stream


>      remove_shadow(&item->tree_item);
>      ring_remove(&item->tree_item.base.siblings_link);
>      ring_remove(&item->list_link);
> @@ -1465,7 +1443,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);
> +                    display_channel_stream_maintenance(worker
> ->display_channel, frame_candidate, drawable);
>                  }
>                  region_exclude(&draw->base.rgn, &and_rgn);
>              }
> @@ -1655,7 +1633,8 @@ static int is_same_drawable(RedWorker *worker,
> Drawable *d1, Drawable *d2)
>      }
>  }
>  
> -static inline void red_detach_stream(RedWorker *worker, Stream
> *stream, int detach_sized)
> +static void detach_stream(DisplayChannel *display, Stream *stream,
> +                          int detach_sized)
>  {
>      spice_assert(stream->current && stream->current->stream);
>      spice_assert(stream->current->stream == stream);
> @@ -1681,14 +1660,15 @@ static int
> red_display_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *
>  }
>  
>  /*
> - * after dcc_detach_stream_gracefully is called for all the display
> channel clients,
> - * red_detach_stream should be called. See comment (1).
> + * after red_display_detach_stream_gracefully is called for all the
> display channel clients,
> + * detach_stream should be called. See comment (1).


This comment reverts to using the old name
red_display_detach_stream_gracefully

>   */
> -static inline void dcc_detach_stream_gracefully(DisplayChannelClient
> *dcc,
> -                                                        Stream
> *stream,
> -                                                        Drawable
> *update_area_limit)
> +static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
> +                                         Stream *stream,
> +                                         Drawable
> *update_area_limit)
>  {
> -    int stream_id = get_stream_id(DCC_TO_WORKER(dcc), stream);
> +    DisplayChannel *display = DCC_TO_DC(dcc);
> +    int stream_id = get_stream_id(display, stream);
>      StreamAgent *agent = &dcc->stream_agents[stream_id];
>  
>      /* stopping the client from playing older frames at once*/
> @@ -1751,17 +1731,17 @@ clear_vis_region:
>      region_clear(&agent->vis_region);
>  }
>  
> -static inline void red_detach_stream_gracefully(RedWorker *worker,
> Stream *stream,
> -                                                Drawable
> *update_area_limit)
> +static void detach_stream_gracefully(DisplayChannel *display, Stream
> *stream,
> +                                     Drawable *update_area_limit)
>  {
>      RingItem *item, *next;
>      DisplayChannelClient *dcc;
>  
> -    FOREACH_DCC(worker->display_channel, item, next, dcc) {
> +    FOREACH_DCC(display, item, next, dcc) {
>          dcc_detach_stream_gracefully(dcc, stream,
> update_area_limit);
>      }
>      if (stream->current) {
> -        red_detach_stream(worker, stream, TRUE);
> +        detach_stream(display, stream, TRUE);
>      }
>  }
>  
> @@ -1773,57 +1753,57 @@ static inline void
> red_detach_stream_gracefully(RedWorker *worker, Stream *strea
>   *           of the "current tree", the drawable parameter should be
> set with
>   *           this drawable, otherwise, it should be NULL. Then, if
> detaching the stream
>   *           involves sending an upgrade image to the client, this
> drawable won't be rendered
> - *           (see dcc_detach_stream_gracefully).
> + *           (see red_display_detach_stream_gracefully).


Reverts to the old name again. drop this piece.


>   */
> -static void red_detach_streams_behind(RedWorker *worker, QRegion
> *region, Drawable *drawable)
> +static void detach_streams_behind(DisplayChannel *display, QRegion
> *region, Drawable *drawable)
>  {
> -    Ring *ring = &worker->streams;
> +    Ring *ring = &display->streams;
>      RingItem *item = ring_get_head(ring);
>      RingItem *dcc_ring_item, *next;
>      DisplayChannelClient *dcc;
> -    int has_clients = display_is_connected(worker);
> +    bool is_connected =
> red_channel_is_connected(RED_CHANNEL(display));
>  
>      while (item) {
>          Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> -        int detach_stream = 0;
> +        int detach = 0;
>          item = ring_next(ring, item);
>  
> -        FOREACH_DCC(worker->display_channel, dcc_ring_item, next,
> dcc) {
> -            StreamAgent *agent = &dcc
> ->stream_agents[get_stream_id(worker, stream)];
> +        FOREACH_DCC(display, dcc_ring_item, next, dcc) {
> +            StreamAgent *agent = &dcc
> ->stream_agents[get_stream_id(display, stream)];
>  
>              if (region_intersects(&agent->vis_region, region)) {
>                  dcc_detach_stream_gracefully(dcc, stream, drawable);
> -                detach_stream = 1;
> -                spice_debug("stream %d", get_stream_id(worker,
> stream));
> +                detach = 1;
> +                spice_debug("stream %d", get_stream_id(display,
> stream));
>              }
>          }
> -        if (detach_stream && stream->current) {
> -            red_detach_stream(worker, stream, TRUE);
> -        } else if (!has_clients) {
> +        if (detach && stream->current) {
> +            detach_stream(display, stream, TRUE);
> +        } else if (!is_connected) {
>              if (stream->current &&
>                  region_intersects(&stream->current
> ->tree_item.base.rgn, region)) {
> -                red_detach_stream(worker, stream, TRUE);
> +                detach_stream(display, stream, TRUE);
>              }
>          }
>      }
>  }
>  
> -static void red_streams_update_visible_region(RedWorker *worker,
> Drawable *drawable)
> +static void streams_update_visible_region(DisplayChannel *display,
> Drawable *drawable)
>  {
>      Ring *ring;
>      RingItem *item;
>      RingItem *dcc_ring_item, *next;
>      DisplayChannelClient *dcc;
>  
> -    if (!display_is_connected(worker)) {
> +    if (!red_channel_is_connected(RED_CHANNEL(display))) {
>          return;
>      }
>  
> -    if (!is_primary_surface(worker, drawable->surface_id)) {
> +    if (!is_primary_surface(display, drawable->surface_id)) {
>          return;
>      }
>  
> -    ring = &worker->streams;
> +    ring = &display->streams;
>      item = ring_get_head(ring);
>  
>      while (item) {
> @@ -1836,8 +1816,8 @@ static void
> red_streams_update_visible_region(RedWorker *worker, Drawable *drawa
>              continue;
>          }
>  
> -        FOREACH_DCC(worker->display_channel, dcc_ring_item, next,
> dcc) {
> -            agent = &dcc->stream_agents[get_stream_id(worker,
> stream)];
> +        FOREACH_DCC(display, dcc_ring_item, next, dcc) {
> +            agent = &dcc->stream_agents[get_stream_id(display,
> stream)];
>  
>              if (region_intersects(&agent->vis_region, &drawable
> ->tree_item.base.rgn)) {
>                  region_exclude(&agent->vis_region, &drawable
> ->tree_item.base.rgn);
> @@ -1848,30 +1828,9 @@ static void
> red_streams_update_visible_region(RedWorker *worker, Drawable *drawa
>      }
>  }
>  
> -static inline unsigned int red_get_streams_timout(RedWorker *worker)
> +static void display_channel_streams_timeout(DisplayChannel *display)
>  {
> -    unsigned int timout = -1;
> -    Ring *ring = &worker->streams;
> -    RingItem *item = ring;
> -
> -    red_time_t now = red_get_monotonic_time();
> -    while ((item = ring_next(ring, item))) {
> -        Stream *stream;
> -
> -        stream = SPICE_CONTAINEROF(item, Stream, link);
> -        red_time_t delta = (stream->last_time + RED_STREAM_TIMEOUT) 
> - now;
> -
> -        if (delta < 1000 * 1000) {
> -            return 0;
> -        }
> -        timout = MIN(timout, (unsigned int)(delta / (1000 * 1000)));
> -    }
> -    return timout;
> -}
> -
> -static inline void red_handle_streams_timout(RedWorker *worker)
> -{
> -    Ring *ring = &worker->streams;
> +    Ring *ring = &display->streams;
>      RingItem *item;
>  
>      red_time_t now = red_get_monotonic_time();
> @@ -1880,20 +1839,20 @@ static inline void
> red_handle_streams_timout(RedWorker *worker)
>          Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
>          item = ring_next(ring, item);
>          if (now >= (stream->last_time + RED_STREAM_TIMEOUT)) {
> -            red_detach_stream_gracefully(worker, stream, NULL);
> -            red_stop_stream(worker, stream);
> +            detach_stream_gracefully(display, stream, NULL);
> +            stop_stream(display, stream);
>          }
>      }
>  }
>  
> -static inline Stream *red_alloc_stream(RedWorker *worker)
> +static Stream *display_channel_stream_try_new(DisplayChannel
> *display)
>  {
>      Stream *stream;
> -    if (!worker->free_streams) {
> +    if (!display->free_streams) {
>          return NULL;
>      }
> -    stream = worker->free_streams;
> -    worker->free_streams = worker->free_streams->next;
> +    stream = display->free_streams;
> +    display->free_streams = display->free_streams->next;
>      return stream;
>  }
>  
> @@ -1942,7 +1901,7 @@ static uint64_t
> red_stream_get_initial_bit_rate(DisplayChannelClient *dcc,
>      /* dividing the available bandwidth among the active streams,
> and saving
>       * (1-RED_STREAM_CHANNEL_CAPACITY) of it for other messages */
>      return (RED_STREAM_CHANNEL_CAPACITY * bit_rate *
> -            stream->width * stream->height) / DCC_TO_WORKER(dcc)
> ->streams_size_total;
> +            stream->width * stream->height) / DCC_TO_DC(dcc)
> ->streams_size_total;
>  }
>  
>  static uint32_t red_stream_mjpeg_encoder_get_roundtrip(void *opaque)
> @@ -1984,7 +1943,7 @@ static void
> red_display_update_streams_max_latency(DisplayChannelClient *dcc, St
>      }
>  
>      dcc->streams_max_latency = 0;
> -    if (DCC_TO_WORKER(dcc)->stream_count == 1) {
> +    if (DCC_TO_DC(dcc)->stream_count == 1) {
>          return;
>      }
>      for (i = 0; i < NUM_STREAMS; i++) {
> @@ -2025,7 +1984,7 @@ static void
> red_stream_update_client_playback_latency(void *opaque, uint32_t del
>  
>  static void dcc_create_stream(DisplayChannelClient *dcc, Stream
> *stream)
>  {
> -    StreamAgent *agent = &dcc
> ->stream_agents[get_stream_id(DCC_TO_WORKER(dcc), stream)];
> +    StreamAgent *agent = &dcc
> ->stream_agents[get_stream_id(DCC_TO_DC(dcc), stream)];
>  
>      stream->refs++;
>      spice_assert(region_is_empty(&agent->vis_region));
> @@ -2061,7 +2020,7 @@ static void
> dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
>          agent->report_id = rand();
>          red_channel_pipe_item_init(RED_CHANNEL_CLIENT(dcc)->channel,
> &report_pipe_item->pipe_item,
>                                    
>  PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
> -        report_pipe_item->stream_id =
> get_stream_id(DCC_TO_WORKER(dcc), stream);
> +        report_pipe_item->stream_id = get_stream_id(DCC_TO_DC(dcc),
> stream);
>          red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc),
> &report_pipe_item->pipe_item);
>      }
>  #ifdef STREAM_STATS
> @@ -2072,7 +2031,7 @@ static void
> dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
>  #endif
>  }
>  
> -static void red_create_stream(RedWorker *worker, Drawable *drawable)
> +static void display_channel_create_stream(DisplayChannel *display,
> Drawable *drawable)
>  {
>      DisplayChannelClient *dcc;
>      RingItem *dcc_ring_item, *next;
> @@ -2081,14 +2040,14 @@ static void red_create_stream(RedWorker
> *worker, Drawable *drawable)
>  
>      spice_assert(!drawable->stream);
>  
> -    if (!(stream = red_alloc_stream(worker))) {
> +    if (!(stream = display_channel_stream_try_new(display))) {
>          return;
>      }
>  
>      spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY);
>      src_rect = &drawable->red_drawable->u.copy.src_area;
>  
> -    ring_add(&worker->streams, &stream->link);
> +    ring_add(&display->streams, &stream->link);
>      stream->current = drawable;
>      stream->last_time = drawable->creation_time;
>      stream->width = src_rect->right - src_rect->left;
> @@ -2101,12 +2060,13 @@ static void red_create_stream(RedWorker
> *worker, Drawable *drawable)
>      stream->input_fps = MAX_FPS;
>      stream->num_input_frames = 0;
>      stream->input_fps_start_time = drawable->creation_time;
> -    worker->streams_size_total += stream->width * stream->height;
> -    worker->stream_count++;
> -    FOREACH_DCC(worker->display_channel, dcc_ring_item, next, dcc) {
> +    display->streams_size_total += stream->width * stream->height;
> +    display->stream_count++;
> +    FOREACH_DCC(display, dcc_ring_item, next, dcc) {
>          dcc_create_stream(dcc, stream);
>      }
> -    spice_debug("stream %d %dx%d (%d, %d) (%d, %d)", (int)(stream -
> worker->streams_buf), stream->width,
> +    spice_debug("stream %d %dx%d (%d, %d) (%d, %d)",
> +                (int)(stream - display->streams_buf), stream->width,
>                  stream->height, stream->dest_area.left, stream
> ->dest_area.top,
>                  stream->dest_area.right, stream->dest_area.bottom);
>      return;
> @@ -2114,7 +2074,7 @@ static void red_create_stream(RedWorker
> *worker, Drawable *drawable)
>  
>  static void dcc_create_all_streams(DisplayChannelClient *dcc)
>  {
> -    Ring *ring = &DCC_TO_WORKER(dcc)->streams;
> +    Ring *ring = &DCC_TO_DC(dcc)->streams;
>      RingItem *item = ring;
>  
>      while ((item = ring_next(ring, item))) {
> @@ -2126,12 +2086,12 @@ static void
> dcc_create_all_streams(DisplayChannelClient *dcc)
>  static void dcc_init_stream_agents(DisplayChannelClient *dcc)
>  {
>      int i;
> -    RedWorker *worker = DCC_TO_WORKER(dcc);
> +    DisplayChannel *display = DCC_TO_DC(dcc);
>      RedChannel *channel = RED_CHANNEL_CLIENT(dcc)->channel;
>  
>      for (i = 0; i < NUM_STREAMS; i++) {
>          StreamAgent *agent = &dcc->stream_agents[i];
> -        agent->stream = &worker->streams_buf[i];
> +        agent->stream = &display->streams_buf[i];
>          region_init(&agent->vis_region);
>          region_init(&agent->clip);
>          red_channel_pipe_item_init(channel, &agent->create_item,
> PIPE_ITEM_TYPE_STREAM_CREATE);
> @@ -2156,14 +2116,14 @@ static void
> dcc_destroy_stream_agents(DisplayChannelClient *dcc)
>      }
>  }
>  
> -static inline int __red_is_next_stream_frame(RedWorker *worker,
> -                                             const Drawable
> *candidate,
> -                                             const int
> other_src_width,
> -                                             const int
> other_src_height,
> -                                             const SpiceRect
> *other_dest,
> -                                             const red_time_t
> other_time,
> -                                             const Stream *stream,
> -                                             int
> container_candidate_allowed)
> +static int is_next_stream_frame(DisplayChannel *display,
> +                                const Drawable *candidate,
> +                                const int other_src_width,
> +                                const int other_src_height,
> +                                const SpiceRect *other_dest,
> +                                const red_time_t other_time,
> +                                const Stream *stream,
> +                                int container_candidate_allowed)
>  {
>      RedDrawable *red_drawable;
>      int is_frame_container = FALSE;
> @@ -2226,22 +2186,8 @@ static inline int
> __red_is_next_stream_frame(RedWorker *worker,
>      }
>  }
>  
> -static inline int red_is_next_stream_frame(RedWorker *worker, const
> Drawable *candidate,
> -                                           const Drawable *prev)
> -{
> -    if (!candidate->streamable) {
> -        return FALSE;
> -    }
> -
> -    SpiceRect* prev_src = &prev->red_drawable->u.copy.src_area;
> -    return __red_is_next_stream_frame(worker, candidate, prev_src
> ->right - prev_src->left,
> -                                      prev_src->bottom - prev_src
> ->top,
> -                                      &prev->red_drawable->bbox,
> prev->creation_time,
> -                                      prev->stream,
> -                                      FALSE);
> -}
> -
> -static inline void pre_stream_item_swap(RedWorker *worker, Stream
> *stream, Drawable *new_frame)
> +static void before_reattach_stream(DisplayChannel *display,
> +                                   Stream *stream, Drawable
> *new_frame)
>  {
>      DrawablePipeItem *dpi;
>      DisplayChannelClient *dcc;
> @@ -2249,9 +2195,9 @@ static inline void
> pre_stream_item_swap(RedWorker *worker, Stream *stream, Drawa
>      StreamAgent *agent;
>      RingItem *ring_item, *next;
>  
> -    spice_assert(stream->current);
> +    spice_return_if_fail(stream->current);
>  
> -    if (!display_is_connected(worker)) {
> +    if (!red_channel_is_connected(RED_CHANNEL(display))) {
>          return;
>      }
>  
> @@ -2260,7 +2206,7 @@ static inline void
> pre_stream_item_swap(RedWorker *worker, Stream *stream, Drawa
>          return;
>      }
>  
> -    index = get_stream_id(worker, stream);
> +    index = get_stream_id(display, stream);
>      DRAWABLE_FOREACH_DPI_SAFE(stream->current, ring_item, next, dpi)
> {
>          dcc = dpi->dcc;
>          agent = &dcc->stream_agents[index];
> @@ -2283,7 +2229,7 @@ static inline void
> pre_stream_item_swap(RedWorker *worker, Stream *stream, Drawa
>      }
>  
>  
> -    FOREACH_DCC(worker->display_channel, ring_item, next, dcc) {
> +    FOREACH_DCC(display, ring_item, next, dcc) {
>          double drop_factor;
>  
>          agent = &dcc->stream_agents[index];
> @@ -2314,12 +2260,13 @@ static inline void
> pre_stream_item_swap(RedWorker *worker, Stream *stream, Drawa
>      }
>  }
>  
> -static inline void red_update_copy_graduality(RedWorker* worker,
> Drawable *drawable)
> +static void update_copy_graduality(Drawable *drawable)
>  {
>      SpiceBitmap *bitmap;
> -    spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY);
> +    spice_return_if_fail(drawable->red_drawable->type ==
> QXL_DRAW_COPY);
>  
> -    if (worker->streaming_video != SPICE_STREAM_VIDEO_FILTER) {
> +    /* TODO: global property -> per dc/dcc */
> +    if (streaming_video != SPICE_STREAM_VIDEO_FILTER) {
>          drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID;
>          return;
>      }
> @@ -2338,7 +2285,7 @@ static inline void
> red_update_copy_graduality(RedWorker* worker, Drawable *drawa
>      }
>  }
>  
> -static inline int red_is_stream_start(Drawable *drawable)
> +static int is_stream_start(Drawable *drawable)
>  {
>      return ((drawable->frames_count >=
> RED_STREAM_FRAMES_START_CONDITION) &&
>              (drawable->gradual_frames_count >=
> @@ -2346,13 +2293,13 @@ static inline int
> red_is_stream_start(Drawable *drawable)
>  }
>  
>  // returns whether a stream was created
> -static int red_stream_add_frame(RedWorker *worker,
> -                                Drawable *frame_drawable,
> -                                int frames_count,
> -                                int gradual_frames_count,
> -                                int last_gradual_frame)
> +static int display_channel_stream_add_frame(DisplayChannel *display,
> +                                            Drawable
> *frame_drawable,
> +                                            int frames_count,
> +                                            int
> gradual_frames_count,
> +                                            int last_gradual_frame)
>  {
> -    red_update_copy_graduality(worker, frame_drawable);
> +    update_copy_graduality(frame_drawable);
>      frame_drawable->frames_count = frames_count + 1;
>      frame_drawable->gradual_frames_count  = gradual_frames_count;
>  
> @@ -2370,45 +2317,52 @@ static int red_stream_add_frame(RedWorker
> *worker,
>          frame_drawable->last_gradual_frame = last_gradual_frame;
>      }
>  
> -    if (red_is_stream_start(frame_drawable)) {
> -        red_create_stream(worker, frame_drawable);
> +    if (is_stream_start(frame_drawable)) {
> +        display_channel_create_stream(display, frame_drawable);
>          return TRUE;
>      }
>      return FALSE;
>  }
>  
> -static inline void red_stream_maintenance(RedWorker *worker,
> Drawable *candidate, Drawable *prev)
> +static void display_channel_stream_maintenance(DisplayChannel
> *display,
> +                                               Drawable *candidate,
> Drawable *prev)
>  {
> -    Stream *stream;
> +    int is_next_frame;
>  
>      if (candidate->stream) {
>          return;
>      }
>  
> -    if ((stream = prev->stream)) {
> -        int is_next_frame = __red_is_next_stream_frame(worker,
> -                                                       candidate,
> -                                                       stream
> ->width,
> -                                                       stream
> ->height,
> -                                                       &stream
> ->dest_area,
> -                                                       stream
> ->last_time,
> -                                                       stream,
> -                                                       TRUE);
> +    if (prev->stream) {
> +        Stream *stream = prev->stream;
> +
> +        is_next_frame = is_next_stream_frame(display, candidate,
> +                                             stream->width, stream
> ->height,
> +                                             &stream->dest_area,
> stream->last_time,
> +                                             stream, TRUE);
>          if (is_next_frame != STREAM_FRAME_NONE) {
> -            pre_stream_item_swap(worker, stream, candidate);
> -            red_detach_stream(worker, stream, FALSE);
> +            before_reattach_stream(display, stream, candidate);
> +            detach_stream(display, stream, FALSE);
>              prev->streamable = FALSE; //prevent item trace
> -            red_attach_stream(worker, candidate, stream);
> +            attach_stream(display, candidate, stream);
>              if (is_next_frame == STREAM_FRAME_CONTAINER) {
>                  candidate->sized_stream = stream;
>              }
>          }
> -    } else {
> -        if (red_is_next_stream_frame(worker, candidate, prev) !=
> STREAM_FRAME_NONE) {
> -            red_stream_add_frame(worker, candidate,
> -                                 prev->frames_count,
> -                                 prev->gradual_frames_count,
> -                                 prev->last_gradual_frame);
> +    } else if (candidate->streamable) {
> +        SpiceRect* prev_src = &prev->red_drawable->u.copy.src_area;
> +
> +        is_next_frame =
> +            is_next_stream_frame(display, candidate, prev_src->right
> - prev_src->left,
> +                                 prev_src->bottom - prev_src->top,
> +                                 &prev->red_drawable->bbox, prev
> ->creation_time,
> +                                 prev->stream,
> +                                 FALSE);
> +        if (is_next_frame != STREAM_FRAME_NONE) {
> +            display_channel_stream_add_frame(display, candidate,
> +                                             prev->frames_count,
> +                                             prev
> ->gradual_frames_count,
> +                                             prev
> ->last_gradual_frame);
>          }
>      }
>  }
> @@ -2446,7 +2400,7 @@ 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);
> +        display_channel_stream_maintenance(worker->display_channel,
> drawable, other_drawable);
>          __current_add_drawable(worker, drawable, &other
> ->siblings_link);
>          other_drawable->refs++;
>          current_remove_drawable(worker, other_drawable);
> @@ -2520,56 +2474,55 @@ 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)
> +#define FOREACH_STREAMS(display, item)                  \
> +    for (item = ring_get_head(&(display)->streams);     \
> +         item != NULL;                                  \
> +         item = ring_next(&(display)->streams, item))
> +
> +static void red_use_stream_trace(DisplayChannel *display, Drawable
> *drawable)
>  {
>      ItemTrace *trace;
>      ItemTrace *trace_end;
> -    Ring *ring;
>      RingItem *item;
>  
>      if (drawable->stream || !drawable->streamable || drawable
> ->frames_count) {
>          return;
>      }
>  
> -
> -    ring = &worker->streams;
> -    item = ring_get_head(ring);
> -
> -    while (item) {
> +    FOREACH_STREAMS(display, item) {
>          Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> -        int is_next_frame = __red_is_next_stream_frame(worker,
> -                                                       drawable,
> -                                                       stream
> ->width,
> -                                                       stream
> ->height,
> -                                                       &stream
> ->dest_area,
> -                                                       stream
> ->last_time,
> -                                                       stream,
> -                                                       TRUE);
> +        int is_next_frame = is_next_stream_frame(display,
> +                                                 drawable,
> +                                                 stream->width,
> +                                                 stream->height,
> +                                                 &stream->dest_area,
> +                                                 stream->last_time,
> +                                                 stream,
> +                                                 TRUE);
>          if (is_next_frame != STREAM_FRAME_NONE) {
>              if (stream->current) {
>                  stream->current->streamable = FALSE; //prevent item
> trace
> -                pre_stream_item_swap(worker, stream, drawable);
> -                red_detach_stream(worker, stream, FALSE);
> +                before_reattach_stream(display, stream, drawable);
> +                detach_stream(display, stream, FALSE);
>              }
> -            red_attach_stream(worker, drawable, stream);
> +            attach_stream(display, drawable, stream);
>              if (is_next_frame == STREAM_FRAME_CONTAINER) {
>                  drawable->sized_stream = stream;
>              }
>              return;
>          }
> -        item = ring_next(ring, item);
>      }
>  
> -    trace = worker->items_trace;
> +    trace = display->items_trace;
>      trace_end = trace + NUM_TRACE_ITEMS;
>      for (; trace < trace_end; trace++) {
> -        if (__red_is_next_stream_frame(worker, drawable, trace
> ->width, trace->height,
> +        if (is_next_stream_frame(display, drawable, trace->width,
> trace->height,
>                                         &trace->dest_area, trace
> ->time, NULL, FALSE) !=
>                                         STREAM_FRAME_NONE) {
> -            if (red_stream_add_frame(worker, drawable,
> -                                     trace->frames_count,
> -                                     trace->gradual_frames_count,
> -                                     trace->last_gradual_frame)) {
> +            if (display_channel_stream_add_frame(display, drawable,
> +                                                 trace
> ->frames_count,
> +                                                 trace
> ->gradual_frames_count,
> +                                                 trace
> ->last_gradual_frame)) {
>                  return;
>              }
>          }
> @@ -2671,8 +2624,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);
> -        red_streams_update_visible_region(worker, drawable);
> +        red_use_stream_trace(worker->display_channel, drawable);
> +        streams_update_visible_region(worker->display_channel,
> drawable);
>          /*
>           * Performing the insertion after exclude_region for
>           * safety (todo: Not sure if exclude_region can affect the
> drawable
> @@ -2686,8 +2639,8 @@ static inline int red_current_add(RedWorker
> *worker, Ring *ring, Drawable *drawa
>           * before calling red_detach_streams_behind
>           */
>          __current_add_drawable(worker, drawable, ring);
> -        if (is_primary_surface(worker, drawable->surface_id)) {
> -            red_detach_streams_behind(worker, &drawable
> ->tree_item.base.rgn, drawable);
> +        if (is_primary_surface(worker->display_channel, drawable
> ->surface_id)) {
> +            detach_streams_behind(worker->display_channel, &drawable
> ->tree_item.base.rgn, drawable);
>          }
>      }
>      region_destroy(&exclude_rgn);
> @@ -2706,6 +2659,7 @@ static void add_clip_rects(QRegion *rgn,
> SpiceClipRects *data)
>  
>  static inline int red_current_add_with_shadow(RedWorker *worker,
> Ring *ring, Drawable *item)
>  {
> +    DisplayChannel *display = worker->display_channel;
>  #ifdef RED_WORKER_STAT
>      stat_time_t start_time = stat_now(worker);
>      ++worker->add_with_shadow_count;
> @@ -2726,8 +2680,8 @@ static inline int
> red_current_add_with_shadow(RedWorker *worker, Ring *ring, Dra
>      // for now putting them on root.
>  
>      // only primary surface streams are supported
> -    if (is_primary_surface(worker, item->surface_id)) {
> -        red_detach_streams_behind(worker, &shadow->base.rgn, NULL);
> +    if (is_primary_surface(display, item->surface_id)) {
> +        detach_streams_behind(display, &shadow->base.rgn, NULL);
>      }
>  
>      ring_add(ring, &shadow->base.siblings_link);
> @@ -2737,10 +2691,10 @@ static inline int
> red_current_add_with_shadow(RedWorker *worker, Ring *ring, Dra
>          region_clone(&exclude_rgn, &item->tree_item.base.rgn);
>          exclude_region(worker, ring, &shadow->base.siblings_link,
> &exclude_rgn, NULL, NULL);
>          region_destroy(&exclude_rgn);
> -        red_streams_update_visible_region(worker, item);
> +        streams_update_visible_region(display, item);
>      } else {
> -        if (is_primary_surface(worker, item->surface_id)) {
> -            red_detach_streams_behind(worker, &item
> ->tree_item.base.rgn, item);
> +        if (is_primary_surface(display, item->surface_id)) {
> +            detach_streams_behind(display, &item
> ->tree_item.base.rgn, item);
>          }
>      }
>      stat_add(&worker->add_stat, start_time);
> @@ -2752,22 +2706,22 @@ static inline int has_shadow(RedDrawable
> *drawable)
>      return drawable->type == QXL_COPY_BITS;
>  }
>  
> -static inline void red_update_streamable(RedWorker *worker, Drawable
> *drawable,
> -                                         RedDrawable *red_drawable)
> +static void drawable_update_streamable(DisplayChannel *display,
> Drawable *drawable)
>  {
> +    RedDrawable *red_drawable = drawable->red_drawable;
>      SpiceImage *image;
>  
> -    if (worker->streaming_video == SPICE_STREAM_VIDEO_OFF) {
> +    if (display->stream_video == SPICE_STREAM_VIDEO_OFF) {
>          return;
>      }
>  
> -    if (!is_primary_surface(worker, drawable->surface_id)) {
> +    if (!is_primary_surface(display, drawable->surface_id)) {
>          return;
>      }
>  
>      if (drawable->tree_item.effect != QXL_EFFECT_OPAQUE ||
> -                                        red_drawable->type !=
> QXL_DRAW_COPY ||
> -                                        red_drawable
> ->u.copy.rop_descriptor != SPICE_ROPD_OP_PUT) {
> +        red_drawable->type != QXL_DRAW_COPY ||
> +        red_drawable->u.copy.rop_descriptor != SPICE_ROPD_OP_PUT) {
>          return;
>      }
>  
> @@ -2777,7 +2731,7 @@ static inline void
> red_update_streamable(RedWorker *worker, Drawable *drawable,
>          return;
>      }
>  
> -    if (worker->streaming_video == SPICE_STREAM_VIDEO_FILTER) {
> +    if (display->stream_video == SPICE_STREAM_VIDEO_FILTER) {
>          SpiceRect* rect;
>          int size;
>  
> @@ -2821,6 +2775,7 @@ static void red_print_stats(RedWorker *worker)
>  
>  static int red_add_drawable(RedWorker *worker, Drawable *drawable)
>  {
> +    DisplayChannel *display = worker->display_channel;
>      int ret = FALSE, surface_id = drawable->surface_id;
>      RedDrawable *red_drawable = drawable->red_drawable;
>      Ring *ring = &worker->surfaces[surface_id].current;
> @@ -2828,7 +2783,7 @@ static int red_add_drawable(RedWorker *worker,
> Drawable *drawable)
>      if (has_shadow(red_drawable)) {
>          ret = red_current_add_with_shadow(worker, ring, drawable);
>      } else {
> -        red_update_streamable(worker, drawable, red_drawable);
> +        drawable_update_streamable(display, drawable);
>          ret = red_current_add(worker, ring, drawable);
>      }
>  
> @@ -2881,6 +2836,7 @@ static int rgb32_data_has_alpha(int width, int
> height, size_t stride,
>  
>  static inline int red_handle_self_bitmap(RedWorker *worker, Drawable
> *drawable)
>  {
> +    DisplayChannel *display = worker->display_channel;
>      SpiceImage *image;
>      int32_t width;
>      int32_t height;
> @@ -2926,7 +2882,7 @@ static inline int
> red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
>  
>      /* 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(display, 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) {
> @@ -3044,6 +3000,7 @@ static inline void
> add_to_surface_dependency(RedWorker *worker, int depend_on_su
>  
>  static inline int red_handle_surfaces_dependencies(RedWorker
> *worker, Drawable *drawable)
>  {
> +    DisplayChannel *display = worker->display_channel;
>      int x;
>  
>      for (x = 0; x < 3; ++x) {
> @@ -3057,7 +3014,7 @@ static inline int
> red_handle_surfaces_dependencies(RedWorker *worker, Drawable *
>                  QRegion depend_region;
>                  region_init(&depend_region);
>                  region_add(&depend_region, &drawable->red_drawable
> ->surfaces_rects[x]);
> -                red_detach_streams_behind(worker, &depend_region,
> NULL);
> +                detach_streams_behind(display, &depend_region,
> NULL);
>              }
>          }
>      }
> @@ -3737,9 +3694,9 @@ static void red_current_flush(RedWorker
> *worker, int surface_id)
>  static ImageItem *red_add_surface_area_image(DisplayChannelClient
> *dcc, int surface_id,
>                                               SpiceRect *area,
> PipeItem *pos, int can_lossy)
>  {
> -    DisplayChannel *display_channel = DCC_TO_DC(dcc);
> -    RedWorker *worker = display_channel->common.worker;
> -    RedChannel *channel = RED_CHANNEL(display_channel);
> +    DisplayChannel *display = DCC_TO_DC(dcc);
> +    RedChannel *channel = RED_CHANNEL(display);
> +    RedWorker *worker = DCC_TO_WORKER(dcc);
>      RedSurface *surface = &worker->surfaces[surface_id];
>      SpiceCanvas *canvas = surface->context.canvas;
>      ImageItem *item;
> @@ -3777,7 +3734,7 @@ static ImageItem
> *red_add_surface_area_image(DisplayChannelClient *dcc, int surf
>  
>      /* 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(display, 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) {
> @@ -6960,10 +6917,9 @@ static inline int
> red_marshall_stream_data(RedChannelClient *rcc,
>                    SpiceMarshaller *base_marshaller, Drawable
> *drawable)
>  {
>      DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> -    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc
> ->channel, DisplayChannel, common.base);
> +    DisplayChannel *display = DCC_TO_DC(dcc);
>      Stream *stream = drawable->stream;
>      SpiceImage *image;
> -    RedWorker *worker = DCC_TO_WORKER(dcc);
>      uint32_t frame_mm_time;
>      int n;
>      int width, height;
> @@ -6975,7 +6931,6 @@ static inline int
> red_marshall_stream_data(RedChannelClient *rcc,
>      }
>      spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY);
>  
> -    worker = display_channel->common.worker;
>      image = drawable->red_drawable->u.copy.src_bitmap;
>  
>      if (image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) {
> @@ -6996,7 +6951,7 @@ static inline int
> red_marshall_stream_data(RedChannelClient *rcc,
>          height = stream->height;
>      }
>  
> -    StreamAgent *agent = &dcc->stream_agents[get_stream_id(worker,
> stream)];
> +    StreamAgent *agent = &dcc->stream_agents[get_stream_id(display,
> stream)];
>      uint64_t time_now = red_get_monotonic_time();
>      size_t outbuf_size;
>  
> @@ -7044,7 +6999,7 @@ static inline int
> red_marshall_stream_data(RedChannelClient *rcc,
>  
>          red_channel_client_init_send_data(rcc,
> SPICE_MSG_DISPLAY_STREAM_DATA, NULL);
>  
> -        stream_data.base.id = get_stream_id(worker, stream);
> +        stream_data.base.id = get_stream_id(display, stream);
>          stream_data.base.multi_media_time = frame_mm_time;
>          stream_data.data_size = n;
>  
> @@ -7054,7 +7009,7 @@ static inline int
> red_marshall_stream_data(RedChannelClient *rcc,
>  
>          red_channel_client_init_send_data(rcc,
> SPICE_MSG_DISPLAY_STREAM_DATA_SIZED, NULL);
>  
> -        stream_data.base.id = get_stream_id(worker, stream);
> +        stream_data.base.id = get_stream_id(display, stream);
>          stream_data.base.multi_media_time = frame_mm_time;
>          stream_data.data_size = n;
>          stream_data.width = width;
> @@ -7426,7 +7381,7 @@ static void
> red_display_marshall_stream_start(RedChannelClient *rcc,
>      SpiceClipRects clip_rects;
>  
>      stream_create.surface_id = 0;
> -    stream_create.id = get_stream_id(DCC_TO_WORKER(dcc), stream);
> +    stream_create.id = get_stream_id(DCC_TO_DC(dcc), stream);
>      stream_create.flags = stream->top_down ?
> SPICE_STREAM_FLAGS_TOP_DOWN : 0;
>      stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG;
>  
> @@ -7462,7 +7417,7 @@ static void
> red_display_marshall_stream_clip(RedChannelClient *rcc,
>      red_channel_client_init_send_data(rcc,
> SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base);
>      SpiceMsgDisplayStreamClip stream_clip;
>  
> -    stream_clip.id = get_stream_id(DCC_TO_WORKER(dcc), agent
> ->stream);
> +    stream_clip.id = get_stream_id(DCC_TO_DC(dcc), agent->stream);
>      stream_clip.clip.type = item->clip_type;
>      stream_clip.clip.rects = item->rects;
>  
> @@ -7476,7 +7431,7 @@ static void
> red_display_marshall_stream_end(RedChannelClient *rcc,
>      SpiceMsgDisplayStreamDestroy destroy;
>  
>      red_channel_client_init_send_data(rcc,
> SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
> -    destroy.id = get_stream_id(DCC_TO_WORKER(dcc), agent->stream);
> +    destroy.id = get_stream_id(DCC_TO_DC(dcc), agent->stream);
>      red_display_stream_agent_stop(dcc, agent);
>      spice_marshall_msg_display_stream_destroy(base_marshaller,
> &destroy);
>  }
> @@ -7711,20 +7666,20 @@ void
> red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
>      red_channel_apply_clients(channel,
> red_channel_client_disconnect);
>  }
>  
> -static void red_destroy_streams(RedWorker *worker)
> +static void detach_and_stop_streams(DisplayChannel *display)
>  {
>      RingItem *stream_item;
>  
>      spice_debug(NULL);
> -    while ((stream_item = ring_get_head(&worker->streams))) {
> +    while ((stream_item = ring_get_head(&display->streams))) {
>          Stream *stream = SPICE_CONTAINEROF(stream_item, Stream,
> link);
>  
> -        red_detach_stream_gracefully(worker, stream, NULL);
> -        red_stop_stream(worker, stream);
> +        detach_stream_gracefully(display, stream, NULL);
> +        stop_stream(display, stream);
>      }
>  }
>  
> -static void red_migrate_display(RedWorker *worker, RedChannelClient
> *rcc)
> +static void red_migrate_display(DisplayChannel *display,
> RedChannelClient *rcc)
>  {
>      /* We need to stop the streams, and to send upgrade_items to the
> client.
>       * Otherwise, (1) the client might display lossy regions that we
> don't track
> @@ -7733,10 +7688,10 @@ static void red_migrate_display(RedWorker
> *worker, RedChannelClient *rcc)
>       * being sent to the client after MSG_MIGRATE and before
> MSG_MIGRATE_DATA (e.g.,
>       * STREAM_CLIP, STREAM_DESTROY, DRAW_COPY)
>       * No message besides MSG_MIGRATE_DATA should be sent after
> MSG_MIGRATE.
> -     * Notice that red_destroy_streams won't lead to any dev ram
> changes, since
> +     * Notice that detach_and_stop_streams won't lead to any dev ram
> changes, since
>       * handle_dev_stop already took care of releasing all the dev
> ram resources.
>       */
> -    red_destroy_streams(worker);
> +    detach_and_stop_streams(display);
>      if (red_channel_client_is_connected(rcc)) {
>          red_channel_client_default_migrate(rcc);
>      }
> @@ -7858,7 +7813,7 @@ static inline void
> red_create_surface_item(DisplayChannelClient *dcc, int surfac
>      RedSurface *surface;
>      SurfaceCreateItem *create;
>      RedWorker *worker = dcc ? DCC_TO_WORKER(dcc) : NULL;
> -    uint32_t flags = is_primary_surface(worker, surface_id) ?
> SPICE_SURFACE_FLAGS_PRIMARY : 0;
> +    uint32_t flags = is_primary_surface(DCC_TO_DC(dcc), surface_id)
> ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
>  
>      /* don't send redundant create surface commands to client */
>      if (!dcc || worker->display_channel
> ->common.during_target_migrate ||
> @@ -8737,17 +8692,17 @@ static void
> display_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item
>  static void
> display_channel_client_release_item_after_push(DisplayChannelClient
> *dcc,
>                                                             PipeItem
> *item)
>  {
> -    RedWorker *worker = DCC_TO_WORKER(dcc);
> +    DisplayChannel *display = DCC_TO_DC(dcc);
>  
>      switch (item->type) {
>      case PIPE_ITEM_TYPE_DRAW:
>          drawable_pipe_item_unref(SPICE_CONTAINEROF(item,
> DrawablePipeItem, dpi_pipe_item));
>          break;
>      case PIPE_ITEM_TYPE_STREAM_CLIP:
> -        red_display_release_stream_clip(worker, (StreamClipItem
> *)item);
> +        display_stream_clip_unref(display, (StreamClipItem *)item);
>          break;
>      case PIPE_ITEM_TYPE_UPGRADE:
> -        release_upgrade_item(worker, (UpgradeItem *)item);
> +        release_upgrade_item(DCC_TO_WORKER(dcc), (UpgradeItem
> *)item);
>          break;
>      case PIPE_ITEM_TYPE_IMAGE:
>          release_image_item((ImageItem *)item);
> @@ -8772,7 +8727,7 @@ static void
> display_channel_client_release_item_after_push(DisplayChannelClient
>  static void
> display_channel_client_release_item_before_push(DisplayChannelClient
> *dcc,
>                                                              PipeItem
> *item)
>  {
> -    RedWorker *worker = DCC_TO_WORKER(dcc);
> +    DisplayChannel *display = DCC_TO_DC(dcc);
>  
>      switch (item->type) {
>      case PIPE_ITEM_TYPE_DRAW: {
> @@ -8783,19 +8738,19 @@ static void
> display_channel_client_release_item_before_push(DisplayChannelClient
>      }
>      case PIPE_ITEM_TYPE_STREAM_CREATE: {
>          StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent,
> create_item);
> -        red_display_release_stream(worker, agent);
> +        display_stream_agent_unref(display, agent);
>          break;
>      }
>      case PIPE_ITEM_TYPE_STREAM_CLIP:
> -        red_display_release_stream_clip(worker, (StreamClipItem
> *)item);
> +        display_stream_clip_unref(display, (StreamClipItem *)item);
>          break;
>      case PIPE_ITEM_TYPE_STREAM_DESTROY: {
>          StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent,
> destroy_item);
> -        red_display_release_stream(worker, agent);
> +        display_stream_agent_unref(display, agent);
>          break;
>      }
>      case PIPE_ITEM_TYPE_UPGRADE:
> -        release_upgrade_item(worker, (UpgradeItem *)item);
> +        release_upgrade_item(DCC_TO_WORKER(dcc), (UpgradeItem
> *)item);
>          break;
>      case PIPE_ITEM_TYPE_IMAGE:
>          release_image_item((ImageItem *)item);
> @@ -8846,16 +8801,16 @@ static void
> display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
>      }
>  }
>  
> -static void red_init_streams(RedWorker *worker)
> +static void init_streams(DisplayChannel *display)
>  {
>      int i;
>  
> -    ring_init(&worker->streams);
> -    worker->free_streams = NULL;
> +    ring_init(&display->streams);
> +    display->free_streams = NULL;
>      for (i = 0; i < NUM_STREAMS; i++) {
> -        Stream *stream = &worker->streams_buf[i];
> +        Stream *stream = &display->streams_buf[i];
>          ring_item_init(&stream->link);
> -        red_free_stream(worker, stream);
> +        display_stream_free(display, stream);
>      }
>  }
>  
> @@ -8875,7 +8830,7 @@ static void display_channel_create(RedWorker
> *worker, int migrate)
>      spice_return_if_fail(num_renderers > 0);
>  
>      spice_info("create display channel");
> -    if (!(worker->display_channel = (DisplayChannel
> *)red_worker_new_channel(
> +    if (!(display_channel = (DisplayChannel
> *)red_worker_new_channel(
>              worker, sizeof(*display_channel), "display_channel",
>              SPICE_CHANNEL_DISPLAY,
>              SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER,
> @@ -8883,7 +8838,7 @@ static void display_channel_create(RedWorker
> *worker, int migrate)
>          spice_warning("failed to create display channel");
>          return;
>      }
> -    display_channel = worker->display_channel;
> +    worker->display_channel = display_channel;
>  #ifdef RED_STATISTICS
>      RedChannel *channel = RED_CHANNEL(display_channel);
>      display_channel->cache_hits_counter = stat_add_counter(channel
> ->stat,
> @@ -8904,6 +8859,7 @@ static void display_channel_create(RedWorker
> *worker, int migrate)
>      display_channel->num_renderers = num_renderers;
>      memcpy(display_channel->renderers, renderers,
> sizeof(display_channel->renderers));
>      display_channel->renderer = RED_RENDERER_INVALID;
> +    init_streams(display_channel);
>      image_cache_init(&display_channel->image_cache);
>  }
>  
> @@ -9179,6 +9135,7 @@ static void
> handle_dev_destroy_surface_wait(void *opaque, void *payload)
>  /* TODO: split me*/
>  static inline void dev_destroy_surfaces(RedWorker *worker)
>  {
> +    DisplayChannel *display = worker->display_channel;
>      int i;
>  
>      spice_debug(NULL);
> @@ -9193,7 +9150,7 @@ static inline void
> dev_destroy_surfaces(RedWorker *worker)
>              spice_assert(!worker->surfaces[i].context.canvas);
>          }
>      }
> -    spice_assert(ring_is_empty(&worker->streams));
> +    spice_assert(ring_is_empty(&display->streams));
>  
>      if (display_is_connected(worker)) {
>          red_channel_pipes_add_type(RED_CHANNEL(worker
> ->display_channel),
> @@ -9307,6 +9264,8 @@ static void
> handle_dev_create_primary_surface(void *opaque, void *payload)
>  
>  static void dev_destroy_primary_surface(RedWorker *worker, uint32_t
> surface_id)
>  {
> +    DisplayChannel *display = worker->display_channel;
> +
>      VALIDATE_SURFACE_RET(worker, surface_id);
>      spice_warn_if(surface_id != 0);
>  
> @@ -9319,7 +9278,7 @@ static void
> dev_destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
>      flush_all_qxl_commands(worker);
>      dev_destroy_surface_wait(worker, 0);
>      red_surface_unref(worker, 0);
> -    spice_assert(ring_is_empty(&worker->streams));
> +    spice_warn_if_fail(ring_is_empty(&display->streams));
>  
>      spice_assert(!worker->surfaces[surface_id].context.canvas);
>  
> @@ -9560,7 +9519,7 @@ static void handle_dev_display_migrate(void
> *opaque, void *payload)
>      RedChannelClient *rcc = msg->rcc;
>      spice_info("migrate display client");
>      spice_assert(rcc);
> -    red_migrate_display(worker, rcc);
> +    red_migrate_display(worker->display_channel, rcc);
>  }
>  
>  static inline uint32_t qxl_monitors_config_size(uint32_t heads)
> @@ -9691,21 +9650,7 @@ static void
> handle_dev_set_streaming_video(void *opaque, void *payload)
>      RedWorkerMessageSetStreamingVideo *msg = payload;
>      RedWorker *worker = opaque;
>  
> -    worker->streaming_video = msg->streaming_video;
> -    spice_assert(worker->streaming_video !=
> SPICE_STREAM_VIDEO_INVALID);
> -    switch(worker->streaming_video) {
> -        case SPICE_STREAM_VIDEO_ALL:
> -            spice_info("sv all");
> -            break;
> -        case SPICE_STREAM_VIDEO_FILTER:
> -            spice_info("sv filter");
> -            break;
> -        case SPICE_STREAM_VIDEO_OFF:
> -            spice_info("sv off");
> -            break;
> -        default:
> -            spice_warning("sv invalid");
> -    }
> +    display_channel_set_stream_video(worker->display_channel, msg
> ->streaming_video);
>  }
>  
>  static void handle_dev_set_mouse_mode(void *opaque, void *payload)
> @@ -10038,12 +9983,10 @@ RedWorker* red_worker_new(QXLInstance *qxl,
> RedDispatcher *red_dispatcher)
>      worker->image_compression = image_compression;
>      worker->jpeg_state = jpeg_state;
>      worker->zlib_glz_state = zlib_glz_state;
> -    worker->streaming_video = streaming_video;
>      worker->driver_cap_monitors_config = 0;
>      ring_init(&worker->current_list);
>      image_surface_init(worker);
>      drawables_init(worker);
> -    red_init_streams(worker);
>      stat_init(&worker->add_stat, add_stat_name);
>      stat_init(&worker->exclude_stat, exclude_stat_name);
>      stat_init(&worker->__exclude_stat, __exclude_stat_name);
> @@ -10122,10 +10065,10 @@ SPICE_GNUC_NORETURN static void
> *red_worker_main(void *arg)
>  
>          timeout = spice_timer_queue_get_timeout_ms();
>          worker->event_timeout = MIN(timeout, worker->event_timeout);
> -        timeout = red_get_streams_timout(worker);
> +        timeout = display_channel_get_streams_timeout(worker
> ->display_channel);
>          worker->event_timeout = MIN(timeout, worker->event_timeout);
>          num_events = poll(worker->poll_fds, MAX_EVENT_SOURCES,
> worker->event_timeout);
> -        red_handle_streams_timout(worker);
> +        display_channel_streams_timeout(worker->display_channel);
>          spice_timer_queue_cb();
>  
>          if (worker->display_channel) {
> diff --git a/server/stream.c b/server/stream.c
> index 53d05f3..6203f3d 100644
> --- a/server/stream.c
> +++ b/server/stream.c
> @@ -28,8 +28,8 @@ void stream_agent_stats_print(StreamAgent *agent)
>          mjpeg_encoder_get_stats(agent->mjpeg_encoder,
> &encoder_stats);
>      }
>  
> -    spice_debug("stream=%p dim=(%dx%d) #in-frames=%"PRIu64" #in-avg
> -fps=%.2f #out-frames=%"PRIu64" "
> -                "out/in=%.2f #drops=%"PRIu64" (#pipe=%"PRIu64"
> #fps=%"PRIu64") out-avg-fps=%.2f "
> +    spice_debug("stream=%p dim=(%dx%d) #in-frames=%lu #in-avg
> -fps=%.2f #out-frames=%lu "
> +                "out/in=%.2f #drops=%lu (#pipe=%lu #fps=%lu) out-avg
> -fps=%.2f "
>                  "passed-mm-time(sec)=%.2f size-total(MB)=%.2f size
> -per-sec(Mbps)=%.2f "
>                  "size-per-frame(KBpf)=%.2f avg-quality=%.2f "
>                  "start-bit-rate(Mbps)=%.2f end-bit-rate(Mbps)=%.2f",


More information about the Spice-devel mailing list