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

Frediano Ziglio fziglio at redhat.com
Wed Nov 25 07:27:38 PST 2015


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



More information about the Spice-devel mailing list