[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