[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