[Spice-devel] [PATCH 14/19] worker: move more stream functions

Fabiano Fidêncio fidencio at redhat.com
Thu Nov 26 01:49:07 PST 2015


On Wed, Nov 25, 2015 at 4:27 PM, Frediano Ziglio <fziglio at redhat.com> wrote:
> From: Marc-André Lureau <marcandre.lureau at gmail.com>
>
> ---
>  server/dcc.c        |  14 +++++
>  server/dcc.h        |   2 +
>  server/red_worker.c | 177 +---------------------------------------------------
>  server/stream.c     | 159 ++++++++++++++++++++++++++++++++++++++++++++++
>  server/stream.h     |   2 +
>  5 files changed, 179 insertions(+), 175 deletions(-)
>
> diff --git a/server/dcc.c b/server/dcc.c
> index 6e8c876..78452f4 100644
> --- a/server/dcc.c
> +++ b/server/dcc.c
> @@ -43,6 +43,20 @@ static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
>      return create;
>  }
>
> +int dcc_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
> +{
> +    DrawablePipeItem *dpi;
> +    RingItem *dpi_link, *dpi_next;
> +
> +    DRAWABLE_FOREACH_DPI_SAFE(drawable, dpi_link, dpi_next, dpi) {
> +        if (dpi->dcc == dcc) {
> +            return TRUE;
> +        }
> +    }
> +
> +    return FALSE;
> +}
> +
>  /*
>   * Return: TRUE if wait_if_used == FALSE, or otherwise, if all of the pipe items that
>   * are related to the surface have been cleared (or sent) from the pipe.
> diff --git a/server/dcc.h b/server/dcc.h
> index 2351d55..14981ca 100644
> --- a/server/dcc.h
> +++ b/server/dcc.h
> @@ -205,6 +205,8 @@ void                       dcc_send_item                             (DisplayCha
>                                                                        PipeItem *item);
>  int                        dcc_clear_surface_drawables_from_pipe     (DisplayChannelClient *dcc,
>                                                                        int surface_id, int force);
> +int                        dcc_drawable_is_in_pipe                   (DisplayChannelClient *dcc,
> +                                                                      Drawable *drawable);
>
>  typedef struct compress_send_data_t {
>      void*    comp_buf;
> diff --git a/server/red_worker.c b/server/red_worker.c
> index 0236f68..b308e97 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -266,166 +266,6 @@ void current_remove_all(DisplayChannel *display, int surface_id)
>      }
>  }
>
> -static int red_display_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
> -{
> -    DrawablePipeItem *dpi;
> -    RingItem *dpi_link, *dpi_next;
> -
> -    DRAWABLE_FOREACH_DPI_SAFE(drawable, dpi_link, dpi_next, dpi) {
> -        if (dpi->dcc == dcc) {
> -            return TRUE;
> -        }
> -    }
> -
> -    return FALSE;
> -}
> -
> -/*
> - * after dcc_detach_stream_gracefully is called for all the display channel clients,
> - * detach_stream should be called. See comment (1).
> - */
> -static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
> -                                         Stream *stream,
> -                                         Drawable *update_area_limit)
> -{
> -    DisplayChannel *display = DCC_TO_DC(dcc);
> -    int stream_id = get_stream_id(display, stream);
> -    StreamAgent *agent = &dcc->stream_agents[stream_id];
> -
> -    /* stopping the client from playing older frames at once*/
> -    region_clear(&agent->clip);
> -    dcc_stream_agent_clip(dcc, agent);
> -
> -    if (region_is_empty(&agent->vis_region)) {
> -        spice_debug("stream %d: vis region empty", stream_id);
> -        return;
> -    }
> -
> -    if (stream->current &&
> -        region_contains(&stream->current->tree_item.base.rgn, &agent->vis_region)) {
> -        RedChannel *channel;
> -        RedChannelClient *rcc;
> -        UpgradeItem *upgrade_item;
> -        int n_rects;
> -
> -        /* (1) The caller should detach the drawable from the stream. This will
> -         * lead to sending the drawable losslessly, as an ordinary drawable. */
> -        if (red_display_drawable_is_in_pipe(dcc, stream->current)) {
> -            spice_debug("stream %d: upgrade by linked drawable. sized %d, box ==>",
> -                        stream_id, stream->current->sized_stream != NULL);
> -            rect_debug(&stream->current->red_drawable->bbox);
> -            goto clear_vis_region;
> -        }
> -        spice_debug("stream %d: upgrade by drawable. sized %d, box ==>",
> -                    stream_id, stream->current->sized_stream != NULL);
> -        rect_debug(&stream->current->red_drawable->bbox);
> -        rcc = RED_CHANNEL_CLIENT(dcc);
> -        channel = rcc->channel;
> -        upgrade_item = spice_new(UpgradeItem, 1);
> -        upgrade_item->refs = 1;
> -        red_channel_pipe_item_init(channel,
> -                &upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
> -        upgrade_item->drawable = stream->current;
> -        upgrade_item->drawable->refs++;
> -        n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
> -        upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
> -        upgrade_item->rects->num_rects = n_rects;
> -        region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn,
> -                         upgrade_item->rects->rects, n_rects);
> -        red_channel_client_pipe_add(rcc, &upgrade_item->base);
> -
> -    } else {
> -        SpiceRect upgrade_area;
> -
> -        region_extents(&agent->vis_region, &upgrade_area);
> -        spice_debug("stream %d: upgrade by screenshot. has current %d. box ==>",
> -                    stream_id, stream->current != NULL);
> -        rect_debug(&upgrade_area);
> -        if (update_area_limit) {
> -            display_channel_draw_until(DCC_TO_DC(dcc), &upgrade_area, 0, update_area_limit);
> -        } else {
> -            display_channel_draw(DCC_TO_DC(dcc), &upgrade_area, 0);
> -        }
> -        dcc_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
> -    }
> -clear_vis_region:
> -    region_clear(&agent->vis_region);
> -}
> -
> -static void detach_stream_gracefully(DisplayChannel *display, Stream *stream,
> -                                     Drawable *update_area_limit)
> -{
> -    RingItem *item, *next;
> -    DisplayChannelClient *dcc;
> -
> -    FOREACH_DCC(display, item, next, dcc) {
> -        dcc_detach_stream_gracefully(dcc, stream, update_area_limit);
> -    }
> -    if (stream->current) {
> -        detach_stream(display, stream, TRUE);
> -    }
> -}
> -
> -/*
> - * region  : a primary surface region. Streams that intersects with the given
> - *           region will be detached.
> - * drawable: If detaching the stream is triggered by the addition of a new drawable
> - *           that is dependent on the given region, and the drawable is already a part
> - *           of the "current tree", the drawable parameter should be set with
> - *           this drawable, otherwise, it should be NULL. Then, if detaching the stream
> - *           involves sending an upgrade image to the client, this drawable won't be rendered
> - *           (see dcc_detach_stream_gracefully).
> - */
> -void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable)
> -{
> -    Ring *ring = &display->streams;
> -    RingItem *item = ring_get_head(ring);
> -    RingItem *dcc_ring_item, *next;
> -    DisplayChannelClient *dcc;
> -    bool is_connected = red_channel_is_connected(RED_CHANNEL(display));
> -
> -    while (item) {
> -        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> -        int detach = 0;
> -        item = ring_next(ring, item);
> -
> -        FOREACH_DCC(display, dcc_ring_item, next, dcc) {
> -            StreamAgent *agent = &dcc->stream_agents[get_stream_id(display, stream)];
> -
> -            if (region_intersects(&agent->vis_region, region)) {
> -                dcc_detach_stream_gracefully(dcc, stream, drawable);
> -                detach = 1;
> -                spice_debug("stream %d", get_stream_id(display, stream));
> -            }
> -        }
> -        if (detach && stream->current) {
> -            detach_stream(display, stream, TRUE);
> -        } else if (!is_connected) {
> -            if (stream->current &&
> -                region_intersects(&stream->current->tree_item.base.rgn, region)) {
> -                detach_stream(display, stream, TRUE);
> -            }
> -        }
> -    }
> -}
> -
> -static void display_channel_streams_timeout(DisplayChannel *display)
> -{
> -    Ring *ring = &display->streams;
> -    RingItem *item;
> -
> -    red_time_t now = red_get_monotonic_time();
> -    item = ring_get_head(ring);
> -    while (item) {
> -        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> -        item = ring_next(ring, item);
> -        if (now >= (stream->last_time + RED_STREAM_TIMEOUT)) {
> -            detach_stream_gracefully(display, stream, NULL);
> -            stream_stop(display, stream);
> -        }
> -    }
> -}
> -
>  static void red_process_draw(RedWorker *worker, RedDrawable *red_drawable,
>                               uint32_t group_id)
>  {
> @@ -687,19 +527,6 @@ void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
>      red_channel_apply_clients(channel, red_channel_client_disconnect);
>  }
>
> -static void detach_and_stop_streams(DisplayChannel *display)
> -{
> -    RingItem *stream_item;
> -
> -    spice_debug(NULL);
> -    while ((stream_item = ring_get_head(&display->streams))) {
> -        Stream *stream = SPICE_CONTAINEROF(stream_item, Stream, link);
> -
> -        detach_stream_gracefully(display, stream, NULL);
> -        stream_stop(display, stream);
> -    }
> -}
> -
>  static void red_migrate_display(DisplayChannel *display, RedChannelClient *rcc)
>  {
>      /* We need to stop the streams, and to send upgrade_items to the client.
> @@ -712,7 +539,7 @@ static void red_migrate_display(DisplayChannel *display, RedChannelClient *rcc)
>       * Notice that detach_and_stop_streams won't lead to any dev ram changes, since
>       * handle_dev_stop already took care of releasing all the dev ram resources.
>       */
> -    detach_and_stop_streams(display);
> +    stream_detach_and_stop(display);
>      if (red_channel_client_is_connected(rcc)) {
>          red_channel_client_default_migrate(rcc);
>      }
> @@ -2007,7 +1834,7 @@ SPICE_GNUC_NORETURN static void *red_worker_main(void *arg)
>          timeout = display_channel_get_streams_timeout(worker->display_channel);
>          worker->event_timeout = MIN(timeout, worker->event_timeout);
>          num_events = poll(worker->poll_fds, MAX_EVENT_SOURCES, worker->event_timeout);
> -        display_channel_streams_timeout(worker->display_channel);
> +        stream_timeout(worker->display_channel);
>          spice_timer_queue_cb();
>
>          if (worker->display_channel) {
> diff --git a/server/stream.c b/server/stream.c
> index 85136ea..08224d8 100644
> --- a/server/stream.c
> +++ b/server/stream.c
> @@ -745,3 +745,162 @@ void stream_agent_stop(StreamAgent *agent)
>          agent->mjpeg_encoder = NULL;
>      }
>  }
> +
> +/*
> + * after dcc_detach_stream_gracefully is called for all the display channel clients,
> + * detach_stream should be called. See comment (1).
> + */
> +static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
> +                                         Stream *stream,
> +                                         Drawable *update_area_limit)
> +{
> +    DisplayChannel *display = DCC_TO_DC(dcc);
> +    int stream_id = get_stream_id(display, stream);
> +    StreamAgent *agent = &dcc->stream_agents[stream_id];
> +
> +    /* stopping the client from playing older frames at once*/
> +    region_clear(&agent->clip);
> +    dcc_stream_agent_clip(dcc, agent);
> +
> +    if (region_is_empty(&agent->vis_region)) {
> +        spice_debug("stream %d: vis region empty", stream_id);
> +        return;
> +    }
> +
> +    if (stream->current &&
> +        region_contains(&stream->current->tree_item.base.rgn, &agent->vis_region)) {
> +        RedChannel *channel;
> +        RedChannelClient *rcc;
> +        UpgradeItem *upgrade_item;
> +        int n_rects;
> +
> +        /* (1) The caller should detach the drawable from the stream. This will
> +         * lead to sending the drawable losslessly, as an ordinary drawable. */
> +        if (dcc_drawable_is_in_pipe(dcc, stream->current)) {
> +            spice_debug("stream %d: upgrade by linked drawable. sized %d, box ==>",
> +                        stream_id, stream->current->sized_stream != NULL);
> +            rect_debug(&stream->current->red_drawable->bbox);
> +            goto clear_vis_region;
> +        }
> +        spice_debug("stream %d: upgrade by drawable. sized %d, box ==>",
> +                    stream_id, stream->current->sized_stream != NULL);
> +        rect_debug(&stream->current->red_drawable->bbox);
> +        rcc = RED_CHANNEL_CLIENT(dcc);
> +        channel = rcc->channel;
> +        upgrade_item = spice_new(UpgradeItem, 1);
> +        upgrade_item->refs = 1;
> +        red_channel_pipe_item_init(channel,
> +                &upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
> +        upgrade_item->drawable = stream->current;
> +        upgrade_item->drawable->refs++;
> +        n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
> +        upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
> +        upgrade_item->rects->num_rects = n_rects;
> +        region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn,
> +                         upgrade_item->rects->rects, n_rects);
> +        red_channel_client_pipe_add(rcc, &upgrade_item->base);
> +
> +    } else {
> +        SpiceRect upgrade_area;
> +
> +        region_extents(&agent->vis_region, &upgrade_area);
> +        spice_debug("stream %d: upgrade by screenshot. has current %d. box ==>",
> +                    stream_id, stream->current != NULL);
> +        rect_debug(&upgrade_area);
> +        if (update_area_limit) {
> +            display_channel_draw_until(DCC_TO_DC(dcc), &upgrade_area, 0, update_area_limit);
> +        } else {
> +            display_channel_draw(DCC_TO_DC(dcc), &upgrade_area, 0);
> +        }
> +        dcc_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
> +    }
> +clear_vis_region:
> +    region_clear(&agent->vis_region);
> +}
> +
> +static void detach_stream_gracefully(DisplayChannel *display, Stream *stream,
> +                                     Drawable *update_area_limit)
> +{
> +    RingItem *item, *next;
> +    DisplayChannelClient *dcc;
> +
> +    FOREACH_DCC(display, item, next, dcc) {
> +        dcc_detach_stream_gracefully(dcc, stream, update_area_limit);
> +    }
> +    if (stream->current) {
> +        detach_stream(display, stream, TRUE);
> +    }
> +}
> +
> +/*
> + * region  : a primary surface region. Streams that intersects with the given
> + *           region will be detached.
> + * drawable: If detaching the stream is triggered by the addition of a new drawable
> + *           that is dependent on the given region, and the drawable is already a part
> + *           of the "current tree", the drawable parameter should be set with
> + *           this drawable, otherwise, it should be NULL. Then, if detaching the stream
> + *           involves sending an upgrade image to the client, this drawable won't be rendered
> + *           (see dcc_detach_stream_gracefully).
> + */
> +void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable)
> +{

If we are moving this function here, would be nice to move its
declaration to stream.h, see:
http://paste.fedoraproject.org/294691/14485312

> +    Ring *ring = &display->streams;
> +    RingItem *item = ring_get_head(ring);
> +    RingItem *dcc_ring_item, *next;
> +    DisplayChannelClient *dcc;
> +    bool is_connected = red_channel_is_connected(RED_CHANNEL(display));
> +
> +    while (item) {
> +        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> +        int detach = 0;
> +        item = ring_next(ring, item);
> +
> +        FOREACH_DCC(display, dcc_ring_item, next, dcc) {
> +            StreamAgent *agent = &dcc->stream_agents[get_stream_id(display, stream)];
> +
> +            if (region_intersects(&agent->vis_region, region)) {
> +                dcc_detach_stream_gracefully(dcc, stream, drawable);
> +                detach = 1;
> +                spice_debug("stream %d", get_stream_id(display, stream));
> +            }
> +        }
> +        if (detach && stream->current) {
> +            detach_stream(display, stream, TRUE);
> +        } else if (!is_connected) {
> +            if (stream->current &&
> +                region_intersects(&stream->current->tree_item.base.rgn, region)) {
> +                detach_stream(display, stream, TRUE);
> +            }
> +        }
> +    }
> +}
> +
> +void stream_detach_and_stop(DisplayChannel *display)
> +{
> +    RingItem *stream_item;
> +
> +    spice_debug(NULL);
> +    while ((stream_item = ring_get_head(&display->streams))) {
> +        Stream *stream = SPICE_CONTAINEROF(stream_item, Stream, link);
> +
> +        detach_stream_gracefully(display, stream, NULL);
> +        stream_stop(display, stream);
> +    }
> +}
> +
> +void stream_timeout(DisplayChannel *display)
> +{
> +    Ring *ring = &display->streams;
> +    RingItem *item;
> +
> +    red_time_t now = red_get_monotonic_time();
> +    item = ring_get_head(ring);
> +    while (item) {
> +        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
> +        item = ring_next(ring, item);
> +        if (now >= (stream->last_time + RED_STREAM_TIMEOUT)) {
> +            detach_stream_gracefully(display, stream, NULL);
> +            stream_stop(display, stream);
> +        }
> +    }
> +}
> diff --git a/server/stream.h b/server/stream.h
> index 3565514..35cbf5f 100644
> --- a/server/stream.h
> +++ b/server/stream.h
> @@ -155,6 +155,8 @@ void                  stream_trace_update                           (DisplayChan
>  void                  stream_maintenance                            (DisplayChannel *display,
>                                                                       Drawable *candidate,
>                                                                       Drawable *prev);
> +void                  stream_timeout                                (DisplayChannel *display);
> +void                  stream_detach_and_stop                        (DisplayChannel *display);
>
>  void                  stream_agent_unref                            (DisplayChannel *display,
>                                                                       StreamAgent *agent);
> --
> 2.4.3
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel

Acked-by: Fabiano Fidêncio <fidencio at redhat.com>


More information about the Spice-devel mailing list