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) +{ + 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