[Spice-devel] [PATCH 6/9] Move stream creation and maintenance functions to stream.[ch]
Jonathon Jongsma
jjongsma at redhat.com
Tue Nov 17 12:03:56 PST 2015
I think Fabiano already ACKed this one. It just has a slightly more explicit
commit log subject now.
On Tue, 2015-11-17 at 16:37 +0000, Frediano Ziglio wrote:
> From: Jonathon Jongsma <jjongsma at redhat.com>
>
> ---
> server/display-channel.h | 5 +
> server/red_worker.c | 375 +---------------------------------------------
> -
> server/stream.c | 359 +++++++++++++++++++++++++++++++++++++++++++++
> server/stream.h | 9 ++
> 4 files changed, 378 insertions(+), 370 deletions(-)
>
> diff --git a/server/display-channel.h b/server/display-channel.h
> index ae8a900..26b4e4e 100644
> --- a/server/display-channel.h
> +++ b/server/display-channel.h
> @@ -166,6 +166,11 @@ struct Drawable {
> uint32_t process_commands_generation;
> };
>
> +#define LINK_TO_DPI(ptr) SPICE_CONTAINEROF((ptr), DrawablePipeItem, base)
> +#define DRAWABLE_FOREACH_DPI_SAFE(drawable, link, next, dpi) \
> + SAFE_FOREACH(link, next, drawable, &(drawable)->pipes, dpi,
> LINK_TO_DPI(link))
> +
> +
> struct DisplayChannelClient {
> CommonChannelClient common;
> SpiceImageCompression image_compression;
> diff --git a/server/red_worker.c b/server/red_worker.c
> index 5269752..1c2ab67 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -79,8 +79,6 @@
>
> #define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
>
> -#define FPS_TEST_INTERVAL 1
> -
> #define ZLIB_DEFAULT_COMPRESSION_LEVEL 3
> #define MIN_GLZ_SIZE_FOR_ZLIB 100
>
> @@ -285,8 +283,6 @@ static void red_draw_drawable(DisplayChannel *display,
> Drawable *item);
> static void red_update_area(DisplayChannel *display, const SpiceRect *area,
> int surface_id);
> static void red_update_area_till(DisplayChannel *display, const SpiceRect
> *area, int surface_id,
> Drawable *last);
> -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);
> @@ -304,10 +300,6 @@ static void red_create_surface(DisplayChannel *display,
> uint32_t surface_id, uin
> uint32_t height, int32_t stride, uint32_t
> format,
> void *line_0, int data_is_valid, int
> send_client);
>
> -#define LINK_TO_DPI(ptr) SPICE_CONTAINEROF((ptr), DrawablePipeItem, base)
> -#define DRAWABLE_FOREACH_DPI_SAFE(drawable, link, next, dpi) \
> - SAFE_FOREACH(link, next, drawable, &(drawable)->pipes, dpi,
> LINK_TO_DPI(link))
> -
>
> #define LINK_TO_GLZ(ptr) SPICE_CONTAINEROF((ptr), RedGlzDrawable, \
> drawable_link)
> @@ -1024,7 +1016,7 @@ static void __exclude_region(DisplayChannel *display,
> Ring *ring, TreeItem *item
> } else {
> if (frame_candidate) {
> Drawable *drawable = SPICE_CONTAINEROF(draw, Drawable,
> tree_item);
> - display_channel_stream_maintenance(display,
> frame_candidate, drawable);
> + stream_maintenance(display, frame_candidate, drawable);
> }
> region_exclude(&draw->base.rgn, &and_rgn);
> }
> @@ -1129,8 +1121,8 @@ static void current_add_drawable(DisplayChannel
> *display,
> drawable->refs++;
> }
>
> -static void detach_stream(DisplayChannel *display, Stream *stream,
> - int detach_sized)
> +void detach_stream(DisplayChannel *display, Stream *stream,
> + int detach_sized)
> {
> spice_assert(stream->current && stream->current->stream);
> spice_assert(stream->current->stream == stream);
> @@ -1341,58 +1333,6 @@ static void
> display_channel_streams_timeout(DisplayChannel *display)
> }
> }
>
> -static Stream *display_channel_stream_try_new(DisplayChannel *display)
> -{
> - Stream *stream;
> - if (!display->free_streams) {
> - return NULL;
> - }
> - stream = display->free_streams;
> - display->free_streams = display->free_streams->next;
> - return stream;
> -}
> -
> -static void display_channel_create_stream(DisplayChannel *display, Drawable
> *drawable)
> -{
> - DisplayChannelClient *dcc;
> - RingItem *dcc_ring_item, *next;
> - Stream *stream;
> - SpiceRect* src_rect;
> -
> - spice_assert(!drawable->stream);
> -
> - 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(&display->streams, &stream->link);
> - stream->current = drawable;
> - stream->last_time = drawable->creation_time;
> - stream->width = src_rect->right - src_rect->left;
> - stream->height = src_rect->bottom - src_rect->top;
> - stream->dest_area = drawable->red_drawable->bbox;
> - stream->refs = 1;
> - SpiceBitmap *bitmap = &drawable->red_drawable->u.copy.src_bitmap
> ->u.bitmap;
> - stream->top_down = !!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN);
> - drawable->stream = stream;
> - stream->input_fps = MAX_FPS;
> - stream->num_input_frames = 0;
> - stream->input_fps_start_time = drawable->creation_time;
> - 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 - 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 dcc_create_all_streams(DisplayChannelClient *dcc)
> {
> Ring *ring = &DCC_TO_DC(dcc)->streams;
> @@ -1437,256 +1377,6 @@ static void
> dcc_destroy_stream_agents(DisplayChannelClient *dcc)
> }
> }
>
> -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;
> -
> - if (!candidate->streamable) {
> - return STREAM_FRAME_NONE;
> - }
> -
> - if (candidate->creation_time - other_time >
> - (stream ? RED_STREAM_CONTINUS_MAX_DELTA :
> RED_STREAM_DETACTION_MAX_DELTA)) {
> - return STREAM_FRAME_NONE;
> - }
> -
> - red_drawable = candidate->red_drawable;
> - if (!container_candidate_allowed) {
> - SpiceRect* candidate_src;
> -
> - if (!rect_is_equal(&red_drawable->bbox, other_dest)) {
> - return STREAM_FRAME_NONE;
> - }
> -
> - candidate_src = &red_drawable->u.copy.src_area;
> - if (candidate_src->right - candidate_src->left != other_src_width ||
> - candidate_src->bottom - candidate_src->top != other_src_height) {
> - return STREAM_FRAME_NONE;
> - }
> - } else {
> - if (rect_contains(&red_drawable->bbox, other_dest)) {
> - int candidate_area = rect_get_area(&red_drawable->bbox);
> - int other_area = rect_get_area(other_dest);
> - /* do not stream drawables that are significantly
> - * bigger than the original frame */
> - if (candidate_area > 2 * other_area) {
> - spice_debug("too big candidate:");
> - spice_debug("prev box ==>");
> - rect_debug(other_dest);
> - spice_debug("new box ==>");
> - rect_debug(&red_drawable->bbox);
> - return STREAM_FRAME_NONE;
> - }
> -
> - if (candidate_area > other_area) {
> - is_frame_container = TRUE;
> - }
> - } else {
> - return STREAM_FRAME_NONE;
> - }
> - }
> -
> - if (stream) {
> - SpiceBitmap *bitmap = &red_drawable->u.copy.src_bitmap->u.bitmap;
> - if (stream->top_down != !!(bitmap->flags &
> SPICE_BITMAP_FLAGS_TOP_DOWN)) {
> - return STREAM_FRAME_NONE;
> - }
> - }
> - if (is_frame_container) {
> - return STREAM_FRAME_CONTAINER;
> - } else {
> - return STREAM_FRAME_NATIVE;
> - }
> -}
> -
> -static void before_reattach_stream(DisplayChannel *display,
> - Stream *stream, Drawable *new_frame)
> -{
> - DrawablePipeItem *dpi;
> - DisplayChannelClient *dcc;
> - int index;
> - StreamAgent *agent;
> - RingItem *ring_item, *next;
> -
> - spice_return_if_fail(stream->current);
> -
> - if (!red_channel_is_connected(RED_CHANNEL(display))) {
> - return;
> - }
> -
> - if (new_frame->process_commands_generation == stream->current
> ->process_commands_generation) {
> - spice_debug("ignoring drop, same process_commands_generation as
> previous frame");
> - return;
> - }
> -
> - index = get_stream_id(display, stream);
> - DRAWABLE_FOREACH_DPI_SAFE(stream->current, ring_item, next, dpi) {
> - dcc = dpi->dcc;
> - agent = &dcc->stream_agents[index];
> -
> - if (!dcc->use_mjpeg_encoder_rate_control &&
> - !dcc->common.is_low_bandwidth) {
> - continue;
> - }
> -
> - if (pipe_item_is_linked(&dpi->dpi_pipe_item)) {
> -#ifdef STREAM_STATS
> - agent->stats.num_drops_pipe++;
> -#endif
> - if (dcc->use_mjpeg_encoder_rate_control) {
> - mjpeg_encoder_notify_server_frame_drop(agent->mjpeg_encoder);
> - } else {
> - ++agent->drops;
> - }
> - }
> - }
> -
> -
> - FOREACH_DCC(display, ring_item, next, dcc) {
> - double drop_factor;
> -
> - agent = &dcc->stream_agents[index];
> -
> - if (dcc->use_mjpeg_encoder_rate_control) {
> - continue;
> - }
> - if (agent->frames / agent->fps < FPS_TEST_INTERVAL) {
> - agent->frames++;
> - continue;
> - }
> - drop_factor = ((double)agent->frames - (double)agent->drops) /
> - (double)agent->frames;
> - spice_debug("stream %d: #frames %u #drops %u", index, agent->frames,
> agent->drops);
> - if (drop_factor == 1) {
> - if (agent->fps < MAX_FPS) {
> - agent->fps++;
> - spice_debug("stream %d: fps++ %u", index, agent->fps);
> - }
> - } else if (drop_factor < 0.9) {
> - if (agent->fps > 1) {
> - agent->fps--;
> - spice_debug("stream %d: fps--%u", index, agent->fps);
> - }
> - }
> - agent->frames = 1;
> - agent->drops = 0;
> - }
> -}
> -
> -static void update_copy_graduality(DisplayChannel *display, Drawable
> *drawable)
> -{
> - SpiceBitmap *bitmap;
> - spice_return_if_fail(drawable->red_drawable->type == QXL_DRAW_COPY);
> -
> - if (display->stream_video != SPICE_STREAM_VIDEO_FILTER) {
> - drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID;
> - return;
> - }
> -
> - if (drawable->copy_bitmap_graduality != BITMAP_GRADUAL_INVALID) {
> - return; // already set
> - }
> -
> - bitmap = &drawable->red_drawable->u.copy.src_bitmap->u.bitmap;
> -
> - if (!bitmap_fmt_has_graduality(bitmap->format) ||
> bitmap_has_extra_stride(bitmap) ||
> - (bitmap->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE)) {
> - drawable->copy_bitmap_graduality = BITMAP_GRADUAL_NOT_AVAIL;
> - } else {
> - drawable->copy_bitmap_graduality =
> bitmap_get_graduality_level(bitmap);
> - }
> -}
> -
> -static int is_stream_start(Drawable *drawable)
> -{
> - return ((drawable->frames_count >= RED_STREAM_FRAMES_START_CONDITION) &&
> - (drawable->gradual_frames_count >=
> - (RED_STREAM_GRADUAL_FRAMES_START_CONDITION * drawable
> ->frames_count)));
> -}
> -
> -// returns whether a stream was created
> -static int display_channel_stream_add_frame(DisplayChannel *display,
> - Drawable *frame_drawable,
> - int frames_count,
> - int gradual_frames_count,
> - int last_gradual_frame)
> -{
> - update_copy_graduality(display, frame_drawable);
> - frame_drawable->frames_count = frames_count + 1;
> - frame_drawable->gradual_frames_count = gradual_frames_count;
> -
> - if (frame_drawable->copy_bitmap_graduality != BITMAP_GRADUAL_LOW) {
> - if ((frame_drawable->frames_count - last_gradual_frame) >
> - RED_STREAM_FRAMES_RESET_CONDITION) {
> - frame_drawable->frames_count = 1;
> - frame_drawable->gradual_frames_count = 1;
> - } else {
> - frame_drawable->gradual_frames_count++;
> - }
> -
> - frame_drawable->last_gradual_frame = frame_drawable->frames_count;
> - } else {
> - frame_drawable->last_gradual_frame = last_gradual_frame;
> - }
> -
> - if (is_stream_start(frame_drawable)) {
> - display_channel_create_stream(display, frame_drawable);
> - return TRUE;
> - }
> - return FALSE;
> -}
> -
> -static void display_channel_stream_maintenance(DisplayChannel *display,
> - Drawable *candidate, Drawable
> *prev)
> -{
> - int is_next_frame;
> -
> - if (candidate->stream) {
> - return;
> - }
> -
> - 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) {
> - before_reattach_stream(display, stream, candidate);
> - detach_stream(display, stream, FALSE);
> - prev->streamable = FALSE; //prevent item trace
> - attach_stream(display, candidate, stream);
> - if (is_next_frame == STREAM_FRAME_CONTAINER) {
> - candidate->sized_stream = stream;
> - }
> - }
> - } 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);
> - }
> - }
> -}
> -
> static inline int red_current_add_equal(DisplayChannel *display, DrawItem
> *item, TreeItem *other)
> {
> DrawItem *other_draw_item;
> @@ -1708,7 +1398,7 @@ static inline int red_current_add_equal(DisplayChannel
> *display, DrawItem *item,
> if (item->effect == QXL_EFFECT_OPAQUE) {
> int add_after = !!other_drawable->stream &&
> is_drawable_independent_from_surfaces(drawable);
> - display_channel_stream_maintenance(display, drawable,
> other_drawable);
> + stream_maintenance(display, drawable, other_drawable);
> current_add_drawable(display, drawable, &other->siblings_link);
> other_drawable->refs++;
> current_remove_drawable(display, other_drawable);
> @@ -1782,61 +1472,6 @@ static inline int red_current_add_equal(DisplayChannel
> *display, DrawItem *item,
> return FALSE;
> }
>
> -#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;
> - RingItem *item;
> -
> - if (drawable->stream || !drawable->streamable || drawable->frames_count)
> {
> - return;
> - }
> -
> - FOREACH_STREAMS(display, item) {
> - Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> - 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
> - before_reattach_stream(display, stream, drawable);
> - detach_stream(display, stream, FALSE);
> - }
> - attach_stream(display, drawable, stream);
> - if (is_next_frame == STREAM_FRAME_CONTAINER) {
> - drawable->sized_stream = stream;
> - }
> - return;
> - }
> - }
> -
> - trace = display->items_trace;
> - trace_end = trace + NUM_TRACE_ITEMS;
> - for (; trace < trace_end; trace++) {
> - if (is_next_stream_frame(display, drawable, trace->width, trace
> ->height,
> - &trace->dest_area, trace->time, NULL,
> FALSE) !=
> - STREAM_FRAME_NONE) {
> - if (display_channel_stream_add_frame(display, drawable,
> - trace->frames_count,
> - trace->gradual_frames_count,
> - trace->last_gradual_frame))
> {
> - return;
> - }
> - }
> - }
> -}
> -
> static int current_add(DisplayChannel *display, Ring *ring, Drawable
> *drawable)
> {
> DrawItem *item = &drawable->tree_item;
> @@ -1933,7 +1568,7 @@ static int current_add(DisplayChannel *display, Ring
> *ring, Drawable *drawable)
> if (item->effect == QXL_EFFECT_OPAQUE) {
> region_or(&exclude_rgn, &item->base.rgn);
> exclude_region(display, ring, exclude_base, &exclude_rgn, NULL,
> drawable);
> - red_use_stream_trace(display, drawable);
> + stream_trace_update(display, drawable);
> streams_update_visible_region(display, drawable);
> /*
> * Performing the insertion after exclude_region for
> diff --git a/server/stream.c b/server/stream.c
> index 27d6d36..f242da7 100644
> --- a/server/stream.c
> +++ b/server/stream.c
> @@ -21,6 +21,12 @@
> #include "stream.h"
> #include "display-channel.h"
>
> +#define FPS_TEST_INTERVAL 1
> +#define FOREACH_STREAMS(display, item) \
> + for (item = ring_get_head(&(display)->streams); \
> + item != NULL; \
> + item = ring_next(&(display)->streams, item))
> +
> void stream_agent_stats_print(StreamAgent *agent)
> {
> #ifdef STREAM_STATS
> @@ -139,6 +145,359 @@ StreamClipItem
> *stream_clip_item_new(DisplayChannelClient* dcc, StreamAgent *age
> return item;
> }
>
> +static int is_stream_start(Drawable *drawable)
> +{
> + return ((drawable->frames_count >= RED_STREAM_FRAMES_START_CONDITION) &&
> + (drawable->gradual_frames_count >=
> + (RED_STREAM_GRADUAL_FRAMES_START_CONDITION * drawable
> ->frames_count)));
> +}
> +
> +static void update_copy_graduality(DisplayChannel *display, Drawable
> *drawable)
> +{
> + SpiceBitmap *bitmap;
> + spice_return_if_fail(drawable->red_drawable->type == QXL_DRAW_COPY);
> +
> + if (display->stream_video != SPICE_STREAM_VIDEO_FILTER) {
> + drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID;
> + return;
> + }
> +
> + if (drawable->copy_bitmap_graduality != BITMAP_GRADUAL_INVALID) {
> + return; // already set
> + }
> +
> + bitmap = &drawable->red_drawable->u.copy.src_bitmap->u.bitmap;
> +
> + if (!bitmap_fmt_has_graduality(bitmap->format) ||
> bitmap_has_extra_stride(bitmap) ||
> + (bitmap->data->flags & SPICE_CHUNKS_FLAGS_UNSTABLE)) {
> + drawable->copy_bitmap_graduality = BITMAP_GRADUAL_NOT_AVAIL;
> + } else {
> + drawable->copy_bitmap_graduality =
> bitmap_get_graduality_level(bitmap);
> + }
> +}
> +
> +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;
> +
> + if (!candidate->streamable) {
> + return STREAM_FRAME_NONE;
> + }
> +
> + if (candidate->creation_time - other_time >
> + (stream ? RED_STREAM_CONTINUS_MAX_DELTA :
> RED_STREAM_DETACTION_MAX_DELTA)) {
> + return STREAM_FRAME_NONE;
> + }
> +
> + red_drawable = candidate->red_drawable;
> + if (!container_candidate_allowed) {
> + SpiceRect* candidate_src;
> +
> + if (!rect_is_equal(&red_drawable->bbox, other_dest)) {
> + return STREAM_FRAME_NONE;
> + }
> +
> + candidate_src = &red_drawable->u.copy.src_area;
> + if (candidate_src->right - candidate_src->left != other_src_width ||
> + candidate_src->bottom - candidate_src->top != other_src_height) {
> + return STREAM_FRAME_NONE;
> + }
> + } else {
> + if (rect_contains(&red_drawable->bbox, other_dest)) {
> + int candidate_area = rect_get_area(&red_drawable->bbox);
> + int other_area = rect_get_area(other_dest);
> + /* do not stream drawables that are significantly
> + * bigger than the original frame */
> + if (candidate_area > 2 * other_area) {
> + spice_debug("too big candidate:");
> + spice_debug("prev box ==>");
> + rect_debug(other_dest);
> + spice_debug("new box ==>");
> + rect_debug(&red_drawable->bbox);
> + return STREAM_FRAME_NONE;
> + }
> +
> + if (candidate_area > other_area) {
> + is_frame_container = TRUE;
> + }
> + } else {
> + return STREAM_FRAME_NONE;
> + }
> + }
> +
> + if (stream) {
> + SpiceBitmap *bitmap = &red_drawable->u.copy.src_bitmap->u.bitmap;
> + if (stream->top_down != !!(bitmap->flags &
> SPICE_BITMAP_FLAGS_TOP_DOWN)) {
> + return STREAM_FRAME_NONE;
> + }
> + }
> + if (is_frame_container) {
> + return STREAM_FRAME_CONTAINER;
> + } else {
> + return STREAM_FRAME_NATIVE;
> + }
> +}
> +
> +static void before_reattach_stream(DisplayChannel *display,
> + Stream *stream, Drawable *new_frame)
> +{
> + DrawablePipeItem *dpi;
> + DisplayChannelClient *dcc;
> + int index;
> + StreamAgent *agent;
> + RingItem *ring_item, *next;
> +
> + spice_return_if_fail(stream->current);
> +
> + if (!red_channel_is_connected(RED_CHANNEL(display))) {
> + return;
> + }
> +
> + if (new_frame->process_commands_generation == stream->current
> ->process_commands_generation) {
> + spice_debug("ignoring drop, same process_commands_generation as
> previous frame");
> + return;
> + }
> +
> + index = get_stream_id(display, stream);
> + DRAWABLE_FOREACH_DPI_SAFE(stream->current, ring_item, next, dpi) {
> + dcc = dpi->dcc;
> + agent = &dcc->stream_agents[index];
> +
> + if (!dcc->use_mjpeg_encoder_rate_control &&
> + !dcc->common.is_low_bandwidth) {
> + continue;
> + }
> +
> + if (pipe_item_is_linked(&dpi->dpi_pipe_item)) {
> +#ifdef STREAM_STATS
> + agent->stats.num_drops_pipe++;
> +#endif
> + if (dcc->use_mjpeg_encoder_rate_control) {
> + mjpeg_encoder_notify_server_frame_drop(agent->mjpeg_encoder);
> + } else {
> + ++agent->drops;
> + }
> + }
> + }
> +
> +
> + FOREACH_DCC(display, ring_item, next, dcc) {
> + double drop_factor;
> +
> + agent = &dcc->stream_agents[index];
> +
> + if (dcc->use_mjpeg_encoder_rate_control) {
> + continue;
> + }
> + if (agent->frames / agent->fps < FPS_TEST_INTERVAL) {
> + agent->frames++;
> + continue;
> + }
> + drop_factor = ((double)agent->frames - (double)agent->drops) /
> + (double)agent->frames;
> + spice_debug("stream %d: #frames %u #drops %u", index, agent->frames,
> agent->drops);
> + if (drop_factor == 1) {
> + if (agent->fps < MAX_FPS) {
> + agent->fps++;
> + spice_debug("stream %d: fps++ %u", index, agent->fps);
> + }
> + } else if (drop_factor < 0.9) {
> + if (agent->fps > 1) {
> + agent->fps--;
> + spice_debug("stream %d: fps--%u", index, agent->fps);
> + }
> + }
> + agent->frames = 1;
> + agent->drops = 0;
> + }
> +}
> +
> +static Stream *display_channel_stream_try_new(DisplayChannel *display)
> +{
> + Stream *stream;
> + if (!display->free_streams) {
> + return NULL;
> + }
> + stream = display->free_streams;
> + display->free_streams = display->free_streams->next;
> + return stream;
> +}
> +
> +static void display_channel_create_stream(DisplayChannel *display, Drawable
> *drawable)
> +{
> + DisplayChannelClient *dcc;
> + RingItem *dcc_ring_item, *next;
> + Stream *stream;
> + SpiceRect* src_rect;
> +
> + spice_assert(!drawable->stream);
> +
> + 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(&display->streams, &stream->link);
> + stream->current = drawable;
> + stream->last_time = drawable->creation_time;
> + stream->width = src_rect->right - src_rect->left;
> + stream->height = src_rect->bottom - src_rect->top;
> + stream->dest_area = drawable->red_drawable->bbox;
> + stream->refs = 1;
> + SpiceBitmap *bitmap = &drawable->red_drawable->u.copy.src_bitmap
> ->u.bitmap;
> + stream->top_down = !!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN);
> + drawable->stream = stream;
> + stream->input_fps = MAX_FPS;
> + stream->num_input_frames = 0;
> + stream->input_fps_start_time = drawable->creation_time;
> + 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 - display->streams_buf), stream->width,
> + stream->height, stream->dest_area.left, stream
> ->dest_area.top,
> + stream->dest_area.right, stream->dest_area.bottom);
> + return;
> +}
> +
> +// returns whether a stream was created
> +static int stream_add_frame(DisplayChannel *display,
> + Drawable *frame_drawable,
> + int frames_count,
> + int gradual_frames_count,
> + int last_gradual_frame)
> +{
> + update_copy_graduality(display, frame_drawable);
> + frame_drawable->frames_count = frames_count + 1;
> + frame_drawable->gradual_frames_count = gradual_frames_count;
> +
> + if (frame_drawable->copy_bitmap_graduality != BITMAP_GRADUAL_LOW) {
> + if ((frame_drawable->frames_count - last_gradual_frame) >
> + RED_STREAM_FRAMES_RESET_CONDITION) {
> + frame_drawable->frames_count = 1;
> + frame_drawable->gradual_frames_count = 1;
> + } else {
> + frame_drawable->gradual_frames_count++;
> + }
> +
> + frame_drawable->last_gradual_frame = frame_drawable->frames_count;
> + } else {
> + frame_drawable->last_gradual_frame = last_gradual_frame;
> + }
> +
> + if (is_stream_start(frame_drawable)) {
> + display_channel_create_stream(display, frame_drawable);
> + return TRUE;
> + }
> + return FALSE;
> +}
> +
> +/* TODO: document the difference between the 2 functions below */
> +void stream_trace_update(DisplayChannel *display, Drawable *drawable)
> +{
> + ItemTrace *trace;
> + ItemTrace *trace_end;
> + RingItem *item;
> +
> + if (drawable->stream || !drawable->streamable || drawable->frames_count)
> {
> + return;
> + }
> +
> + FOREACH_STREAMS(display, item) {
> + Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> + 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
> + before_reattach_stream(display, stream, drawable);
> + detach_stream(display, stream, FALSE);
> + }
> + attach_stream(display, drawable, stream);
> + if (is_next_frame == STREAM_FRAME_CONTAINER) {
> + drawable->sized_stream = stream;
> + }
> + return;
> + }
> + }
> +
> + trace = display->items_trace;
> + trace_end = trace + NUM_TRACE_ITEMS;
> + for (; trace < trace_end; trace++) {
> + if (is_next_stream_frame(display, drawable, trace->width, trace
> ->height,
> + &trace->dest_area, trace->time, NULL,
> FALSE) !=
> + STREAM_FRAME_NONE) {
> + if (stream_add_frame(display, drawable,
> + trace->frames_count,
> + trace->gradual_frames_count,
> + trace->last_gradual_frame)) {
> + return;
> + }
> + }
> + }
> +}
> +
> +void stream_maintenance(DisplayChannel *display,
> + Drawable *candidate, Drawable *prev)
> +{
> + int is_next_frame;
> +
> + if (candidate->stream) {
> + return;
> + }
> +
> + 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) {
> + before_reattach_stream(display, stream, candidate);
> + detach_stream(display, stream, FALSE);
> + prev->streamable = FALSE; //prevent item trace
> + attach_stream(display, candidate, stream);
> + if (is_next_frame == STREAM_FRAME_CONTAINER) {
> + candidate->sized_stream = stream;
> + }
> + }
> + } 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) {
> + stream_add_frame(display, candidate,
> + prev->frames_count,
> + prev->gradual_frames_count,
> + prev->last_gradual_frame);
> + }
> + }
> +}
> +
> static void dcc_update_streams_max_latency(DisplayChannelClient *dcc,
> StreamAgent *remove_agent)
> {
> uint32_t new_max_latency = 0;
> diff --git a/server/stream.h b/server/stream.h
> index c2007af..0577dc8 100644
> --- a/server/stream.h
> +++ b/server/stream.h
> @@ -141,10 +141,19 @@ void stream_stop
> (DisplayChan
> Stream
> *stream);
> void stream_unref
> (DisplayChannel *display,
> Stream
> *stream);
> +void stream_trace_update
> (DisplayChannel *display,
> + Drawable
> *drawable);
> +void stream_maintenance
> (DisplayChannel *display,
> + Drawable
> *candidate,
> + Drawable
> *prev);
> +
> void stream_agent_unref
> (DisplayChannel *display,
>
> StreamAgent *agent);
> void stream_agent_stats_print
> (StreamAgent *agent);
> void stream_agent_stop
> (DisplayChannelClient *dcc,
>
> StreamAgent *agent);
>
> +void attach_stream(DisplayChannel *display, Drawable *drawable, Stream
> *stream);
> +void detach_stream(DisplayChannel *display, Stream *stream, int
> detach_sized);
> +
> #endif /* STREAM_H */
More information about the Spice-devel
mailing list