summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2013-10-01 16:53:31 +0200
committerFrediano Ziglio <fziglio@redhat.com>2015-11-26 15:19:03 +0000
commitd9b17bbebbec48c581746d9d4486cb4d90111679 (patch)
treef10a9f2d1933007e252c4b21715f96fe79de1adf
parentc26a825451293b9c14eb3bea6f618d51db9365d5 (diff)
worker: move more stream functions
Acked-by: Fabiano FidĂȘncio <fidencio@redhat.com>
-rw-r--r--server/dcc.c14
-rw-r--r--server/dcc.h2
-rw-r--r--server/display-channel.h1
-rw-r--r--server/red_worker.c177
-rw-r--r--server/stream.c159
-rw-r--r--server/stream.h3
6 files changed, 180 insertions, 176 deletions
diff --git a/server/dcc.c b/server/dcc.c
index 6e8c876a..78452f4f 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 c5767c9a..456ca235 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -203,6 +203,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/display-channel.h b/server/display-channel.h
index 81c11cd8..b909202a 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -448,7 +448,6 @@ static inline void draw_depend_on_me(DisplayChannel *display, uint32_t surface_i
void current_remove_drawable(DisplayChannel *display, Drawable *item);
void red_pipes_remove_drawable(Drawable *drawable);
void current_remove(DisplayChannel *display, TreeItem *item);
-void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable);
void current_remove_all(DisplayChannel *display, int surface_id);
#endif /* DISPLAY_CHANNEL_H_ */
diff --git a/server/red_worker.c b/server/red_worker.c
index 6ea7cd5b..9747cb04 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -329,166 +329,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_get_area(DisplayChannel *display, int surface_id, const SpiceRect *area,
uint8_t *dest, int dest_stride, int update)
{
@@ -3381,19 +3221,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.
@@ -3406,7 +3233,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);
}
@@ -4701,7 +4528,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 8d166586..e8b8f9bf 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -740,3 +740,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 7c589e42..a9abc824 100644
--- a/server/stream.h
+++ b/server/stream.h
@@ -148,6 +148,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);
@@ -155,5 +157,6 @@ void stream_agent_stats_print (StreamAgent
void stream_agent_stop (StreamAgent *agent);
void detach_stream(DisplayChannel *display, Stream *stream, int detach_sized);
+void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable);
#endif /* STREAM_H */