> NACK > > There's a lot of stuff going on in this patch, but I think it would > be hard to split out (other than a few minor include changes I noted > below). So I'm OK with that part. But there seems to be one behavior > change that I've noted below. > > Agree that code change (if stream one) looks wrong (and probably untested). I'll try to split the patch. Frediano > > On Fri, 2015-11-06 at 11:01 +0000, Frediano Ziglio wrote: > > > From: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> > > > > --- > > server/Makefile.am | 2 + > > server/display-channel.c | 44 +++ > > server/display-channel.h | 82 ++--- > > server/red_worker.c | 916 ++++++++++++++++++++----------------- > > ---------- > > server/red_worker.h | 1 + > > server/stream.c | 66 ++++ > > server/stream.h | 143 ++++++++ > > server/utils.h | 1 + > > 8 files changed, 664 insertions(+), 591 deletions(-) > > create mode 100644 server/stream.c > > create mode 100644 server/stream.h > > > > diff --git a/server/Makefile.am b/server/Makefile.am > > index 7216ab0..52703c9 100644 > > --- a/server/Makefile.am > > +++ b/server/Makefile.am > > @@ -136,6 +136,8 @@ libspice_server_la_SOURCES = > > \ > > spice-bitmap-utils.h \ > > spice-bitmap-utils.c \ > > utils.h \ > > + stream.c \ > > + stream.h \ > > $(NULL) > > > > if HAVE_GL > > diff --git a/server/display-channel.c b/server/display-channel.c > > index 5deab13..3df6a31 100644 > > --- a/server/display-channel.c > > +++ b/server/display-channel.c > > @@ -221,3 +221,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 827a9d4..b92bc5c 100644 > > --- a/server/display-channel.h > > +++ b/server/display-channel.h > > @@ -54,11 +54,9 @@ > > #include "spice_image_cache.h" > > #include "utils.h" > > #include "tree.h" > > +#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) > > @@ -128,23 +126,6 @@ typedef struct { > > EncoderData data; > > } GlzData; > > > > -typedef struct Stream Stream; > > -struct Stream { > > - uint8_t refs; > > - Drawable *current; > > - red_time_t last_time; > > - int width; > > - int height; > > - SpiceRect dest_area; > > - int top_down; > > - Stream *next; > > - RingItem link; > > - > > - uint32_t num_input_frames; > > - uint64_t input_fps_start_time; > > - uint32_t input_fps; > > -}; > > - > > typedef struct DependItem { > > Drawable *drawable; > > RingItem ring_item; > > @@ -179,48 +160,6 @@ struct Drawable { > > uint32_t process_commands_generation; > > }; > > > > -#define STREAM_STATS > > -#ifdef STREAM_STATS > > -typedef struct StreamStats { > > - uint64_t num_drops_pipe; > > - uint64_t num_drops_fps; > > - uint64_t num_frames_sent; > > - uint64_t num_input_frames; > > - uint64_t size_sent; > > - > > - uint64_t start; > > - uint64_t end; > > -} StreamStats; > > -#endif > > - > > -typedef struct StreamAgent { > > - QRegion vis_region; /* the part of the surface area that is > > currently occupied by video > > - fragments */ > > - QRegion clip; /* the current video clipping. It can be > > different from vis_region: > > - for example, let c1 be the clip area at > > time t1, and c2 > > - be the clip area at time t2, where t1 < > > t2. If c1 contains c2, and > > - at least part of c1/c2, hasn't been > > covered by a non-video images, > > - vis_region will contain c2 and also the > > part of c1/c2 that still > > - displays fragments of the video */ > > - > > - PipeItem create_item; > > - PipeItem destroy_item; > > - Stream *stream; > > - uint64_t last_send_time; > > - MJpegEncoder *mjpeg_encoder; > > - DisplayChannelClient *dcc; > > - > > - int frames; > > - int drops; > > - int fps; > > - > > - uint32_t report_id; > > - uint32_t client_required_latency; > > -#ifdef STREAM_STATS > > - StreamStats stats; > > -#endif > > -} StreamAgent; > > - > > struct DisplayChannelClient { > > CommonChannelClient common; > > > > @@ -328,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 > > > > @@ -344,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; > > + > > #ifdef RED_STATISTICS > > uint64_t *cache_hits_counter; > > uint64_t *add_to_cache_counter; > > @@ -360,6 +312,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 df5be98..7a4822a 100644 > > --- a/server/red_worker.c > > +++ b/server/red_worker.c > > @@ -58,6 +58,7 @@ > > #include "common/generated_server_marshallers.h" > > > > #include "display-channel.h" > > +#include "stream.h" > > > > #include "spice.h" > > #include "red_worker.h" > > @@ -80,21 +81,6 @@ > > > > #define DISPLAY_FREE_LIST_DEFAULT_SIZE 128 > > > > -#define RED_STREAM_DETACTION_MAX_DELTA ((1000 * 1000 * 1000) / 5) // > > 1/5 sec > > -#define RED_STREAM_CONTINUS_MAX_DELTA (1000 * 1000 * 1000) > > -#define RED_STREAM_TIMOUT (1000 * 1000 * 1000) > > -#define RED_STREAM_FRAMES_START_CONDITION 20 > > -#define RED_STREAM_GRADUAL_FRAMES_START_CONDITION 0.2 > > -#define RED_STREAM_FRAMES_RESET_CONDITION 100 > > -#define RED_STREAM_MIN_SIZE (96 * 96) > > -#define RED_STREAM_INPUT_FPS_TIMEOUT ((uint64_t)5 * 1000 * 1000 * > > 1000) // 5 sec > > -#define RED_STREAM_CHANNEL_CAPACITY 0.8 > > -/* the client's stream report frequency is the minimum of the 2 > > values below */ > > -#define RED_STREAM_CLIENT_REPORT_WINDOW 5 // #frames > > -#define RED_STREAM_CLIENT_REPORT_TIMEOUT 1000 // milliseconds > > -#define RED_STREAM_DEFAULT_HIGH_START_BIT_RATE (10 * 1024 * 1024) // > > 10Mbps > > -#define RED_STREAM_DEFAULT_LOW_START_BIT_RATE (2.5 * 1024 * 1024) // > > 2.5Mbps > > - > > #define FPS_TEST_INTERVAL 1 > > #define MAX_FPS 30 > > > > @@ -241,11 +227,6 @@ typedef struct SurfaceDestroyItem { > > PipeItem pipe_item; > > } SurfaceDestroyItem; > > > > -typedef struct StreamActivateReportItem { > > - PipeItem pipe_item; > > - uint32_t stream_id; > > -} StreamActivateReportItem; > > - > > #define MAX_PIPE_SIZE 50 > > > > #define WIDE_CLIENT_ACK_WINDOW 40 > > @@ -266,20 +247,6 @@ typedef struct ImageItem { > > uint8_t data[0]; > > } ImageItem; > > > > -enum { > > - STREAM_FRAME_NONE, > > - STREAM_FRAME_NATIVE, > > - STREAM_FRAME_CONTAINER, > > -}; > > - > > -typedef struct StreamClipItem { > > - PipeItem base; > > - int refs; > > - StreamAgent *stream_agent; > > - int clip_type; > > - SpiceClipRects *rects; > > -} StreamClipItem; > > - > > typedef struct { > > QuicUsrContext usr; > > EncoderData data; > > @@ -382,20 +349,6 @@ typedef struct RedSurface { > > QXLReleaseInfoExt create, destroy; > > } RedSurface; > > > > -typedef struct ItemTrace { > > - red_time_t time; > > - int frames_count; > > - int gradual_frames_count; > > - int last_gradual_frame; > > - int width; > > - int height; > > - SpiceRect dest_area; > > -} ItemTrace; > > - > > -#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 > > #define NUM_CURSORS 100 > > > > @@ -428,7 +381,6 @@ typedef struct RedWorker { > > > > uint32_t shadows_count; > > uint32_t containers_count; > > - uint32_t stream_count; > > > > uint32_t bits_unique; > > > > @@ -443,14 +395,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; > > > > @@ -519,16 +463,12 @@ 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 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, > > @@ -565,6 +505,136 @@ static void > > display_channel_client_release_item_after_push(DisplayChannelClient > > SAFE_FOREACH(link, next, drawable, &(drawable)->glz_ring, glz, > > LINK_TO_GLZ(link)) > > > > > > +static int get_stream_id(DisplayChannel *display, Stream *stream) > > +{ > > + return (int)(stream - display->streams_buf); > > +} > > + > > +static void display_stream_free(DisplayChannel *display, Stream > > *stream) > > +{ > > + stream->next = display->free_streams; > > + display->free_streams = stream; > > +} > > + > > +static void display_stream_unref(DisplayChannel *display, Stream > > *stream) > > +{ > > + 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 display_stream_agent_unref(DisplayChannel *display, > > StreamAgent *agent) > > +{ > > + display_stream_unref(display, agent->stream); > > +} > > + > > +static void display_stream_clip_unref(DisplayChannel *display, > > StreamClipItem *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) > > +{ > > + StreamClipItem *item = stream_clip_item_new(dcc, agent); > > + int n_rects; > > + > > + 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); > > +} > > + > > + > > +void attach_stream(DisplayChannel *display, Drawable *drawable, > > Stream *stream) > > +{ > > + DisplayChannelClient *dcc; > > + RingItem *item, *next; > > + > > + spice_assert(!drawable->stream && !stream->current); > > + spice_assert(drawable && stream); > > + stream->current = drawable; > > + drawable->stream = stream; > > + stream->last_time = drawable->creation_time; > > + > > + uint64_t duration = drawable->creation_time - stream > > ->input_fps_start_time; > > + if (duration >= RED_STREAM_INPUT_FPS_TIMEOUT) { > > + /* Round to the nearest integer, for instance 24 for 23.976 > > */ > > + stream->input_fps = ((uint64_t)stream->num_input_frames * > > 1000 * 1000 * 1000 + duration / 2) / duration; > > + spice_debug("input-fps=%u", stream->input_fps); > > + stream->num_input_frames = 0; > > + stream->input_fps_start_time = drawable->creation_time; > > + } else { > > + stream->num_input_frames++; > > + } > > + > > + FOREACH_DCC(display, item, next, dcc) { > > + StreamAgent *agent; > > + QRegion clip_in_draw_dest; > > + > > + 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); > > + region_add(&clip_in_draw_dest, &drawable->red_drawable > > ->bbox); > > + region_and(&clip_in_draw_dest, &agent->clip); > > + > > + if (!region_is_equal(&clip_in_draw_dest, &drawable > > ->tree_item.base.rgn)) { > > + region_remove(&agent->clip, &drawable->red_drawable > > ->bbox); > > + region_or(&agent->clip, &drawable->tree_item.base.rgn); > > + dcc_push_stream_agent_clip(dcc, agent); > > + } > > +#ifdef STREAM_STATS > > + agent->stats.num_input_frames++; > > +#endif > > + } > > +} > > + > > +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(display, stream)); > > + FOREACH_DCC(display, item, next, dcc) { > > + StreamAgent *stream_agent; > > + > > + 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)); > > + if (stream_agent->mjpeg_encoder && dcc > > ->use_mjpeg_encoder_rate_control) { > > + uint64_t stream_bit_rate = > > mjpeg_encoder_get_bit_rate(stream_agent->mjpeg_encoder); > > + > > + if (stream_bit_rate > dcc->streams_max_bit_rate) { > > + spice_debug("old max-bit-rate=%.2f new=%.2f", > > + dcc->streams_max_bit_rate / 8.0 / 1024.0 / 1024.0, > > + stream_bit_rate / 8.0 / 1024.0 / 1024.0); > > + dcc->streams_max_bit_rate = stream_bit_rate; > > + } > > + } > > + stream->refs++; > > + red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), > > &stream_agent->destroy_item); > > + stream_agent_stats_print(stream_agent); > > + } > > + display->streams_size_total -= stream->width * stream->height; > > + ring_remove(&stream->link); > > + display_stream_unref(display, stream); > > +} > > + > > /* fixme: move to display channel */ > > DrawablePipeItem *drawable_pipe_item_new(DisplayChannelClient *dcc, > > Drawable *drawable) > > @@ -610,7 +680,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; > > @@ -896,8 +966,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) > > { > > @@ -929,16 +997,36 @@ static inline void > > red_destroy_surface_item(RedWorker *worker, > > red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy > > ->pipe_item); > > } > > > > +static void stop_streams(DisplayChannel *display) > > +{ > > + Ring *ring = &display->streams; > > + RingItem *item = ring_get_head(ring); > > + > > + while (item) { > > + Stream *stream = SPICE_CONTAINEROF(item, Stream, link); > > + item = ring_next(ring, item); > > + if (!stream->current) { > > + stop_stream(display, stream); > > + } else { > > + spice_info("attached stream"); > > + } > > + } > > + > > + display->next_item_trace = 0; > > + memset(display->items_trace, 0, sizeof(display->items_trace)); > > +} > > + > > static inline void red_destroy_surface(RedWorker *worker, uint32_t > > surface_id) > > { > > + DisplayChannel *display = worker->display_channel; > > RedSurface *surface = &worker->surfaces[surface_id]; > > DisplayChannelClient *dcc; > > RingItem *link, *next; > > > > if (!--surface->refs) { > > // 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); > > > > @@ -1025,6 +1113,9 @@ static void > > remove_drawable_dependencies(RedWorker *worker, Drawable *drawable) > > } > > } > > > > +static void detach_stream(DisplayChannel *display, Stream *stream, > > + int detach_sized); > > + > > static void red_worker_drawable_unref(RedWorker *worker, Drawable > > *drawable) > > { > > RingItem *item, *next; > > @@ -1036,7 +1127,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); > > > > @@ -1094,14 +1185,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; > > } > > This appears to be a change in behavior. It looks to be related to > the change just below in the next hunk, but it seems incorrect. > > In the pervious version, we were calling this function only if > item->stream was NULL (see below). In the new version, we're calling > this function unconditionally (see below), but we're returning early > if item->stream is NULL. This effectively reverses the test: > > old: call function if item->stream is NULL > new: call function if item->stream is not NULL > > I'm afraid I don't know enough about this code to determine what > effect this might have... > > > > > - 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; > > @@ -1136,9 +1228,8 @@ static inline void > > current_remove_drawable(RedWorker *worker, Drawable *item) > > if (item->tree_item.effect != QXL_EFFECT_OPAQUE) { > > worker->transparent_count--; > > } > > - if (!item->stream) { > > - red_add_item_trace(worker, item); > > - } > > + > > + display_stream_trace_add_drawable(worker->display_channel, > > item); > > remove_shadow(worker, &item->tree_item); > > ring_remove(&item->tree_item.base.siblings_link); > > ring_remove(&item->list_link); > > @@ -1366,7 +1457,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); > > } > > @@ -1556,22 +1647,8 @@ static int is_same_drawable(RedWorker *worker, > > Drawable *d1, Drawable *d2) > > } > > } > > > > -static inline void red_free_stream(RedWorker *worker, Stream > > *stream) > > -{ > > - stream->next = worker->free_streams; > > - worker->free_streams = stream; > > -} > > - > > -static void red_release_stream(RedWorker *worker, Stream *stream) > > -{ > > - if (!--stream->refs) { > > - spice_assert(!ring_item_is_linked(&stream->link)); > > - red_free_stream(worker, stream); > > - worker->stream_count--; > > - } > > -} > > - > > -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); > > @@ -1582,164 +1659,6 @@ static inline void > > red_detach_stream(RedWorker *worker, Stream *stream, int deta > > stream->current = NULL; > > } > > > > -static StreamClipItem *__new_stream_clip(DisplayChannelClient* dcc, > > StreamAgent *agent) > > -{ > > - StreamClipItem *item = spice_new(StreamClipItem, 1); > > - red_channel_pipe_item_init(RED_CHANNEL_CLIENT(dcc)->channel, > > - (PipeItem *)item, PIPE_ITEM_TYPE_STREAM_CLIP); > > - > > - item->stream_agent = agent; > > - agent->stream->refs++; > > - item->refs = 1; > > - return item; > > -} > > - > > -static void push_stream_clip(DisplayChannelClient* dcc, StreamAgent > > *agent) > > -{ > > - StreamClipItem *item = __new_stream_clip(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_display_release_stream_clip(RedWorker *worker, > > StreamClipItem *item) > > -{ > > - if (!--item->refs) { > > - red_display_release_stream(worker, item->stream_agent); > > - free(item->rects); > > - free(item); > > - } > > -} > > - > > -static inline int get_stream_id(RedWorker *worker, Stream *stream) > > -{ > > - return (int)(stream - worker->streams_buf); > > -} > > - > > -static void red_attach_stream(RedWorker *worker, Drawable *drawable, > > Stream *stream) > > -{ > > - DisplayChannelClient *dcc; > > - RingItem *item, *next; > > - > > - spice_assert(!drawable->stream && !stream->current); > > - spice_assert(drawable && stream); > > - stream->current = drawable; > > - drawable->stream = stream; > > - stream->last_time = drawable->creation_time; > > - > > - uint64_t duration = drawable->creation_time - stream > > ->input_fps_start_time; > > - if (duration >= RED_STREAM_INPUT_FPS_TIMEOUT) { > > - /* Round to the nearest integer, for instance 24 for 23.976 > > */ > > - stream->input_fps = ((uint64_t)stream->num_input_frames * > > 1000 * 1000 * 1000 + duration / 2) / duration; > > - spice_debug("input-fps=%u", stream->input_fps); > > - stream->num_input_frames = 0; > > - stream->input_fps_start_time = drawable->creation_time; > > - } else { > > - stream->num_input_frames++; > > - } > > - > > - FOREACH_DCC(worker->display_channel, item, next, dcc) { > > - StreamAgent *agent; > > - QRegion clip_in_draw_dest; > > - > > - agent = &dcc->stream_agents[get_stream_id(worker, stream)]; > > - region_or(&agent->vis_region, &drawable > > ->tree_item.base.rgn); > > - > > - region_init(&clip_in_draw_dest); > > - region_add(&clip_in_draw_dest, &drawable->red_drawable > > ->bbox); > > - region_and(&clip_in_draw_dest, &agent->clip); > > - > > - if (!region_is_equal(&clip_in_draw_dest, &drawable > > ->tree_item.base.rgn)) { > > - region_remove(&agent->clip, &drawable->red_drawable > > ->bbox); > > - region_or(&agent->clip, &drawable->tree_item.base.rgn); > > - push_stream_clip(dcc, agent); > > - } > > -#ifdef STREAM_STATS > > - agent->stats.num_input_frames++; > > -#endif > > - } > > -} > > - > > -static void red_print_stream_stats(DisplayChannelClient *dcc, > > StreamAgent *agent) > > -{ > > -#ifdef STREAM_STATS > > - StreamStats *stats = &agent->stats; > > - double passed_mm_time = (stats->end - stats->start) / 1000.0; > > - MJpegEncoderStats encoder_stats = {0}; > > - > > - if (agent->mjpeg_encoder) { > > - mjpeg_encoder_get_stats(agent->mjpeg_encoder, > > &encoder_stats); > > - } > > - > > - spice_debug("stream=%"PRIdPTR" 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 " > > - "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", > > - agent - dcc->stream_agents, agent->stream->width, > > agent->stream->height, > > - stats->num_input_frames, > > - stats->num_input_frames / passed_mm_time, > > - stats->num_frames_sent, > > - (stats->num_frames_sent + 0.0) / stats > > ->num_input_frames, > > - stats->num_drops_pipe + > > - stats->num_drops_fps, > > - stats->num_drops_pipe, > > - stats->num_drops_fps, > > - stats->num_frames_sent / passed_mm_time, > > - passed_mm_time, > > - stats->size_sent / 1024.0 / 1024.0, > > - ((stats->size_sent * 8.0) / (1024.0 * 1024)) / > > passed_mm_time, > > - stats->size_sent / 1000.0 / stats->num_frames_sent, > > - encoder_stats.avg_quality, > > - encoder_stats.starting_bit_rate / (1024.0 * 1024), > > - encoder_stats.cur_bit_rate / (1024.0 * 1024)); > > -#endif > > -} > > - > > -static void red_stop_stream(RedWorker *worker, 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) { > > - StreamAgent *stream_agent; > > - > > - stream_agent = &dcc->stream_agents[get_stream_id(worker, > > stream)]; > > - region_clear(&stream_agent->vis_region); > > - region_clear(&stream_agent->clip); > > - spice_assert(!pipe_item_is_linked(&stream_agent > > ->destroy_item)); > > - if (stream_agent->mjpeg_encoder && dcc > > ->use_mjpeg_encoder_rate_control) { > > - uint64_t stream_bit_rate = > > mjpeg_encoder_get_bit_rate(stream_agent->mjpeg_encoder); > > - > > - if (stream_bit_rate > dcc->streams_max_bit_rate) { > > - spice_debug("old max-bit-rate=%.2f new=%.2f", > > - dcc->streams_max_bit_rate / 8.0 / 1024.0 / 1024.0, > > - stream_bit_rate / 8.0 / 1024.0 / 1024.0); > > - dcc->streams_max_bit_rate = stream_bit_rate; > > - } > > - } > > - stream->refs++; > > - red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), > > &stream_agent->destroy_item); > > - red_print_stream_stats(dcc, stream_agent); > > - } > > - worker->streams_size_total -= stream->width * stream->height; > > - ring_remove(&stream->link); > > - red_release_stream(worker, stream); > > -} > > - > > static int red_display_drawable_is_in_pipe(DisplayChannelClient > > *dcc, Drawable *drawable) > > { > > DrawablePipeItem *dpi; > > @@ -1756,18 +1675,19 @@ static int > > red_display_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable * > > > > /* > > * after red_display_detach_stream_gracefully is called for all the > > display channel clients, > > - * red_detach_stream should be called. See comment (1). > > + * detach_stream should be called. See comment (1). > > */ > > -static inline void > > red_display_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*/ > > region_clear(&agent->clip); > > - push_stream_clip(dcc, agent); > > + dcc_push_stream_agent_clip(dcc, agent); > > > > if (region_is_empty(&agent->vis_region)) { > > spice_debug("stream %d: vis region empty", stream_id); > > @@ -1825,17 +1745,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) { > > - red_display_detach_stream_gracefully(dcc, stream, > > update_area_limit); > > + 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); > > } > > } > > > > @@ -1849,55 +1769,55 @@ static inline void > > red_detach_stream_gracefully(RedWorker *worker, Stream *strea > > * involves sending an upgrade image to the client, this > > drawable won't be rendered > > * (see red_display_detach_stream_gracefully). > > */ > > -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)) { > > - red_display_detach_stream_gracefully(dcc, stream, > > drawable); > > - detach_stream = 1; > > - spice_debug("stream %d", get_stream_id(worker, > > stream)); > > + dcc_detach_stream_gracefully(dcc, stream, drawable); > > + 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) { > > @@ -1910,42 +1830,21 @@ 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); > > region_exclude(&agent->clip, &drawable > > ->tree_item.base.rgn); > > - push_stream_clip(dcc, agent); > > + dcc_push_stream_agent_clip(dcc, agent); > > } > > } > > } > > } > > > > -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_TIMOUT) - > > 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(); > > @@ -1953,27 +1852,21 @@ static inline void > > red_handle_streams_timout(RedWorker *worker) > > while (item) { > > Stream *stream = SPICE_CONTAINEROF(item, Stream, link); > > item = ring_next(ring, item); > > - if (now >= (stream->last_time + RED_STREAM_TIMOUT)) { > > - red_detach_stream_gracefully(worker, stream, NULL); > > - red_stop_stream(worker, stream); > > + if (now >= (stream->last_time + RED_STREAM_TIMEOUT)) { > > + detach_stream_gracefully(display, stream, NULL); > > + stop_stream(display, stream); > > } > > } > > } > > > > -static void red_display_release_stream(RedWorker *worker, > > StreamAgent *agent) > > -{ > > - spice_assert(agent->stream); > > - red_release_stream(worker, agent->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; > > } > > > > @@ -2022,7 +1915,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) > > @@ -2064,7 +1957,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++) { > > @@ -2103,9 +1996,9 @@ static void > > red_stream_update_client_playback_latency(void *opaque, uint32_t del > > main_dispatcher_set_mm_time_latency(RED_CHANNEL_CLIENT(agent > > ->dcc)->client, agent->dcc->streams_max_latency); > > } > > > > -static void red_display_create_stream(DisplayChannelClient *dcc, > > Stream *stream) > > +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)); > > @@ -2141,7 +2034,7 @@ static void > > red_display_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 > > @@ -2152,7 +2045,7 @@ static void > > red_display_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; > > @@ -2161,14 +2054,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; > > @@ -2181,37 +2074,38 @@ 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) { > > - red_display_create_stream(dcc, stream); > > + 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; > > } > > > > -static void red_disply_start_streams(DisplayChannelClient *dcc) > > +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))) { > > Stream *stream = SPICE_CONTAINEROF(item, Stream, link); > > - red_display_create_stream(dcc, stream); > > + dcc_create_stream(dcc, stream); > > } > > } > > > > -static void red_display_client_init_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); > > @@ -2221,7 +2115,7 @@ static void > > red_display_client_init_streams(DisplayChannelClient *dcc) > > red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), > > SPICE_DISPLAY_CAP_STREAM_REPORT); > > } > > > > -static void red_display_destroy_streams_agents(DisplayChannelClient > > *dcc) > > +static void dcc_destroy_stream_agents(DisplayChannelClient *dcc) > > { > > int i; > > > > @@ -2236,27 +2130,14 @@ static void > > red_display_destroy_streams_agents(DisplayChannelClient *dcc) > > } > > } > > > > -static void red_init_streams(RedWorker *worker) > > -{ > > - int i; > > - > > - ring_init(&worker->streams); > > - worker->free_streams = NULL; > > - for (i = 0; i < NUM_STREAMS; i++) { > > - Stream *stream = &worker->streams_buf[i]; > > - ring_item_init(&stream->link); > > - red_free_stream(worker, stream); > > - } > > -} > > - > > -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; > > @@ -2319,22 +2200,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; > > @@ -2342,9 +2209,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; > > } > > > > @@ -2353,7 +2220,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]; > > @@ -2376,7 +2243,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]; > > @@ -2407,12 +2274,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; > > } > > @@ -2431,7 +2299,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 >= > > @@ -2439,13 +2307,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; > > > > @@ -2463,45 +2331,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); > > } > > } > > } > > @@ -2539,7 +2414,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); > > @@ -2613,81 +2488,61 @@ 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; > > } > > } > > } > > } > > > > -static void red_reset_stream_trace(RedWorker *worker) > > -{ > > - Ring *ring = &worker->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); > > - } else { > > - spice_info("attached stream"); > > - } > > - } > > - > > - worker->next_item_trace = 0; > > - memset(worker->items_trace, 0, sizeof(worker->items_trace)); > > -} > > - > > static inline int red_current_add(RedWorker *worker, Ring *ring, > > Drawable *drawable) > > { > > DrawItem *item = &drawable->tree_item; > > @@ -2784,8 +2639,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 > > @@ -2799,8 +2654,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); > > @@ -2819,6 +2674,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; > > @@ -2840,8 +2696,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); > > @@ -2851,10 +2707,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); > > @@ -2866,22 +2722,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; > > } > > > > @@ -2891,7 +2747,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; > > > > @@ -2935,6 +2791,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; > > @@ -2942,7 +2799,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); > > } > > > > @@ -2995,6 +2852,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; > > @@ -3040,7 +2898,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) { > > @@ -3158,6 +3016,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) { > > @@ -3171,7 +3030,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); > > } > > } > > } > > @@ -3910,9 +3769,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; > > @@ -3950,7 +3809,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) { > > @@ -7133,10 +6992,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; > > @@ -7148,7 +7006,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) { > > @@ -7169,7 +7026,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; > > > > @@ -7217,7 +7074,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; > > > > @@ -7227,7 +7084,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; > > @@ -7599,7 +7456,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; > > > > @@ -7635,7 +7492,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; > > > > @@ -7649,7 +7506,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); > > } > > @@ -7862,7 +7719,7 @@ static void > > display_channel_client_on_disconnect(RedChannelClient *rcc) > > free(dcc->send_data.stream_outbuf); > > red_display_reset_compress_buf(dcc); > > free(dcc->send_data.free_list.res); > > - red_display_destroy_streams_agents(dcc); > > + dcc_destroy_stream_agents(dcc); > > > > // this was the last channel client > > if (!red_channel_is_connected(rcc->channel)) { > > @@ -7884,20 +7741,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 > > @@ -7906,10 +7763,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); > > } > > @@ -8029,7 +7886,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 || > > @@ -8288,7 +8145,7 @@ static void > > on_new_display_channel_client(DisplayChannelClient *dcc) > > red_push_surface_image(dcc, 0); > > dcc_push_monitors_config(dcc); > > red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK); > > - red_disply_start_streams(dcc); > > + dcc_create_all_streams(dcc); > > } > > } > > > > @@ -8908,17 +8765,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); > > @@ -8943,7 +8800,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: { > > @@ -8954,19 +8811,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); > > @@ -9017,6 +8874,19 @@ static void > > display_channel_release_item(RedChannelClient *rcc, PipeItem *item, > > } > > } > > > > +static void init_streams(DisplayChannel *display) > > +{ > > + int i; > > + > > + ring_init(&display->streams); > > + display->free_streams = NULL; > > + for (i = 0; i < NUM_STREAMS; i++) { > > + Stream *stream = &display->streams_buf[i]; > > + ring_item_init(&stream->link); > > + display_stream_free(display, stream); > > + } > > +} > > + > > static void display_channel_create(RedWorker *worker, int migrate) > > { > > DisplayChannel *display_channel; > > @@ -9033,7 +8903,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, > > @@ -9041,7 +8911,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, > > @@ -9062,6 +8932,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); > > } > > > > static void guest_set_client_capabilities(RedWorker *worker) > > @@ -9166,7 +9037,7 @@ static void > > handle_new_display_channel(RedWorker *worker, RedClient *client, Red > > > > // todo: tune level according to bandwidth > > display_channel->zlib_level = ZLIB_DEFAULT_COMPRESSION_LEVEL; > > - red_display_client_init_streams(dcc); > > + dcc_init_stream_agents(dcc); > > on_new_display_channel_client(dcc); > > } > > > > @@ -9354,6 +9225,7 @@ 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); > > @@ -9368,7 +9240,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), > > @@ -9482,6 +9354,8 @@ 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); > > > > @@ -9494,7 +9368,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_destroy_surface(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); > > > > @@ -9739,7 +9613,7 @@ 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) > > @@ -9870,21 +9744,7 @@ 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); > > } > > > > void handle_dev_set_mouse_mode(void *opaque, void *payload) > > @@ -10199,13 +10059,11 @@ 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_cache_init(&worker->image_cache); > > 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); > > @@ -10284,10 +10142,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/red_worker.h b/server/red_worker.h > > index 2995b8f..d2f2206 100644 > > --- a/server/red_worker.h > > +++ b/server/red_worker.h > > @@ -20,6 +20,7 @@ > > > > #include <unistd.h> > > #include <errno.h> > > +#include <glib.h> > > #include "red_common.h" > > #include "red_dispatcher.h" > > > This include is unrelated and shouldn't be part of this commit. > > > > > diff --git a/server/stream.c b/server/stream.c > > new file mode 100644 > > index 0000000..6203f3d > > --- /dev/null > > +++ b/server/stream.c > > @@ -0,0 +1,66 @@ > > +/* > > + Copyright (C) 2009-2015 Red Hat, Inc. > > + > > + This library is free software; you can redistribute it and/or > > + modify it under the terms of the GNU Lesser General Public > > + License as published by the Free Software Foundation; either > > + version 2.1 of the License, or (at your option) any later > > version. > > + > > + This library is distributed in the hope that it will be useful, > > + but WITHOUT ANY WARRANTY; without even the implied warranty of > > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + Lesser General Public License for more details. > > + > > + You should have received a copy of the GNU Lesser General Public > > + License along with this library; if not, see < > > http://www.gnu.org/licenses/>;;. > > +*/ > > +#include "stream.h" > > +#include "display-channel.h" > > + > > +void stream_agent_stats_print(StreamAgent *agent) > > +{ > > +#ifdef STREAM_STATS > > + StreamStats *stats = &agent->stats; > > + double passed_mm_time = (stats->end - stats->start) / 1000.0; > > + MJpegEncoderStats encoder_stats = {0}; > > + > > + if (agent->mjpeg_encoder) { > > + mjpeg_encoder_get_stats(agent->mjpeg_encoder, > > &encoder_stats); > > + } > > + > > + 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", > > + agent, agent->stream->width, agent->stream->height, > > + stats->num_input_frames, > > + stats->num_input_frames / passed_mm_time, > > + stats->num_frames_sent, > > + (stats->num_frames_sent + 0.0) / stats > > ->num_input_frames, > > + stats->num_drops_pipe + > > + stats->num_drops_fps, > > + stats->num_drops_pipe, > > + stats->num_drops_fps, > > + stats->num_frames_sent / passed_mm_time, > > + passed_mm_time, > > + stats->size_sent / 1024.0 / 1024.0, > > + ((stats->size_sent * 8.0) / (1024.0 * 1024)) / > > passed_mm_time, > > + stats->size_sent / 1000.0 / stats->num_frames_sent, > > + encoder_stats.avg_quality, > > + encoder_stats.starting_bit_rate / (1024.0 * 1024), > > + encoder_stats.cur_bit_rate / (1024.0 * 1024)); > > +#endif > > +} > > + > > +StreamClipItem *stream_clip_item_new(DisplayChannelClient* dcc, > > StreamAgent *agent) > > +{ > > + StreamClipItem *item = spice_new(StreamClipItem, 1); > > + red_channel_pipe_item_init(RED_CHANNEL_CLIENT(dcc)->channel, > > + (PipeItem *)item, > > PIPE_ITEM_TYPE_STREAM_CLIP); > > + > > + item->stream_agent = agent; > > + agent->stream->refs++; > > + item->refs = 1; > > + return item; > > +} > > diff --git a/server/stream.h b/server/stream.h > > new file mode 100644 > > index 0000000..4b85fb8 > > --- /dev/null > > +++ b/server/stream.h > > @@ -0,0 +1,143 @@ > > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > > +/* > > + Copyright (C) 2009-2015 Red Hat, Inc. > > + > > + This library is free software; you can redistribute it and/or > > + modify it under the terms of the GNU Lesser General Public > > + License as published by the Free Software Foundation; either > > + version 2.1 of the License, or (at your option) any later > > version. > > + > > + This library is distributed in the hope that it will be useful, > > + but WITHOUT ANY WARRANTY; without even the implied warranty of > > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + Lesser General Public License for more details. > > + > > + You should have received a copy of the GNU Lesser General Public > > + License along with this library; if not, see < > > http://www.gnu.org/licenses/>;;. > > +*/ > > +#ifndef STREAM_H_ > > +#define STREAM_H_ > > + > > +#include <glib.h> > > +#include "utils.h" > > +#include "mjpeg_encoder.h" > > +#include "common/region.h" > > +#include "red_channel.h" > > + > > +/* FIXME: move back to display_channel.h (once structs are private) > > */ > > +typedef struct Drawable Drawable; > > +typedef struct DisplayChannelClient DisplayChannelClient; > > + > > + > > +#define RED_STREAM_DETACTION_MAX_DELTA ((1000 * 1000 * 1000) / 5) // > > 1/5 sec > > +#define RED_STREAM_CONTINUS_MAX_DELTA (1000 * 1000 * 1000) > > +#define RED_STREAM_TIMEOUT (1000 * 1000 * 1000) > > +#define RED_STREAM_FRAMES_START_CONDITION 20 > > +#define RED_STREAM_GRADUAL_FRAMES_START_CONDITION 0.2 > > +#define RED_STREAM_FRAMES_RESET_CONDITION 100 > > +#define RED_STREAM_MIN_SIZE (96 * 96) > > +#define RED_STREAM_INPUT_FPS_TIMEOUT ((uint64_t)5 * 1000 * 1000 * > > 1000) // 5 sec > > +#define RED_STREAM_CHANNEL_CAPACITY 0.8 > > +/* the client's stream report frequency is the minimum of the 2 > > values below */ > > +#define RED_STREAM_CLIENT_REPORT_WINDOW 5 // #frames > > +#define RED_STREAM_CLIENT_REPORT_TIMEOUT 1000 // milliseconds > > +#define RED_STREAM_DEFAULT_HIGH_START_BIT_RATE (10 * 1024 * 1024) // > > 10Mbps > > +#define RED_STREAM_DEFAULT_LOW_START_BIT_RATE (2.5 * 1024 * 1024) // > > 2.5Mbps > > + > > +typedef struct Stream Stream; > > + > > +typedef struct StreamActivateReportItem { > > + PipeItem pipe_item; > > + uint32_t stream_id; > > +} StreamActivateReportItem; > > + > > +enum { > > + STREAM_FRAME_NONE, > > + STREAM_FRAME_NATIVE, > > + STREAM_FRAME_CONTAINER, > > +}; > > + > > +#define STREAM_STATS > > +#ifdef STREAM_STATS > > +typedef struct StreamStats { > > + uint64_t num_drops_pipe; > > + uint64_t num_drops_fps; > > + uint64_t num_frames_sent; > > + uint64_t num_input_frames; > > + uint64_t size_sent; > > + > > + uint64_t start; > > + uint64_t end; > > +} StreamStats; > > +#endif > > + > > +typedef struct StreamAgent { > > + QRegion vis_region; /* the part of the surface area that is > > currently occupied by video > > + fragments */ > > + QRegion clip; /* the current video clipping. It can be > > different from vis_region: > > + for example, let c1 be the clip area at > > time t1, and c2 > > + be the clip area at time t2, where t1 < > > t2. If c1 contains c2, and > > + at least part of c1/c2, hasn't been > > covered by a non-video images, > > + vis_region will contain c2 and also the > > part of c1/c2 that still > > + displays fragments of the video */ > > + > > + PipeItem create_item; > > + PipeItem destroy_item; > > + Stream *stream; > > + uint64_t last_send_time; > > + MJpegEncoder *mjpeg_encoder; > > + DisplayChannelClient *dcc; > > + > > + int frames; > > + int drops; > > + int fps; > > + > > + uint32_t report_id; > > + uint32_t client_required_latency; > > +#ifdef STREAM_STATS > > + StreamStats stats; > > +#endif > > +} StreamAgent; > > + > > +typedef struct StreamClipItem { > > + PipeItem base; > > + int refs; > > + StreamAgent *stream_agent; > > + int clip_type; > > + SpiceClipRects *rects; > > +} StreamClipItem; > > + > > +StreamClipItem * stream_clip_item_new > > (DisplayChannelClient* dcc, > > + > > StreamAgent *agent); > > + > > +typedef struct ItemTrace { > > + red_time_t time; > > + int frames_count; > > + int gradual_frames_count; > > + int last_gradual_frame; > > + int width; > > + int height; > > + SpiceRect dest_area; > > +} ItemTrace; > > + > > +typedef struct Stream Stream; > > +struct Stream { > > + uint8_t refs; > > + Drawable *current; > > + red_time_t last_time; > > + int width; > > + int height; > > + SpiceRect dest_area; > > + int top_down; > > + Stream *next; > > + RingItem link; > > + > > + uint32_t num_input_frames; > > + uint64_t input_fps_start_time; > > + uint32_t input_fps; > > +}; > > + > > + > > +void stream_agent_stats_print > > (StreamAgent *agent); > > + > > +#endif /* STREAM_H */ > > diff --git a/server/utils.h b/server/utils.h > > index 1ebc32f..6750c1c 100644 > > --- a/server/utils.h > > +++ b/server/utils.h > > @@ -18,6 +18,7 @@ > > #ifndef UTILS_H_ > > # define UTILS_H_ > > > > +#include <stdint.h> > > #include <time.h> > > > > typedef int64_t red_time_t; > > > This last hunk seems unrelated. Should be split into a separate > commit. > _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel