[Spice-devel] [PATCH 10/11] Move stream functions to stream.[ch]
Jonathon Jongsma
jjongsma at redhat.com
Mon Nov 16 08:55:42 PST 2015
On Mon, 2015-11-16 at 15:02 +0100, Fabiano FidĂȘncio wrote:
> On Mon, Nov 16, 2015 at 12:06 PM, Frediano Ziglio <fziglio at redhat.com> wrote:
> > From: Jonathon Jongsma <jjongsma at redhat.com>
> >
> > ---
> > server/display-channel.h | 5 +
> > server/red_worker.c | 376 +-------------------------------------------
> > ---
> > server/stream.c | 359 ++++++++++++++++++++++++++++++++++++++++++++
> > server/stream.h | 9 ++
> > 4 files changed, 378 insertions(+), 371 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 e63828b..6a29e00 100644
> > --- a/server/red_worker.c
> > +++ b/server/red_worker.c
> > @@ -79,9 +79,6 @@
> >
> > #define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
> >
> > -#define FPS_TEST_INTERVAL 1
> > -#define MAX_FPS 30
> > -
> > #define ZLIB_DEFAULT_COMPRESSION_LEVEL 3
> > #define MIN_GLZ_SIZE_FOR_ZLIB 100
> >
> > @@ -286,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);
> > @@ -305,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)
> > @@ -1025,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);
> > }
> > @@ -1130,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);
> > @@ -1342,17 +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 uint64_t red_stream_get_initial_bit_rate(DisplayChannelClient *dcc,
> > Stream *stream)
> > {
> > @@ -1528,47 +1508,6 @@ void dcc_create_stream(DisplayChannelClient *dcc,
> > Stream *stream)
> > #endif
> > }
> >
> > -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;
> > @@ -1613,256 +1552,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;
> > @@ -1884,7 +1573,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);
> > @@ -1958,61 +1647,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;
> > @@ -2109,7 +1743,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 d61cec1..54f81a8 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
> > @@ -138,3 +144,356 @@ StreamClipItem
> > *stream_clip_item_new(DisplayChannelClient* dcc, StreamAgent *age
> > item->refs = 1;
> > 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);
> > + }
> > + }
> > +}
> > diff --git a/server/stream.h b/server/stream.h
> > index 4704937..bf78137 100644
> > --- a/server/stream.h
> > +++ b/server/stream.h
> > @@ -39,6 +39,7 @@
> > #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 MAX_FPS 30
> >
> > /* move back to display_channel once struct private */
> > typedef struct DisplayChannel DisplayChannel;
> > @@ -143,5 +144,13 @@ void stream_unref
> > (DisplayChan
> > void stream_agent_unref
> > (DisplayChannel *display,
> >
> > StreamAgent *agent);
> > void stream_agent_stats_print
> > (StreamAgent *agent);
> > +void stream_trace_update
> > (DisplayChannel *display,
> > +
> > Drawable *drawable);
> > +void stream_maintenance
> > (DisplayChannel *display,
> > +
> > Drawable *candidate,
> > +
> > Drawable *prev);
> > +
> > +void attach_stream(DisplayChannel *display, Drawable *drawable, Stream
> > *stream);
> > +void detach_stream(DisplayChannel *display, Stream *stream, int
> > detach_sized);
> >
> > #endif /* STREAM_H */
> > --
> > 2.4.3
> >
> > _______________________________________________
> > Spice-devel mailing list
> > Spice-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/spice-devel
>
> The patch is huge, but it's pretty much just moving things around.
> From a few simple tests (both with Linux and Windows guests) it
> doesn't seem to break anything.
> ACK.
I just noticed that this (split) commit now has basically the same name as patch
01/11 in this same series. Should I change the commit log?
More information about the Spice-devel
mailing list