On Wed, Nov 25, 2015 at 4:27 PM, Frediano Ziglio <fziglio@xxxxxxxxxx> wrote: > From: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> > > --- > 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@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel Acked-by: Fabiano Fidêncio <fidencio@xxxxxxxxxx> _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel