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@xxxxxxxxxx> > > > wrote: > > > > From: Jonathon Jongsma <jjongsma@xxxxxxxxxx> > > > > > > > > --- > > > > 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@xxxxxxxxxxxxxxxxxxxxx > > > > 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]"? _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel