[Spice-commits] 5 commits - server/dcc.c server/dcc.h server/display-channel.c server/display-channel.h server/red_worker.c

Frediano Ziglio fziglio at kemper.freedesktop.org
Wed Nov 25 06:15:52 PST 2015


 server/dcc.c             |  106 +++++++++
 server/dcc.h             |    5 
 server/display-channel.c |  341 +++++++++++++++++++++++++++++
 server/display-channel.h |   49 ++++
 server/red_worker.c      |  552 ++---------------------------------------------
 5 files changed, 525 insertions(+), 528 deletions(-)

New commits:
commit 7d38c28a0aef29567bf6b87188cbdd10a5fcb8e9
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Wed Nov 25 08:58:25 2015 +0100

    display: Remove extra parameters from create_canvas_for_surface
    
    Get them from the surface
    
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/server/display-channel.c b/server/display-channel.c
index 39d944f..1496f07 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -1538,16 +1538,14 @@ static void send_create_surface(DisplayChannel *display, int surface_id, int ima
 }
 
 static SpiceCanvas*
-create_canvas_for_surface(DisplayChannel *display, RedSurface *surface,
-                          uint32_t renderer, uint32_t width, uint32_t height,
-                          int32_t stride, uint32_t format, void *line_0)
+create_canvas_for_surface(DisplayChannel *display, RedSurface *surface, uint32_t renderer)
 {
     SpiceCanvas *canvas;
 
     switch (renderer) {
     case RED_RENDERER_SW:
-        canvas = canvas_create_for_data(width, height, format,
-                                        line_0, stride,
+        canvas = canvas_create_for_data(surface->context.width, surface->context.height, surface->context.format,
+                                        surface->context.line_0, surface->context.stride,
                                         &display->image_cache.base,
                                         &display->image_surfaces, NULL, NULL, NULL);
         surface->context.top_down = TRUE;
@@ -1590,9 +1588,7 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
     region_init(&surface->draw_dirty_region);
     surface->refs = 1;
     if (display->renderer != RED_RENDERER_INVALID) {
-        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderer,
-                                                            width, height, stride,
-                                                            surface->context.format, line_0);
+        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderer);
         if (!surface->context.canvas) {
             spice_critical("drawing canvas creating failed - can`t create same type canvas");
         }
@@ -1603,9 +1599,7 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
     }
 
     for (i = 0; i < display->num_renderers; i++) {
-        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderers[i],
-                                                            width, height, stride,
-                                                            surface->context.format, line_0);
+        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderers[i]);
         if (surface->context.canvas) { //no need canvas check
             display->renderer = display->renderers[i];
             if (send_client)
commit 4e35645fb05cb82e1f8b90215a5024a6d83f7474
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Fri Sep 27 19:10:03 2013 +0200

    worker: move display_channel_create_surface
    
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/display-channel.c b/server/display-channel.c
index 55dd37b..39d944f 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -1525,6 +1525,98 @@ void display_channel_destroy_surfaces(DisplayChannel *display)
     display_channel_free_glz_drawables(display);
 }
 
+static void send_create_surface(DisplayChannel *display, int surface_id, int image_ready)
+{
+    DisplayChannelClient *dcc;
+    RingItem *item, *next;
+
+    FOREACH_DCC(display, item, next, dcc) {
+        dcc_create_surface(dcc, surface_id);
+        if (image_ready)
+            dcc_push_surface_image(dcc, surface_id);
+    }
+}
+
+static SpiceCanvas*
+create_canvas_for_surface(DisplayChannel *display, RedSurface *surface,
+                          uint32_t renderer, uint32_t width, uint32_t height,
+                          int32_t stride, uint32_t format, void *line_0)
+{
+    SpiceCanvas *canvas;
+
+    switch (renderer) {
+    case RED_RENDERER_SW:
+        canvas = canvas_create_for_data(width, height, format,
+                                        line_0, stride,
+                                        &display->image_cache.base,
+                                        &display->image_surfaces, NULL, NULL, NULL);
+        surface->context.top_down = TRUE;
+        surface->context.canvas_draws_on_surface = TRUE;
+        return canvas;
+    default:
+        spice_warn_if_reached();
+    };
+
+    return NULL;
+}
+
+void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id, uint32_t width,
+                                    uint32_t height, int32_t stride, uint32_t format,
+                                    void *line_0, int data_is_valid, int send_client)
+{
+    RedSurface *surface = &display->surfaces[surface_id];
+    uint32_t i;
+
+    spice_warn_if(surface->context.canvas);
+
+    surface->context.canvas_draws_on_surface = FALSE;
+    surface->context.width = width;
+    surface->context.height = height;
+    surface->context.format = format;
+    surface->context.stride = stride;
+    surface->context.line_0 = line_0;
+    if (!data_is_valid) {
+        char *data = line_0;
+        if (stride < 0) {
+            data -= abs(stride) * (height - 1);
+        }
+        memset(data, 0, height*abs(stride));
+    }
+    surface->create.info = NULL;
+    surface->destroy.info = NULL;
+    ring_init(&surface->current);
+    ring_init(&surface->current_list);
+    ring_init(&surface->depend_on_me);
+    region_init(&surface->draw_dirty_region);
+    surface->refs = 1;
+    if (display->renderer != RED_RENDERER_INVALID) {
+        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderer,
+                                                            width, height, stride,
+                                                            surface->context.format, line_0);
+        if (!surface->context.canvas) {
+            spice_critical("drawing canvas creating failed - can`t create same type canvas");
+        }
+
+        if (send_client)
+            send_create_surface(display, surface_id, data_is_valid);
+        return;
+    }
+
+    for (i = 0; i < display->num_renderers; i++) {
+        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderers[i],
+                                                            width, height, stride,
+                                                            surface->context.format, line_0);
+        if (surface->context.canvas) { //no need canvas check
+            display->renderer = display->renderers[i];
+            if (send_client)
+                send_create_surface(display, surface_id, data_is_valid);
+            return;
+        }
+    }
+
+    spice_critical("unable to create drawing canvas");
+}
+
 static void on_disconnect(RedChannelClient *rcc)
 {
     DisplayChannel *display;
diff --git a/server/display-channel.h b/server/display-channel.h
index 0bdf9dc..33caabe 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -255,6 +255,10 @@ DisplayChannel*            display_channel_new                       (RedWorker
                                                                       int migrate,
                                                                       int stream_video,
                                                                       uint32_t n_surfaces);
+void                       display_channel_create_surface            (DisplayChannel *display, uint32_t surface_id,
+                                                                      uint32_t width, uint32_t height,
+                                                                      int32_t stride, uint32_t format, void *line_0,
+                                                                      int data_is_valid, int send_client);
 void                       display_channel_draw                      (DisplayChannel *display,
                                                                       const SpiceRect *area,
                                                                       int surface_id);
diff --git a/server/red_worker.c b/server/red_worker.c
index 0c3ab30..678b581 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -134,9 +134,6 @@ typedef struct BitmapData {
 } BitmapData;
 
 static inline void display_begin_send_message(RedChannelClient *rcc);
-static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uint32_t width,
-                               uint32_t height, int32_t stride, uint32_t format,
-                               void *line_0, int data_is_valid, int send_client);
 
 QXLInstance* red_worker_get_qxl(RedWorker *worker)
 {
@@ -740,11 +737,11 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
         if (stride < 0) {
             data -= (int32_t)(stride * (height - 1));
         }
-        red_create_surface(worker->display_channel, surface_id, surface->u.surface_create.width,
-                           height, stride, surface->u.surface_create.format, data,
-                           reloaded_surface,
-                           // reloaded surfaces will be sent on demand
-                           !reloaded_surface);
+        display_channel_create_surface(worker->display_channel, surface_id, surface->u.surface_create.width,
+                                       height, stride, surface->u.surface_create.format, data,
+                                       reloaded_surface,
+                                       // reloaded surfaces will be sent on demand
+                                       !reloaded_surface);
         set_surface_release_info(&red_surface->create, surface->release_info, group_id);
         break;
     }
@@ -3416,114 +3413,6 @@ static void red_migrate_display(DisplayChannel *display, RedChannelClient *rcc)
     }
 }
 
-static inline void *create_canvas_for_surface(DisplayChannel *display, RedSurface *surface,
-                                              uint32_t renderer, uint32_t width, uint32_t height,
-                                              int32_t stride, uint32_t format, void *line_0)
-{
-    SpiceCanvas *canvas;
-
-    switch (renderer) {
-    case RED_RENDERER_SW:
-        canvas = canvas_create_for_data(width, height, format,
-                                        line_0, stride,
-                                        &display->image_cache.base,
-                                        &display->image_surfaces, NULL, NULL, NULL);
-        surface->context.top_down = TRUE;
-        surface->context.canvas_draws_on_surface = TRUE;
-        return canvas;
-    default:
-        spice_error("invalid renderer type");
-    };
-
-    return NULL;
-}
-
-static void red_worker_create_surface_item(DisplayChannel *display, int surface_id)
-{
-    DisplayChannelClient *dcc;
-    RingItem *item, *next;
-
-    FOREACH_DCC(display, item, next, dcc) {
-        dcc_create_surface(dcc, surface_id);
-    }
-}
-
-
-static void red_worker_push_surface_image(DisplayChannel *display, int surface_id)
-{
-    DisplayChannelClient *dcc;
-    RingItem *item, *next;
-
-    FOREACH_DCC(display, item, next, dcc) {
-        dcc_push_surface_image(dcc, surface_id);
-    }
-}
-
-static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uint32_t width,
-                               uint32_t height, int32_t stride, uint32_t format,
-                               void *line_0, int data_is_valid, int send_client)
-{
-    RedSurface *surface = &display->surfaces[surface_id];
-    uint32_t i;
-
-    spice_warn_if(surface->context.canvas);
-
-    surface->context.canvas_draws_on_surface = FALSE;
-    surface->context.width = width;
-    surface->context.height = height;
-    surface->context.format = format;
-    surface->context.stride = stride;
-    surface->context.line_0 = line_0;
-    if (!data_is_valid) {
-        char *data = line_0;
-        if (stride < 0) {
-            data -= abs(stride) * (height - 1);
-        }
-        memset(data, 0, height*abs(stride));
-    }
-    surface->create.info = NULL;
-    surface->destroy.info = NULL;
-    ring_init(&surface->current);
-    ring_init(&surface->current_list);
-    ring_init(&surface->depend_on_me);
-    region_init(&surface->draw_dirty_region);
-    surface->refs = 1;
-    if (display->renderer != RED_RENDERER_INVALID) {
-        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderer,
-                                                            width, height, stride,
-                                                            surface->context.format, line_0);
-        if (!surface->context.canvas) {
-            spice_critical("drawing canvas creating failed - can`t create same type canvas");
-        }
-
-        if (send_client) {
-            red_worker_create_surface_item(display, surface_id);
-            if (data_is_valid) {
-                red_worker_push_surface_image(display, surface_id);
-            }
-        }
-        return;
-    }
-
-    for (i = 0; i < display->num_renderers; i++) {
-        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderers[i],
-                                                            width, height, stride,
-                                                            surface->context.format, line_0);
-        if (surface->context.canvas) { //no need canvas check
-            display->renderer = display->renderers[i];
-            if (send_client) {
-                red_worker_create_surface_item(display, surface_id);
-                if (data_is_valid) {
-                    red_worker_push_surface_image(display, surface_id);
-                }
-            }
-            return;
-        }
-    }
-
-    spice_critical("unable to create drawing canvas");
-}
-
 static inline void flush_display_commands(RedWorker *worker)
 {
     RedChannel *display_red_channel = RED_CHANNEL(worker->display_channel);
@@ -4043,8 +3932,8 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
         line_0 -= (int32_t)(surface.stride * (surface.height -1));
     }
 
-    red_create_surface(display, 0, surface.width, surface.height, surface.stride, surface.format,
-                       line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA, TRUE);
+    display_channel_create_surface(display, 0, surface.width, surface.height, surface.stride, surface.format,
+                                   line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA, TRUE);
     set_monitors_config_to_primary(display);
 
     if (display_is_connected(worker) && !worker->display_channel->common.during_target_migrate) {
commit fd9c97a83328d98cbf80734c5d694b600b5db815
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Fri Sep 27 19:29:45 2013 +0200

    worker: move display_channel_update
    
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/server/display-channel.c b/server/display-channel.c
index 1ed0568..55dd37b 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -1419,6 +1419,45 @@ void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int su
     surface_update_dest(surface, area);
 }
 
+static void region_to_qxlrects(QRegion *region, QXLRect *qxl_rects, uint32_t num_rects)
+{
+    SpiceRect *rects;
+    int i;
+
+    rects = spice_new0(SpiceRect, num_rects);
+    region_ret_rects(region, rects, num_rects);
+    for (i = 0; i < num_rects; i++) {
+        qxl_rects[i].top    = rects[i].top;
+        qxl_rects[i].left   = rects[i].left;
+        qxl_rects[i].bottom = rects[i].bottom;
+        qxl_rects[i].right  = rects[i].right;
+    }
+    free(rects);
+}
+
+void display_channel_update(DisplayChannel *display,
+                            uint32_t surface_id, const QXLRect *area, uint32_t clear_dirty,
+                            QXLRect **qxl_dirty_rects, uint32_t *num_dirty_rects)
+{
+    SpiceRect rect;
+    RedSurface *surface;
+
+    spice_return_if_fail(validate_surface(display, surface_id));
+
+    red_get_rect_ptr(&rect, area);
+    display_channel_draw(display, &rect, surface_id);
+
+    surface = &display->surfaces[surface_id];
+    if (*qxl_dirty_rects == NULL) {
+        *num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
+        *qxl_dirty_rects = spice_new0(QXLRect, *num_dirty_rects);
+    }
+
+    region_to_qxlrects(&surface->draw_dirty_region, *qxl_dirty_rects, *num_dirty_rects);
+    if (clear_dirty)
+        region_clear(&surface->draw_dirty_region);
+}
+
 static void clear_surface_drawables_from_pipes(DisplayChannel *display, int surface_id,
                                                int wait_if_used)
 {
diff --git a/server/display-channel.h b/server/display-channel.h
index e74941a..0bdf9dc 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -262,6 +262,12 @@ void                       display_channel_draw_till                 (DisplayCha
                                                                       const SpiceRect *area,
                                                                       int surface_id,
                                                                       Drawable *last);
+void                       display_channel_update                    (DisplayChannel *display,
+                                                                      uint32_t surface_id,
+                                                                      const QXLRect *area,
+                                                                      uint32_t clear_dirty,
+                                                                      QXLRect **qxl_dirty_rects,
+                                                                      uint32_t *num_dirty_rects);
 void                       display_channel_free_some                 (DisplayChannel *display);
 void                       display_channel_set_stream_video          (DisplayChannel *display,
                                                                       int stream_video);
diff --git a/server/red_worker.c b/server/red_worker.c
index 3709691..0c3ab30 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -3915,45 +3915,6 @@ static void cursor_connect(RedWorker *worker, RedClient *client, RedsStream *str
         cursor_channel_init(channel, ccc);
 }
 
-static void region_to_qxlrects(QRegion *region, QXLRect *qxl_rects, uint32_t num_rects)
-{
-    SpiceRect *rects;
-    int i;
-
-    rects = spice_new0(SpiceRect, num_rects);
-    region_ret_rects(region, rects, num_rects);
-    for (i = 0; i < num_rects; i++) {
-        qxl_rects[i].top    = rects[i].top;
-        qxl_rects[i].left   = rects[i].left;
-        qxl_rects[i].bottom = rects[i].bottom;
-        qxl_rects[i].right  = rects[i].right;
-    }
-    free(rects);
-}
-
-void display_channel_update(DisplayChannel *display,
-                            uint32_t surface_id, const QXLRect *area, uint32_t clear_dirty,
-                            QXLRect **qxl_dirty_rects, uint32_t *num_dirty_rects)
-{
-    SpiceRect rect;
-    RedSurface *surface;
-
-    spice_return_if_fail(validate_surface(display, surface_id));
-
-    red_get_rect_ptr(&rect, area);
-    display_channel_draw(display, &rect, surface_id);
-
-    surface = &display->surfaces[surface_id];
-    if (!*qxl_dirty_rects) {
-        *num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
-        *qxl_dirty_rects = spice_new0(QXLRect, *num_dirty_rects);
-    }
-
-    region_to_qxlrects(&surface->draw_dirty_region, *qxl_dirty_rects, *num_dirty_rects);
-    if (clear_dirty)
-        region_clear(&surface->draw_dirty_region);
-}
-
 static void handle_dev_update_async(void *opaque, void *payload)
 {
     RedWorker *worker = opaque;
commit 0ebb539f48f3a504191d9a7429893cf7cf75c640
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Fri Sep 27 17:54:44 2013 +0200

    worker: move destroy_surface() familly
    
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/dcc.c b/server/dcc.c
index e3b0c55..6c089da 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -22,6 +22,8 @@
 #include "dcc.h"
 #include "display-channel.h"
 
+#define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano
+
 static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
                                                   uint32_t surface_id, uint32_t width,
                                                   uint32_t height, uint32_t format, uint32_t flags)
@@ -41,6 +43,84 @@ static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
     return create;
 }
 
+/*
+ * 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.
+ */
+int dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id,
+                                          int wait_if_used)
+{
+    Ring *ring;
+    PipeItem *item;
+    int x;
+    RedChannelClient *rcc;
+
+    spice_return_val_if_fail(dcc != NULL, TRUE);
+    /* removing the newest drawables that their destination is surface_id and
+       no other drawable depends on them */
+
+    rcc = RED_CHANNEL_CLIENT(dcc);
+    ring = &rcc->pipe;
+    item = (PipeItem *) ring;
+    while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) {
+        Drawable *drawable;
+        DrawablePipeItem *dpi = NULL;
+        int depend_found = FALSE;
+
+        if (item->type == PIPE_ITEM_TYPE_DRAW) {
+            dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
+            drawable = dpi->drawable;
+        } else if (item->type == PIPE_ITEM_TYPE_UPGRADE) {
+            drawable = ((UpgradeItem *)item)->drawable;
+        } else {
+            continue;
+        }
+
+        if (drawable->surface_id == surface_id) {
+            PipeItem *tmp_item = item;
+            item = (PipeItem *)ring_prev(ring, (RingItem *)item);
+            red_channel_client_pipe_remove_and_release(rcc, tmp_item);
+            if (!item) {
+                item = (PipeItem *)ring;
+            }
+            continue;
+        }
+
+        for (x = 0; x < 3; ++x) {
+            if (drawable->surface_deps[x] == surface_id) {
+                depend_found = TRUE;
+                break;
+            }
+        }
+
+        if (depend_found) {
+            spice_debug("surface %d dependent item found %p, %p", surface_id, drawable, item);
+            if (wait_if_used) {
+                break;
+            } else {
+                return TRUE;
+            }
+        }
+    }
+
+    if (!wait_if_used) {
+        return TRUE;
+    }
+
+    if (item) {
+        return red_channel_client_wait_pipe_item_sent(RED_CHANNEL_CLIENT(dcc), item,
+                                                      DISPLAY_CLIENT_TIMEOUT);
+    } else {
+        /*
+         * in case that the pipe didn't contain any item that is dependent on the surface, but
+         * there is one during sending. Use a shorter timeout, since it is just one item
+         */
+        return red_channel_client_wait_outgoing_item(RED_CHANNEL_CLIENT(dcc),
+                                                     DISPLAY_CLIENT_SHORT_TIMEOUT);
+    }
+    return TRUE;
+}
+
 void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
 {
     DisplayChannel *display;
diff --git a/server/dcc.h b/server/dcc.h
index dc6f1e7..c5767c9 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -201,6 +201,8 @@ void                       dcc_release_item                          (DisplayCha
                                                                       int item_pushed);
 void                       dcc_send_item                             (DisplayChannelClient *dcc,
                                                                       PipeItem *item);
+int                        dcc_clear_surface_drawables_from_pipe     (DisplayChannelClient *dcc,
+                                                                      int surface_id, int force);
 
 typedef struct compress_send_data_t {
     void*    comp_buf;
diff --git a/server/display-channel.c b/server/display-channel.c
index 4190ac4..1ed0568 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -1419,6 +1419,73 @@ void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int su
     surface_update_dest(surface, area);
 }
 
+static void clear_surface_drawables_from_pipes(DisplayChannel *display, int surface_id,
+                                               int wait_if_used)
+{
+    RingItem *item, *next;
+    DisplayChannelClient *dcc;
+
+    FOREACH_DCC(display, item, next, dcc) {
+        if (!dcc_clear_surface_drawables_from_pipe(dcc, surface_id, wait_if_used)) {
+            red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
+        }
+    }
+}
+
+/* TODO: cleanup/refactor destroy functions */
+void display_channel_destroy_surface(DisplayChannel *display, uint32_t surface_id)
+{
+    draw_depend_on_me(display, surface_id);
+    /* note that draw_depend_on_me must be called before current_remove_all.
+       otherwise "current" will hold items that other drawables may depend on, and then
+       current_remove_all will remove them from the pipe. */
+    current_remove_all(display, surface_id);
+    clear_surface_drawables_from_pipes(display, surface_id, FALSE);
+    display_channel_surface_unref(display, surface_id);
+}
+
+void display_channel_destroy_surface_wait(DisplayChannel *display, uint32_t surface_id)
+{
+    if (!validate_surface(display, surface_id))
+        return;
+    if (!display->surfaces[surface_id].context.canvas)
+        return;
+
+    draw_depend_on_me(display, surface_id);
+    /* note that draw_depend_on_me must be called before current_remove_all.
+       otherwise "current" will hold items that other drawables may depend on, and then
+       current_remove_all will remove them from the pipe. */
+    current_remove_all(display, surface_id);
+    clear_surface_drawables_from_pipes(display, surface_id, TRUE);
+}
+
+/* called upon device reset */
+/* TODO: split me*/
+void display_channel_destroy_surfaces(DisplayChannel *display)
+{
+    int i;
+
+    spice_debug(NULL);
+    //to handle better
+    for (i = 0; i < NUM_SURFACES; ++i) {
+        if (display->surfaces[i].context.canvas) {
+            display_channel_destroy_surface_wait(display, i);
+            if (display->surfaces[i].context.canvas) {
+                display_channel_surface_unref(display, i);
+            }
+            spice_assert(!display->surfaces[i].context.canvas);
+        }
+    }
+    spice_warn_if_fail(ring_is_empty(&display->streams));
+
+    if (red_channel_is_connected(RED_CHANNEL(display))) {
+        red_channel_pipes_add_type(RED_CHANNEL(display), PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
+        red_pipes_add_verb(RED_CHANNEL(display), SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
+    }
+
+    display_channel_free_glz_drawables(display);
+}
+
 static void on_disconnect(RedChannelClient *rcc)
 {
     DisplayChannel *display;
diff --git a/server/display-channel.h b/server/display-channel.h
index 90d7f80..e74941a 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -284,6 +284,11 @@ int                        display_channel_wait_for_migrate_data     (DisplayCha
 void                       display_channel_flush_all_surfaces        (DisplayChannel *display);
 void                       display_channel_free_glz_drawables_to_free(DisplayChannel *display);
 void                       display_channel_free_glz_drawables        (DisplayChannel *display);
+void                       display_channel_destroy_surface_wait      (DisplayChannel *display,
+                                                                      uint32_t surface_id);
+void                       display_channel_destroy_surfaces          (DisplayChannel *display);
+void                       display_channel_destroy_surface           (DisplayChannel *display,
+                                                                      uint32_t surface_id);
 
 static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
 {
@@ -415,6 +420,21 @@ static inline void region_add_clip_rects(QRegion *rgn, SpiceClipRects *data)
     }
 }
 
+static inline void draw_depend_on_me(DisplayChannel *display, uint32_t surface_id)
+{
+    RedSurface *surface;
+    RingItem *ring_item;
+
+    surface = &display->surfaces[surface_id];
+
+    while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
+        Drawable *drawable;
+        DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item);
+        drawable = depended_item->drawable;
+        display_channel_draw(display, &drawable->red_drawable->bbox, drawable->surface_id);
+    }
+}
+
 void current_remove_drawable(DisplayChannel *display, Drawable *item);
 void red_pipes_remove_drawable(Drawable *drawable);
 void current_remove(DisplayChannel *display, TreeItem *item);
diff --git a/server/red_worker.c b/server/red_worker.c
index f792ea3..3709691 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -72,8 +72,6 @@
 #define CMD_RING_POLL_TIMEOUT 10 //milli
 #define CMD_RING_POLL_RETRIES 200
 
-#define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano
-
 #define MAX_EVENT_SOURCES 20
 #define INF_EVENT_WAIT ~0
 
@@ -334,101 +332,6 @@ void current_remove_all(DisplayChannel *display, int surface_id)
     }
 }
 
-/*
- * 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.
- */
-static int red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id,
-                                                 int wait_if_used)
-{
-    Ring *ring;
-    PipeItem *item;
-    int x;
-    RedChannelClient *rcc;
-
-    if (!dcc) {
-        return TRUE;
-    }
-
-    /* removing the newest drawables that their destination is surface_id and
-       no other drawable depends on them */
-
-    rcc = RED_CHANNEL_CLIENT(dcc);
-    ring = &rcc->pipe;
-    item = (PipeItem *) ring;
-    while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) {
-        Drawable *drawable;
-        DrawablePipeItem *dpi = NULL;
-        int depend_found = FALSE;
-
-        if (item->type == PIPE_ITEM_TYPE_DRAW) {
-            dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
-            drawable = dpi->drawable;
-        } else if (item->type == PIPE_ITEM_TYPE_UPGRADE) {
-            drawable = ((UpgradeItem *)item)->drawable;
-        } else {
-            continue;
-        }
-
-        if (drawable->surface_id == surface_id) {
-            PipeItem *tmp_item = item;
-            item = (PipeItem *)ring_prev(ring, (RingItem *)item);
-            red_channel_client_pipe_remove_and_release(rcc, tmp_item);
-            if (!item) {
-                item = (PipeItem *)ring;
-            }
-            continue;
-        }
-
-        for (x = 0; x < 3; ++x) {
-            if (drawable->surface_deps[x] == surface_id) {
-                depend_found = TRUE;
-                break;
-            }
-        }
-
-        if (depend_found) {
-            spice_debug("surface %d dependent item found %p, %p", surface_id, drawable, item);
-            if (wait_if_used) {
-                break;
-            } else {
-                return TRUE;
-            }
-        }
-    }
-
-    if (!wait_if_used) {
-        return TRUE;
-    }
-
-    if (item) {
-        return red_channel_client_wait_pipe_item_sent(RED_CHANNEL_CLIENT(dcc), item,
-                                                      DISPLAY_CLIENT_TIMEOUT);
-    } else {
-        /*
-         * in case that the pipe didn't contain any item that is dependent on the surface, but
-         * there is one during sending. Use a shorter timeout, since it is just one item
-         */
-        return red_channel_client_wait_outgoing_item(RED_CHANNEL_CLIENT(dcc),
-                                                     DISPLAY_CLIENT_SHORT_TIMEOUT);
-    }
-    return TRUE;
-}
-
-static void red_clear_surface_drawables_from_pipes(DisplayChannel *display,
-                                                   int surface_id,
-                                                   int wait_if_used)
-{
-    RingItem *item, *next;
-    DisplayChannelClient *dcc;
-
-    FOREACH_DCC(display, item, next, dcc) {
-        if (!red_clear_surface_drawables_from_pipe(dcc, surface_id, wait_if_used)) {
-            red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
-        }
-    }
-}
-
 static int red_display_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
 {
     DrawablePipeItem *dpi;
@@ -697,23 +600,6 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
     return drawable;
 }
 
-static inline int red_handle_depends_on_target_surface(DisplayChannel *display, uint32_t surface_id)
-{
-    RedSurface *surface;
-    RingItem *ring_item;
-
-    surface = &display->surfaces[surface_id];
-
-    while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
-        Drawable *drawable;
-        DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item);
-        drawable = depended_item->drawable;
-        display_channel_draw(display, &drawable->red_drawable->bbox, drawable->surface_id);
-    }
-
-    return TRUE;
-}
-
 static inline void add_to_surface_dependency(DisplayChannel *display, int depend_on_surface_id,
                                              DependItem *depend_item, Drawable *drawable)
 {
@@ -812,9 +698,7 @@ static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable
         goto cleanup;
     }
 
-    if (!red_handle_depends_on_target_surface(worker->display_channel, surface_id)) {
-        goto cleanup;
-    }
+    draw_depend_on_me(display, surface_id);
 
     if (!red_handle_surfaces_dependencies(worker->display_channel, drawable)) {
         goto cleanup;
@@ -870,16 +754,10 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
             break;
         }
         set_surface_release_info(&red_surface->destroy, surface->release_info, group_id);
-        red_handle_depends_on_target_surface(display, surface_id);
-        /* note that red_handle_depends_on_target_surface must be called before current_remove_all.
-           otherwise "current" will hold items that other drawables may depend on, and then
-           current_remove_all will remove them from the pipe. */
-        current_remove_all(display, surface_id);
-        red_clear_surface_drawables_from_pipes(display, surface_id, FALSE);
-        display_channel_surface_unref(display, surface_id);
+        display_channel_destroy_surface(display, surface_id);
         break;
     default:
-            spice_error("unknown surface command");
+        spice_warn_if_reached();
     };
 exit:
     red_put_surface_cmd(surface);
@@ -4119,21 +3997,6 @@ static void handle_dev_del_memslot(void *opaque, void *payload)
     red_memslot_info_del_slot(&worker->mem_slots, slot_group_id, slot_id);
 }
 
-void display_channel_destroy_surface_wait(DisplayChannel *display, int surface_id)
-{
-    if (!validate_surface(display, surface_id))
-        return;
-    if (!display->surfaces[surface_id].context.canvas)
-        return;
-
-    red_handle_depends_on_target_surface(display, surface_id);
-    /* note that red_handle_depends_on_target_surface must be called before current_remove_all.
-       otherwise "current" will hold items that other drawables may depend on, and then
-       current_remove_all will remove them from the pipe. */
-    current_remove_all(display, surface_id);
-    red_clear_surface_drawables_from_pipes(display, surface_id, TRUE);
-}
-
 static void handle_dev_destroy_surface_wait(void *opaque, void *payload)
 {
     RedWorkerMessageDestroySurfaceWait *msg = payload;
@@ -4145,34 +4008,6 @@ static void handle_dev_destroy_surface_wait(void *opaque, void *payload)
     display_channel_destroy_surface_wait(worker->display_channel, msg->surface_id);
 }
 
-/* called upon device reset */
-
-/* TODO: split me*/
-void display_channel_destroy_surfaces(DisplayChannel *display)
-{
-    int i;
-
-    spice_debug(NULL);
-    //to handle better
-    for (i = 0; i < NUM_SURFACES; ++i) {
-        if (display->surfaces[i].context.canvas) {
-            display_channel_destroy_surface_wait(display, i);
-            if (display->surfaces[i].context.canvas) {
-                display_channel_surface_unref(display, i);
-            }
-            spice_assert(!display->surfaces[i].context.canvas);
-        }
-    }
-    spice_warn_if_fail(ring_is_empty(&display->streams));
-
-    if (red_channel_is_connected(RED_CHANNEL(display))) {
-        red_channel_pipes_add_type(RED_CHANNEL(display), PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
-        red_pipes_add_verb(RED_CHANNEL(display), SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
-    }
-
-    display_channel_free_glz_drawables(display);
-}
-
 static void handle_dev_destroy_surfaces(void *opaque, void *payload)
 {
     RedWorker *worker = opaque;
@@ -4738,6 +4573,8 @@ static void register_callbacks(Dispatcher *dispatcher)
     dispatcher_register_async_done_callback(
                                     dispatcher,
                                     worker_handle_dispatcher_async_done);
+
+    /* TODO: register cursor & display specific msg in respective channel files */
     dispatcher_register_handler(dispatcher,
                                 RED_WORKER_MESSAGE_DISPLAY_CONNECT,
                                 handle_dev_display_connect,
commit 9c828e8553a4ef6e3ab291bfde7b18fe18a2cd81
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Fri Sep 27 17:23:02 2013 +0200

    worker: move display_channel_new
    
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/dcc.c b/server/dcc.c
index 5d666cb..e3b0c55 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -372,6 +372,32 @@ void dcc_start(DisplayChannelClient *dcc)
     }
 }
 
+static void dcc_destroy_stream_agents(DisplayChannelClient *dcc)
+{
+    int i;
+
+    for (i = 0; i < NUM_STREAMS; i++) {
+        StreamAgent *agent = &dcc->stream_agents[i];
+        region_destroy(&agent->vis_region);
+        region_destroy(&agent->clip);
+        if (agent->mjpeg_encoder) {
+            mjpeg_encoder_destroy(agent->mjpeg_encoder);
+            agent->mjpeg_encoder = NULL;
+        }
+    }
+}
+
+void dcc_stop(DisplayChannelClient *dcc)
+{
+    pixmap_cache_unref(dcc->pixmap_cache);
+    dcc->pixmap_cache = NULL;
+    dcc_release_glz(dcc);
+    dcc_palette_cache_reset(dcc);
+    free(dcc->send_data.stream_outbuf);
+    free(dcc->send_data.free_list.res);
+    dcc_destroy_stream_agents(dcc);
+    dcc_encoders_free(dcc);
+}
 
 void dcc_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent)
 {
diff --git a/server/dcc.h b/server/dcc.h
index 62261e8..dc6f1e7 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -161,6 +161,7 @@ DisplayChannelClient*      dcc_new                                   (DisplayCha
                                                                       spice_wan_compression_t jpeg_state,
                                                                       spice_wan_compression_t zlib_glz_state);
 void                       dcc_start                                 (DisplayChannelClient *dcc);
+void                       dcc_stop                                  (DisplayChannelClient *dcc);
 int                        dcc_handle_message                        (RedChannelClient *rcc,
                                                                       uint32_t size,
                                                                       uint16_t type, void *msg);
@@ -198,6 +199,8 @@ void                       dcc_add_drawable_after                    (DisplayCha
 void                       dcc_release_item                          (DisplayChannelClient *dcc,
                                                                       PipeItem *item,
                                                                       int item_pushed);
+void                       dcc_send_item                             (DisplayChannelClient *dcc,
+                                                                      PipeItem *item);
 
 typedef struct compress_send_data_t {
     void*    comp_buf;
diff --git a/server/display-channel.c b/server/display-channel.c
index e158d59..4190ac4 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -1418,3 +1418,152 @@ void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int su
 
     surface_update_dest(surface, area);
 }
+
+static void on_disconnect(RedChannelClient *rcc)
+{
+    DisplayChannel *display;
+    DisplayChannelClient *dcc;
+
+    spice_info(NULL);
+    spice_return_if_fail(rcc != NULL);
+
+    dcc = RCC_TO_DCC(rcc);
+    display = DCC_TO_DC(dcc);
+
+    dcc_stop(dcc); // TODO: start/stop -> connect/disconnect?
+    display_channel_compress_stats_print(display);
+
+    // this was the last channel client
+    spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d",
+                display->drawable_count, display->red_drawable_count,
+                display->glz_drawable_count);
+}
+
+static void send_item(RedChannelClient *rcc, PipeItem *item)
+{
+    dcc_send_item(RCC_TO_DCC(rcc), item);
+}
+
+static void hold_item(RedChannelClient *rcc, PipeItem *item)
+{
+    spice_return_if_fail(item);
+
+    switch (item->type) {
+    case PIPE_ITEM_TYPE_DRAW:
+        drawable_pipe_item_ref(SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item));
+        break;
+    case PIPE_ITEM_TYPE_STREAM_CLIP:
+        ((StreamClipItem *)item)->refs++;
+        break;
+    case PIPE_ITEM_TYPE_UPGRADE:
+        ((UpgradeItem *)item)->refs++;
+        break;
+    case PIPE_ITEM_TYPE_IMAGE:
+        ((ImageItem *)item)->refs++;
+        break;
+    default:
+        spice_warn_if_reached();
+    }
+}
+
+static void release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
+{
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+
+    spice_assert(item != NULL);
+    dcc_release_item(dcc, item, item_pushed);
+}
+
+static int handle_migrate_flush_mark(RedChannelClient *rcc)
+{
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    RedChannel *channel = RED_CHANNEL(display_channel);
+
+    red_channel_pipes_add_type(channel, PIPE_ITEM_TYPE_MIGRATE_DATA);
+    return TRUE;
+}
+
+static uint64_t handle_migrate_data_get_serial(RedChannelClient *rcc, uint32_t size, void *message)
+{
+    SpiceMigrateDataDisplay *migrate_data;
+
+    migrate_data = (SpiceMigrateDataDisplay *)((uint8_t *)message + sizeof(SpiceMigrateDataHeader));
+
+    return migrate_data->message_serial;
+}
+
+static int handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
+{
+    return dcc_handle_migrate_data(RCC_TO_DCC(rcc), size, message);
+}
+
+static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t surface_id)
+{
+    DisplayChannel *display = SPICE_CONTAINEROF(surfaces, DisplayChannel, image_surfaces);
+
+    spice_return_val_if_fail(validate_surface(display, surface_id), NULL);
+
+    return display->surfaces[surface_id].context.canvas;
+}
+
+DisplayChannel* display_channel_new(RedWorker *worker, int migrate, int stream_video,
+                                    uint32_t n_surfaces)
+{
+    DisplayChannel *display;
+    ChannelCbs cbs = {
+        .on_disconnect = on_disconnect,
+        .send_item = send_item,
+        .hold_item = hold_item,
+        .release_item = release_item,
+        .handle_migrate_flush_mark = handle_migrate_flush_mark,
+        .handle_migrate_data = handle_migrate_data,
+        .handle_migrate_data_get_serial = handle_migrate_data_get_serial
+    };
+    static SpiceImageSurfacesOps image_surfaces_ops = {
+        image_surfaces_get,
+    };
+
+    spice_return_val_if_fail(num_renderers > 0, NULL);
+
+    spice_info("create display channel");
+    display = (DisplayChannel *)red_worker_new_channel(
+        worker, sizeof(*display), "display_channel",
+        SPICE_CHANNEL_DISPLAY,
+        SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
+        &cbs, dcc_handle_message);
+    spice_return_val_if_fail(display, NULL);
+
+    stat_init(&display->add_stat, "add", red_worker_get_clockid(worker));
+    stat_init(&display->exclude_stat, "exclude", red_worker_get_clockid(worker));
+    stat_init(&display->__exclude_stat, "__exclude", red_worker_get_clockid(worker));
+#ifdef RED_STATISTICS
+    RedChannel *channel = RED_CHANNEL(display);
+    display->cache_hits_counter = stat_add_counter(channel->stat,
+                                                           "cache_hits", TRUE);
+    display->add_to_cache_counter = stat_add_counter(channel->stat,
+                                                             "add_to_cache", TRUE);
+    display->non_cache_counter = stat_add_counter(channel->stat,
+                                                          "non_cache", TRUE);
+#endif
+    stat_compress_init(&display->lz_stat, "lz");
+    stat_compress_init(&display->glz_stat, "glz");
+    stat_compress_init(&display->quic_stat, "quic");
+    stat_compress_init(&display->jpeg_stat, "jpeg");
+    stat_compress_init(&display->zlib_glz_stat, "zlib");
+    stat_compress_init(&display->jpeg_alpha_stat, "jpeg_alpha");
+    stat_compress_init(&display->lz4_stat, "lz4");
+
+    display->n_surfaces = n_surfaces;
+    display->num_renderers = num_renderers;
+    memcpy(display->renderers, renderers, sizeof(display->renderers));
+    display->renderer = RED_RENDERER_INVALID;
+
+    ring_init(&display->current_list);
+    display->image_surfaces.ops = &image_surfaces_ops;
+    drawables_init(display);
+    image_cache_init(&display->image_cache);
+    display->stream_video = stream_video;
+    display_channel_init_streams(display);
+
+    return display;
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index 391e4ab..90d7f80 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -251,6 +251,10 @@ typedef struct UpgradeItem {
 } UpgradeItem;
 
 
+DisplayChannel*            display_channel_new                       (RedWorker *worker,
+                                                                      int migrate,
+                                                                      int stream_video,
+                                                                      uint32_t n_surfaces);
 void                       display_channel_draw                      (DisplayChannel *display,
                                                                       const SpiceRect *area,
                                                                       int surface_id);
@@ -281,6 +285,21 @@ void                       display_channel_flush_all_surfaces        (DisplayCha
 void                       display_channel_free_glz_drawables_to_free(DisplayChannel *display);
 void                       display_channel_free_glz_drawables        (DisplayChannel *display);
 
+static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
+{
+    if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
+        spice_warning("invalid surface_id %u", surface_id);
+        return 0;
+    }
+    if (!display->surfaces[surface_id].context.canvas) {
+        spice_warning("canvas address is %p for %d (and is NULL)\n",
+                   &(display->surfaces[surface_id].context.canvas), surface_id);
+        spice_warning("failed on %d", surface_id);
+        return 0;
+    }
+    return 1;
+}
+
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
     SpicePathSeg *seg1, *seg2;
diff --git a/server/red_worker.c b/server/red_worker.c
index 19ee4e6..f792ea3 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -135,8 +135,6 @@ typedef struct BitmapData {
     SpiceRect lossy_rect;
 } BitmapData;
 
-static inline int validate_surface(DisplayChannel *display, uint32_t surface_id);
-
 static inline void display_begin_send_message(RedChannelClient *rcc);
 static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uint32_t width,
                                uint32_t height, int32_t stride, uint32_t format,
@@ -178,21 +176,6 @@ static int validate_drawable_bbox(DisplayChannel *display, RedDrawable *drawable
         return TRUE;
 }
 
-static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
-{
-    if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
-        spice_warning("invalid surface_id %u", surface_id);
-        return 0;
-    }
-    if (!display->surfaces[surface_id].context.canvas) {
-        spice_warning("canvas address is %p for %d (and is NULL)\n",
-                   &(display->surfaces[surface_id].context.canvas), surface_id);
-        spice_warning("failed on %d", surface_id);
-        return 0;
-    }
-    return 1;
-}
-
 static int display_is_connected(RedWorker *worker)
 {
     return (worker->display_channel && red_channel_is_connected(
@@ -606,21 +589,6 @@ static void display_channel_streams_timeout(DisplayChannel *display)
     }
 }
 
-static void dcc_destroy_stream_agents(DisplayChannelClient *dcc)
-{
-    int i;
-
-    for (i = 0; i < NUM_STREAMS; i++) {
-        StreamAgent *agent = &dcc->stream_agents[i];
-        region_destroy(&agent->vis_region);
-        region_destroy(&agent->clip);
-        if (agent->mjpeg_encoder) {
-            mjpeg_encoder_destroy(agent->mjpeg_encoder);
-            agent->mjpeg_encoder = NULL;
-        }
-    }
-}
-
 static void red_get_area(DisplayChannel *display, int surface_id, const SpiceRect *area,
                          uint8_t *dest, int dest_stride, int update)
 {
@@ -918,24 +886,6 @@ exit:
     free(surface);
 }
 
-static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t surface_id)
-{
-    DisplayChannel *display = SPICE_CONTAINEROF(surfaces, DisplayChannel, image_surfaces);
-
-    spice_return_val_if_fail(validate_surface(display, surface_id), NULL);
-
-    return display->surfaces[surface_id].context.canvas;
-}
-
-static void image_surface_init(DisplayChannel *display)
-{
-    static SpiceImageSurfacesOps image_surfaces_ops = {
-        image_surfaces_get,
-    };
-
-    display->image_surfaces.ops = &image_surfaces_ops;
-}
-
 static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
 {
     QXLCommandExt ext_cmd;
@@ -1367,13 +1317,6 @@ static void fill_attr(SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id
     }
 }
 
-static inline void red_display_reset_send_data(DisplayChannelClient *dcc)
-{
-    dcc->send_data.free_list.res->count = 0;
-    dcc->send_data.num_pixmap_cache_items = 0;
-    memset(dcc->send_data.free_list.sync, 0, sizeof(dcc->send_data.free_list.sync));
-}
-
 /* set area=NULL for testing the whole surface */
 static int is_surface_area_lossy(DisplayChannelClient *dcc, uint32_t surface_id,
                                  const SpiceRect *area, SpiceRect *out_lossy_area)
@@ -3447,12 +3390,19 @@ static void red_marshall_stream_activate_report(RedChannelClient *rcc,
     spice_marshall_msg_display_stream_activate_report(base_marshaller, &msg);
 }
 
-static void send_item(RedChannelClient *rcc, PipeItem *pipe_item)
+static void reset_send_data(DisplayChannelClient *dcc)
+{
+    dcc->send_data.free_list.res->count = 0;
+    dcc->send_data.num_pixmap_cache_items = 0;
+    memset(dcc->send_data.free_list.sync, 0, sizeof(dcc->send_data.free_list.sync));
+}
+
+void dcc_send_item(DisplayChannelClient *dcc, PipeItem *pipe_item)
 {
+    RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
-    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
 
-    red_display_reset_send_data(dcc);
+    reset_send_data(dcc);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_DRAW: {
         DrawablePipeItem *dpi = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item);
@@ -3546,37 +3496,6 @@ static inline void red_push(RedWorker *worker)
     }
 }
 
-static void on_disconnect(RedChannelClient *rcc)
-{
-    DisplayChannel *display;
-    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
-    CommonChannel *common;
-    RedWorker *worker;
-
-    if (!rcc) {
-        return;
-    }
-    spice_info(NULL);
-    common = SPICE_CONTAINEROF(rcc->channel, CommonChannel, base);
-    worker = common->worker;
-    display = (DisplayChannel *)rcc->channel;
-    spice_assert(display == worker->display_channel);
-    display_channel_compress_stats_print(display);
-    pixmap_cache_unref(dcc->pixmap_cache);
-    dcc->pixmap_cache = NULL;
-    dcc_release_glz(dcc);
-    dcc_palette_cache_reset(dcc);
-    free(dcc->send_data.stream_outbuf);
-    free(dcc->send_data.free_list.res);
-    dcc_destroy_stream_agents(dcc);
-    dcc_encoders_free(dcc);
-
-    // this was the last channel client
-    spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d",
-                display->drawable_count, display->red_drawable_count,
-                display->glz_drawable_count);
-}
-
 void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
 {
     // TODO: we need to record the client that actually causes the timeout. So
@@ -3823,29 +3742,6 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
     flush_cursor_commands(worker);
 }
 
-static int handle_migrate_flush_mark(RedChannelClient *rcc)
-{
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
-    RedChannel *channel = RED_CHANNEL(display_channel);
-
-    red_channel_pipes_add_type(channel, PIPE_ITEM_TYPE_MIGRATE_DATA);
-    return TRUE;
-}
-
-static uint64_t handle_migrate_data_get_serial(RedChannelClient *rcc, uint32_t size, void *message)
-{
-    SpiceMigrateDataDisplay *migrate_data;
-
-    migrate_data = (SpiceMigrateDataDisplay *)((uint8_t *)message + sizeof(SpiceMigrateDataHeader));
-
-    return migrate_data->message_serial;
-}
-
-static int handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
-{
-    return dcc_handle_migrate_data(RCC_TO_DCC(rcc), size, message);
-}
-
 static int common_channel_config_socket(RedChannelClient *rcc)
 {
     RedClient *client = red_channel_client_get_client(rcc);
@@ -4028,94 +3924,6 @@ RedChannel *red_worker_new_channel(RedWorker *worker, int size,
     return channel;
 }
 
-static void hold_item(RedChannelClient *rcc, PipeItem *item)
-{
-    spice_assert(item);
-    switch (item->type) {
-    case PIPE_ITEM_TYPE_DRAW:
-        drawable_pipe_item_ref(SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item));
-        break;
-    case PIPE_ITEM_TYPE_STREAM_CLIP:
-        ((StreamClipItem *)item)->refs++;
-        break;
-    case PIPE_ITEM_TYPE_UPGRADE:
-        ((UpgradeItem *)item)->refs++;
-        break;
-    case PIPE_ITEM_TYPE_IMAGE:
-        ((ImageItem *)item)->refs++;
-        break;
-    default:
-        spice_critical("invalid item type");
-    }
-}
-
-static void release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
-{
-    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
-
-    spice_assert(item);
-    dcc_release_item(dcc, item, item_pushed);
-}
-
-static void display_channel_create(RedWorker *worker, int migrate, int stream_video,
-                                   uint32_t n_surfaces)
-{
-    DisplayChannel *display_channel;
-    ChannelCbs cbs = {
-        .on_disconnect = on_disconnect,
-        .send_item = send_item,
-        .hold_item = hold_item,
-        .release_item = release_item,
-        .handle_migrate_flush_mark = handle_migrate_flush_mark,
-        .handle_migrate_data = handle_migrate_data,
-        .handle_migrate_data_get_serial = handle_migrate_data_get_serial
-    };
-
-    spice_return_if_fail(num_renderers > 0);
-
-    spice_info("create display channel");
-    if (!(display_channel = (DisplayChannel *)red_worker_new_channel(
-            worker, sizeof(*display_channel), "display_channel",
-            SPICE_CHANNEL_DISPLAY,
-            SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
-            &cbs, dcc_handle_message))) {
-        spice_warning("failed to create display channel");
-        return;
-    }
-    worker->display_channel = display_channel;
-    stat_init(&display_channel->add_stat, "add", worker->clockid);
-    stat_init(&display_channel->exclude_stat, "exclude", worker->clockid);
-    stat_init(&display_channel->__exclude_stat, "__exclude", worker->clockid);
-#ifdef RED_STATISTICS
-    RedChannel *channel = RED_CHANNEL(display_channel);
-    display_channel->cache_hits_counter = stat_add_counter(channel->stat,
-                                                           "cache_hits", TRUE);
-    display_channel->add_to_cache_counter = stat_add_counter(channel->stat,
-                                                             "add_to_cache", TRUE);
-    display_channel->non_cache_counter = stat_add_counter(channel->stat,
-                                                          "non_cache", TRUE);
-#endif
-    stat_compress_init(&display_channel->lz_stat, "lz");
-    stat_compress_init(&display_channel->glz_stat, "glz");
-    stat_compress_init(&display_channel->quic_stat, "quic");
-    stat_compress_init(&display_channel->jpeg_stat, "jpeg");
-    stat_compress_init(&display_channel->zlib_glz_stat, "zlib");
-    stat_compress_init(&display_channel->jpeg_alpha_stat, "jpeg_alpha");
-    stat_compress_init(&display_channel->lz4_stat, "lz4");
-
-    display_channel->n_surfaces = n_surfaces;
-    display_channel->num_renderers = num_renderers;
-    memcpy(display_channel->renderers, renderers, sizeof(display_channel->renderers));
-    display_channel->renderer = RED_RENDERER_INVALID;
-
-    ring_init(&display_channel->current_list);
-    image_surface_init(display_channel);
-    drawables_init(display_channel);
-    image_cache_init(&display_channel->image_cache);
-    display_channel->stream_video = stream_video;
-    display_channel_init_streams(display_channel);
-}
-
 static void guest_set_client_capabilities(RedWorker *worker)
 {
     int i;
@@ -5173,7 +4981,8 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher)
 
     worker->cursor_channel = cursor_channel_new(worker);
     // TODO: handle seemless migration. Temp, setting migrate to FALSE
-    display_channel_create(worker, FALSE, streaming_video, init_info.n_surfaces);
+    worker->display_channel = display_channel_new(worker, FALSE, streaming_video,
+                                                  init_info.n_surfaces);
 
     return worker;
 }


More information about the Spice-commits mailing list