[Spice-devel] [PATCH 10/11] Move stream functions to stream.[ch]
Jonathon Jongsma
jjongsma at redhat.com
Tue Nov 17 08:19:49 PST 2015
On Tue, 2015-11-17 at 08:59 -0500, Frediano Ziglio wrote:
> >
> > 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?
> >
> >
>
> Well, describing the difference between the first set of function and these
> would be helpful.
>
> Frediano
How about "Move stream creation and maintenance functions to stream.[ch]"?
More information about the Spice-devel
mailing list