[Spice-commits] 3 commits - server/dcc.c server/dcc-encoders.c server/dcc-encoders.h server/dcc.h server/display-channel.c server/display-channel.h server/display-limits.h server/Makefile.am server/red_worker.c

Frediano Ziglio fziglio at kemper.freedesktop.org
Thu Nov 19 04:44:38 PST 2015


 server/Makefile.am       |    3 
 server/dcc-encoders.c    |    1 
 server/dcc-encoders.h    |    1 
 server/dcc.c             |  311 +++++++++++++++++++++++++++++++++++++++++++++++
 server/dcc.h             |  167 +++++++++++++++++++++++++
 server/display-channel.c |  158 ++++-------------------
 server/display-channel.h |  120 ------------------
 server/display-limits.h  |   27 ++++
 server/red_worker.c      |  272 +++--------------------------------------
 9 files changed, 568 insertions(+), 492 deletions(-)

New commits:
commit 1cbf6b3ab69a1e789ebb52c146d46f637a290e1f
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Sep 17 16:36:29 2013 +0200

    worker: move display_channel_wait_for_migrate_data
    
    Acked-by: Fabiano Fidêncio <fidencio at redhat.com>

diff --git a/server/display-channel.c b/server/display-channel.c
index 9990c71..37ba5c3 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -807,3 +807,34 @@ int display_channel_add_drawable(DisplayChannel *display, Drawable *drawable)
 
     return ret;
 }
+
+int display_channel_wait_for_migrate_data(DisplayChannel *display)
+{
+    uint64_t end_time = red_get_monotonic_time() + DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT;
+    RedChannel *channel = &display->common.base;
+    RedChannelClient *rcc;
+
+    spice_debug(NULL);
+    spice_assert(channel->clients_num == 1);
+
+    rcc = SPICE_CONTAINEROF(ring_get_head(&channel->clients), RedChannelClient, channel_link);
+    spice_assert(red_channel_client_waits_for_migrate_data(rcc));
+
+    for (;;) {
+        red_channel_client_receive(rcc);
+        if (!red_channel_client_is_connected(rcc)) {
+            break;
+        }
+
+        if (!red_channel_client_waits_for_migrate_data(rcc)) {
+            return TRUE;
+        }
+        if (red_get_monotonic_time() > end_time) {
+            spice_warning("timeout");
+            red_channel_client_disconnect(rcc);
+            break;
+        }
+        usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
+    }
+    return FALSE;
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index 8c53aef..69ceb3c 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -268,6 +268,7 @@ int                        display_channel_add_drawable              (DisplayCha
                                                                       Drawable *drawable);
 void                       display_channel_current_flush             (DisplayChannel *display,
                                                                       int surface_id);
+int                        display_channel_wait_for_migrate_data     (DisplayChannel *display);
 
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
diff --git a/server/red_worker.c b/server/red_worker.c
index a6e6b6a..32612d5 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -6911,37 +6911,6 @@ static void handle_dev_stop(void *opaque, void *payload)
     }
 }
 
-static int display_channel_wait_for_migrate_data(DisplayChannel *display)
-{
-    uint64_t end_time = red_get_monotonic_time() + DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT;
-    RedChannel *channel = &display->common.base;
-    RedChannelClient *rcc;
-
-    spice_debug(NULL);
-    spice_assert(channel->clients_num == 1);
-
-    rcc = SPICE_CONTAINEROF(ring_get_head(&channel->clients), RedChannelClient, channel_link);
-    spice_assert(red_channel_client_waits_for_migrate_data(rcc));
-
-    for (;;) {
-        red_channel_client_receive(rcc);
-        if (!red_channel_client_is_connected(rcc)) {
-            break;
-        }
-
-        if (!red_channel_client_waits_for_migrate_data(rcc)) {
-            return TRUE;
-        }
-        if (red_get_monotonic_time() > end_time) {
-            spice_warning("timeout");
-            red_channel_client_disconnect(rcc);
-            break;
-        }
-        usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
-    }
-    return FALSE;
-}
-
 static void handle_dev_start(void *opaque, void *payload)
 {
     RedWorker *worker = opaque;
commit 0e224d04fbd9a05a3289b19c32e9a8fd4afca086
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Sep 17 16:29:44 2013 +0200

    worker: move dcc_start()
    
    Author:    Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Fabiano Fidêncio <fidencio at redhat.com>

diff --git a/server/dcc.c b/server/dcc.c
index 4a95735..a14247c 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -22,6 +22,97 @@
 #include "dcc.h"
 #include "display-channel.h"
 
+static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
+                                                  uint32_t surface_id, uint32_t width,
+                                                  uint32_t height, uint32_t format, uint32_t flags)
+{
+    SurfaceCreateItem *create;
+
+    create = spice_malloc(sizeof(SurfaceCreateItem));
+
+    create->surface_create.surface_id = surface_id;
+    create->surface_create.width = width;
+    create->surface_create.height = height;
+    create->surface_create.flags = flags;
+    create->surface_create.format = format;
+
+    red_channel_pipe_item_init(channel,
+                               &create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
+    return create;
+}
+
+void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
+{
+    DisplayChannel *display;
+    RedSurface *surface;
+    SurfaceCreateItem *create;
+    uint32_t flags;
+
+    if (!dcc) {
+        return;
+    }
+
+    display = DCC_TO_DC(dcc);
+    flags = is_primary_surface(DCC_TO_DC(dcc), surface_id) ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
+
+    /* don't send redundant create surface commands to client */
+    if (!dcc || display->common.during_target_migrate ||
+        dcc->surface_client_created[surface_id]) {
+        return;
+    }
+    surface = &display->surfaces[surface_id];
+    create = surface_create_item_new(RED_CHANNEL_CLIENT(dcc)->channel,
+                                     surface_id, surface->context.width, surface->context.height,
+                                     surface->context.format, flags);
+    dcc->surface_client_created[surface_id] = TRUE;
+    red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &create->pipe_item);
+}
+
+void dcc_push_surface_image(DisplayChannelClient *dcc, int surface_id)
+{
+    DisplayChannel *display;
+    SpiceRect area;
+    RedSurface *surface;
+
+    if (!dcc) {
+        return;
+    }
+
+    display = DCC_TO_DC(dcc);
+    surface = &display->surfaces[surface_id];
+    if (!surface->context.canvas) {
+        return;
+    }
+    area.top = area.left = 0;
+    area.right = surface->context.width;
+    area.bottom = surface->context.height;
+
+    /* not allowing lossy compression because probably, especially if it is a primary surface,
+       it combines both "picture-like" areas with areas that are more "artificial"*/
+    dcc_add_surface_area_image(dcc, surface_id, &area, NULL, FALSE);
+    red_channel_client_push(RED_CHANNEL_CLIENT(dcc));
+}
+
+static void dcc_init_stream_agents(DisplayChannelClient *dcc)
+{
+    int i;
+    DisplayChannel *display = DCC_TO_DC(dcc);
+    RedChannel *channel = RED_CHANNEL_CLIENT(dcc)->channel;
+
+    for (i = 0; i < NUM_STREAMS; i++) {
+        StreamAgent *agent = &dcc->stream_agents[i];
+        agent->stream = &display->streams_buf[i];
+        region_init(&agent->vis_region);
+        region_init(&agent->clip);
+        red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
+        red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
+    }
+    dcc->use_mjpeg_encoder_rate_control =
+        red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT);
+}
+
+#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
+
 DisplayChannelClient *dcc_new(DisplayChannel *display,
                               RedClient *client, RedsStream *stream,
                               int mig_target,
@@ -40,6 +131,7 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
         common_caps, num_common_caps,
         caps, num_caps);
     spice_return_val_if_fail(dcc, NULL);
+    spice_info("New display (client %p) dcc %p stream %p", client, dcc, stream);
 
     ring_init(&dcc->palette_cache_lru);
     dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
@@ -49,11 +141,89 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
     // TODO: tune quality according to bandwidth
     dcc->jpeg_quality = 85;
 
+    size_t stream_buf_size;
+    stream_buf_size = 32*1024;
+    dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size);
+    dcc->send_data.stream_outbuf_size = stream_buf_size;
+    dcc->send_data.free_list.res =
+        spice_malloc(sizeof(SpiceResourceList) +
+                     DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID));
+    dcc->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
+
+    dcc_init_stream_agents(dcc);
+
     dcc_encoders_init(dcc);
 
     return dcc;
 }
 
+static void dcc_create_all_streams(DisplayChannelClient *dcc)
+{
+    Ring *ring = &DCC_TO_DC(dcc)->streams;
+    RingItem *item = ring;
+
+    while ((item = ring_next(ring, item))) {
+        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
+        dcc_create_stream(dcc, stream);
+    }
+}
+
+/* TODO: this function is evil^Wsynchronous, fix */
+static int display_channel_client_wait_for_init(DisplayChannelClient *dcc)
+{
+    dcc->expect_init = TRUE;
+    uint64_t end_time = red_get_monotonic_time() + DISPLAY_CLIENT_TIMEOUT;
+    for (;;) {
+        red_channel_client_receive(RED_CHANNEL_CLIENT(dcc));
+        if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(dcc))) {
+            break;
+        }
+        if (dcc->pixmap_cache && dcc->glz_dict) {
+            dcc->pixmap_cache_generation = dcc->pixmap_cache->generation;
+            /* TODO: move common.id? if it's used for a per client structure.. */
+            spice_info("creating encoder with id == %d", dcc->common.id);
+            dcc->glz = glz_encoder_create(dcc->common.id, dcc->glz_dict->dict, &dcc->glz_data.usr);
+            if (!dcc->glz) {
+                spice_critical("create global lz failed");
+            }
+            return TRUE;
+        }
+        if (red_get_monotonic_time() > end_time) {
+            spice_warning("timeout");
+            red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
+            break;
+        }
+        usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
+    }
+    return FALSE;
+}
+
+void dcc_start(DisplayChannelClient *dcc)
+{
+    DisplayChannel *display = DCC_TO_DC(dcc);
+    RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
+
+    red_channel_client_push_set_ack(RED_CHANNEL_CLIENT(dcc));
+
+    if (red_channel_client_waits_for_migrate_data(rcc))
+        return;
+
+    if (!display_channel_client_wait_for_init(dcc))
+        return;
+
+    red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
+    if (display->surfaces[0].context.canvas) {
+        display_channel_current_flush(display, 0);
+        red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
+        dcc_create_surface(dcc, 0);
+        dcc_push_surface_image(dcc, 0);
+        dcc_push_monitors_config(dcc);
+        red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK);
+        dcc_create_all_streams(dcc);
+    }
+}
+
+
 void dcc_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent)
 {
     StreamClipItem *item = stream_clip_item_new(dcc, agent);
diff --git a/server/dcc.h b/server/dcc.h
index ee2e75f..a6ca9be 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -31,6 +31,10 @@
 #define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK)
 #define CLIENT_PALETTE_CACHE_SIZE 128
 
+#define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano
+#define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
+#define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
+
 /* Each drawable can refer to at most 3 images: src, brush and mask */
 #define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3
 
@@ -111,6 +115,25 @@ struct DisplayChannelClient {
      SPICE_CONTAINEROF((dcc)->common.base.channel, DisplayChannel, common.base)
 #define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
 
+typedef struct SurfaceCreateItem {
+    SpiceMsgSurfaceCreate surface_create;
+    PipeItem pipe_item;
+} SurfaceCreateItem;
+
+typedef struct ImageItem {
+    PipeItem link;
+    int refs;
+    SpicePoint pos;
+    int width;
+    int height;
+    int stride;
+    int top_down;
+    int surface_id;
+    int image_format;
+    uint32_t image_flags;
+    int can_lossy;
+    uint8_t data[0];
+} ImageItem;
 
 DisplayChannelClient*      dcc_new                                   (DisplayChannel *display,
                                                                       RedClient *client,
@@ -123,6 +146,7 @@ DisplayChannelClient*      dcc_new                                   (DisplayCha
                                                                       SpiceImageCompression image_compression,
                                                                       spice_wan_compression_t jpeg_state,
                                                                       spice_wan_compression_t zlib_glz_state);
+void                       dcc_start                                 (DisplayChannelClient *dcc);
 void                       dcc_push_monitors_config                  (DisplayChannelClient *dcc);
 void                       dcc_destroy_surface                       (DisplayChannelClient *dcc,
                                                                       uint32_t surface_id);
@@ -130,5 +154,14 @@ void                       dcc_stream_agent_clip                     (DisplayCha
                                                                       StreamAgent *agent);
 void                       dcc_create_stream                         (DisplayChannelClient *dcc,
                                                                       Stream *stream);
+void                       dcc_create_surface                        (DisplayChannelClient *dcc,
+                                                                      int surface_id);
+void                       dcc_push_surface_image                    (DisplayChannelClient *dcc,
+                                                                      int surface_id);
+ImageItem *                dcc_add_surface_area_image                (DisplayChannelClient *dcc,
+                                                                      int surface_id,
+                                                                      SpiceRect *area,
+                                                                      PipeItem *pos,
+                                                                      int can_lossy);
 
 #endif /* DCC_H_ */
diff --git a/server/display-channel.h b/server/display-channel.h
index aba7dce..8c53aef 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -253,11 +253,6 @@ typedef struct SurfaceDestroyItem {
     PipeItem pipe_item;
 } SurfaceDestroyItem;
 
-typedef struct SurfaceCreateItem {
-    SpiceMsgSurfaceCreate surface_create;
-    PipeItem pipe_item;
-} SurfaceCreateItem;
-
 
 void                       display_channel_set_stream_video          (DisplayChannel *display,
                                                                       int stream_video);
@@ -271,6 +266,8 @@ bool                       display_channel_surface_has_canvas        (DisplayCha
                                                                       uint32_t surface_id);
 int                        display_channel_add_drawable              (DisplayChannel *display,
                                                                       Drawable *drawable);
+void                       display_channel_current_flush             (DisplayChannel *display,
+                                                                      int surface_id);
 
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
diff --git a/server/red_worker.c b/server/red_worker.c
index 7669854..a6e6b6a 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -119,21 +119,6 @@ struct SpiceWatch {
 #define WIDE_CLIENT_ACK_WINDOW 40
 #define NARROW_CLIENT_ACK_WINDOW 20
 
-typedef struct ImageItem {
-    PipeItem link;
-    int refs;
-    SpicePoint pos;
-    int width;
-    int height;
-    int stride;
-    int top_down;
-    int surface_id;
-    int image_format;
-    uint32_t image_flags;
-    int can_lossy;
-    uint8_t data[0];
-} ImageItem;
-
 pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER;
 Ring glz_dictionary_list = {&glz_dictionary_list, &glz_dictionary_list};
 
@@ -199,7 +184,6 @@ typedef struct BitmapData {
 static inline int validate_surface(DisplayChannel *display, uint32_t surface_id);
 
 static void red_draw_qxl_drawable(DisplayChannel *display, Drawable *drawable);
-static void red_current_flush(DisplayChannel *display, int surface_id);
 static void red_draw_drawable(DisplayChannel *display, Drawable *item);
 static void red_update_area(DisplayChannel *display, const SpiceRect *area, int surface_id);
 static void red_update_area_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
@@ -211,8 +195,6 @@ static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type
                                          uint64_t* sync_data);
 static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc);
 static void dcc_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable);
-static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
-                                             SpiceRect *area, PipeItem *pos, int can_lossy);
 static void display_channel_client_release_item_before_push(DisplayChannelClient *dcc,
                                                             PipeItem *item);
 static void display_channel_client_release_item_after_push(DisplayChannelClient *dcc,
@@ -369,8 +351,6 @@ static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
     return 1;
 }
 
-static inline void red_create_surface_item(DisplayChannelClient *dcc, int surface_id);
-static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id);
 
 static inline void red_handle_drawable_surfaces_client_synced(
                         DisplayChannelClient *dcc, Drawable *drawable)
@@ -386,9 +366,9 @@ static inline void red_handle_drawable_surfaces_client_synced(
             if (dcc->surface_client_created[surface_id] == TRUE) {
                 continue;
             }
-            red_create_surface_item(dcc, surface_id);
-            red_current_flush(display, surface_id);
-            red_push_surface_image(dcc, surface_id);
+            dcc_create_surface(dcc, surface_id);
+            display_channel_current_flush(display, surface_id);
+            dcc_push_surface_image(dcc, surface_id);
         }
     }
 
@@ -396,9 +376,9 @@ static inline void red_handle_drawable_surfaces_client_synced(
         return;
     }
 
-    red_create_surface_item(dcc, drawable->surface_id);
-    red_current_flush(display, drawable->surface_id);
-    red_push_surface_image(dcc, drawable->surface_id);
+    dcc_create_surface(dcc, drawable->surface_id);
+    display_channel_current_flush(display, drawable->surface_id);
+    dcc_push_surface_image(dcc, drawable->surface_id);
 }
 
 static int display_is_connected(RedWorker *worker)
@@ -985,7 +965,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         } else {
             red_update_area(DCC_TO_DC(dcc), &upgrade_area, 0);
         }
-        red_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
+        dcc_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
     }
 clear_vis_region:
     region_clear(&agent->vis_region);
@@ -1065,35 +1045,6 @@ static void display_channel_streams_timeout(DisplayChannel *display)
     }
 }
 
-static void dcc_create_all_streams(DisplayChannelClient *dcc)
-{
-    Ring *ring = &DCC_TO_DC(dcc)->streams;
-    RingItem *item = ring;
-
-    while ((item = ring_next(ring, item))) {
-        Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
-        dcc_create_stream(dcc, stream);
-    }
-}
-
-static void dcc_init_stream_agents(DisplayChannelClient *dcc)
-{
-    int i;
-    DisplayChannel *display = DCC_TO_DC(dcc);
-    RedChannel *channel = RED_CHANNEL_CLIENT(dcc)->channel;
-
-    for (i = 0; i < NUM_STREAMS; i++) {
-        StreamAgent *agent = &dcc->stream_agents[i];
-        agent->stream = &display->streams_buf[i];
-        region_init(&agent->vis_region);
-        region_init(&agent->clip);
-        red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
-        red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
-    }
-    dcc->use_mjpeg_encoder_rate_control =
-        red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT);
-}
-
 static void dcc_destroy_stream_agents(DisplayChannelClient *dcc)
 {
     int i;
@@ -1999,7 +1950,7 @@ static void red_free_some(RedWorker *worker)
     }
 }
 
-static void red_current_flush(DisplayChannel *display, int surface_id)
+void display_channel_current_flush(DisplayChannel *display, int surface_id)
 {
     while (!ring_is_empty(&display->surfaces[surface_id].current_list)) {
         free_one_drawable(display, FALSE);
@@ -2008,8 +1959,8 @@ static void red_current_flush(DisplayChannel *display, int surface_id)
 }
 
 // adding the pipe item after pos. If pos == NULL, adding to head.
-static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
-                                             SpiceRect *area, PipeItem *pos, int can_lossy)
+ImageItem *dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
+                                      SpiceRect *area, PipeItem *pos, int can_lossy)
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
     RedChannel *channel = RED_CHANNEL(display);
@@ -2071,31 +2022,6 @@ static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surf
     return item;
 }
 
-static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id)
-{
-    DisplayChannel *display;
-    SpiceRect area;
-    RedSurface *surface;
-
-    if (!dcc) {
-        return;
-    }
-
-    display = DCC_TO_DC(dcc);
-    surface = &display->surfaces[surface_id];
-    if (!surface->context.canvas) {
-        return;
-    }
-    area.top = area.left = 0;
-    area.right = surface->context.width;
-    area.bottom = surface->context.height;
-
-    /* not allowing lossy compression because probably, especially if it is a primary surface,
-       it combines both "picture-like" areas with areas that are more "artificial"*/
-    red_add_surface_area_image(dcc, surface_id, &area, NULL, FALSE);
-    red_channel_client_push(RED_CHANNEL_CLIENT(dcc));
-}
-
 static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
 {
     SpiceMsgDisplayBase base;
@@ -3501,7 +3427,7 @@ static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient
             continue;
         }
 
-        image = red_add_surface_area_image(dcc, drawable->red_drawable->surface_id,
+        image = dcc_add_surface_area_image(dcc, drawable->red_drawable->surface_id,
                                            &drawable->red_drawable->bbox, pipe_item, TRUE);
         resent_surface_ids[num_resent] = drawable->red_drawable->surface_id;
         resent_areas[num_resent] = drawable->red_drawable->bbox;
@@ -3557,7 +3483,7 @@ static void red_add_lossless_drawable_dependencies(RedChannelClient *rcc,
         // the surfaces areas will be sent as DRAW_COPY commands, that
         // will be executed before the current drawable
         for (i = 0; i < num_deps; i++) {
-            red_add_surface_area_image(dcc, deps_surfaces_ids[i], deps_areas[i],
+            dcc_add_surface_area_image(dcc, deps_surfaces_ids[i], deps_areas[i],
                                        red_pipe_get_tail(dcc), FALSE);
 
         }
@@ -3578,7 +3504,7 @@ static void red_add_lossless_drawable_dependencies(RedChannelClient *rcc,
                                                             &drawable->bbox);
         }
 
-        red_add_surface_area_image(dcc, drawable->surface_id, &drawable->bbox,
+        dcc_add_surface_area_image(dcc, drawable->surface_id, &drawable->bbox,
                                    red_pipe_get_tail(dcc), TRUE);
     }
 }
@@ -5574,60 +5500,13 @@ static inline void *create_canvas_for_surface(DisplayChannel *display, RedSurfac
     return NULL;
 }
 
-static SurfaceCreateItem *get_surface_create_item(
-    RedChannel* channel,
-    uint32_t surface_id, uint32_t width,
-    uint32_t height, uint32_t format, uint32_t flags)
-{
-    SurfaceCreateItem *create;
-
-    create = spice_malloc(sizeof(SurfaceCreateItem));
-
-    create->surface_create.surface_id = surface_id;
-    create->surface_create.width = width;
-    create->surface_create.height = height;
-    create->surface_create.flags = flags;
-    create->surface_create.format = format;
-
-    red_channel_pipe_item_init(channel,
-            &create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
-    return create;
-}
-
-static inline void red_create_surface_item(DisplayChannelClient *dcc, int surface_id)
-{
-    DisplayChannel *display;
-    RedSurface *surface;
-    SurfaceCreateItem *create;
-    uint32_t flags;
-
-    if (!dcc) {
-        return;
-    }
-
-    display = DCC_TO_DC(dcc);
-    flags = is_primary_surface(DCC_TO_DC(dcc), surface_id) ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
-
-    /* don't send redundant create surface commands to client */
-    if (display->common.during_target_migrate ||
-        dcc->surface_client_created[surface_id]) {
-        return;
-    }
-    surface = &display->surfaces[surface_id];
-    create = get_surface_create_item(RED_CHANNEL_CLIENT(dcc)->channel,
-            surface_id, surface->context.width, surface->context.height,
-                                     surface->context.format, flags);
-    dcc->surface_client_created[surface_id] = TRUE;
-    red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &create->pipe_item);
-}
-
 static void red_worker_create_surface_item(DisplayChannel *display, int surface_id)
 {
     DisplayChannelClient *dcc;
     RingItem *item, *next;
 
     FOREACH_DCC(display, item, next, dcc) {
-        red_create_surface_item(dcc, surface_id);
+        dcc_create_surface(dcc, surface_id);
     }
 }
 
@@ -5638,7 +5517,7 @@ static void red_worker_push_surface_image(DisplayChannel *display, int surface_i
     RingItem *item, *next;
 
     FOREACH_DCC(display, item, next, dcc) {
-        red_push_surface_image(dcc, surface_id);
+        dcc_push_surface_image(dcc, surface_id);
     }
 }
 
@@ -5803,70 +5682,6 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
     flush_cursor_commands(worker);
 }
 
-static void push_new_primary_surface(DisplayChannelClient *dcc)
-{
-    RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
-
-    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
-    red_create_surface_item(dcc, 0);
-    red_channel_client_push(rcc);
-}
-
-/* TODO: this function is evil^Wsynchronous, fix */
-static int display_channel_client_wait_for_init(DisplayChannelClient *dcc)
-{
-    dcc->expect_init = TRUE;
-    uint64_t end_time = red_get_monotonic_time() + DISPLAY_CLIENT_TIMEOUT;
-    for (;;) {
-        red_channel_client_receive(RED_CHANNEL_CLIENT(dcc));
-        if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(dcc))) {
-            break;
-        }
-        if (dcc->pixmap_cache && dcc->glz_dict) {
-            dcc->pixmap_cache_generation = dcc->pixmap_cache->generation;
-            /* TODO: move common.id? if it's used for a per client structure.. */
-            spice_info("creating encoder with id == %d", dcc->common.id);
-            dcc->glz = glz_encoder_create(dcc->common.id, dcc->glz_dict->dict, &dcc->glz_data.usr);
-            if (!dcc->glz) {
-                spice_critical("create global lz failed");
-            }
-            return TRUE;
-        }
-        if (red_get_monotonic_time() > end_time) {
-            spice_warning("timeout");
-            red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
-            break;
-        }
-        usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
-    }
-    return FALSE;
-}
-
-static void on_new_display_channel_client(DisplayChannelClient *dcc)
-{
-    DisplayChannel *display = DCC_TO_DC(dcc);
-    RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
-
-    red_channel_client_push_set_ack(RED_CHANNEL_CLIENT(dcc));
-
-    if (red_channel_client_waits_for_migrate_data(rcc)) {
-        return;
-    }
-
-    if (!display_channel_client_wait_for_init(dcc)) {
-        return;
-    }
-    red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
-    if (display->surfaces[0].context.canvas) {
-        red_current_flush(display, 0);
-        push_new_primary_surface(dcc);
-        red_push_surface_image(dcc, 0);
-        dcc_push_monitors_config(dcc);
-        red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK);
-        dcc_create_all_streams(dcc);
-    }
-}
-
 static GlzSharedDictionary *_red_find_glz_dictionary(RedClient *client, uint8_t dict_id)
 {
     RingItem *now;
@@ -6707,12 +6522,9 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
 {
     DisplayChannel *display_channel;
     DisplayChannelClient *dcc;
-    size_t stream_buf_size;
 
-    if (!worker->display_channel) {
-        spice_warning("Display channel was not created");
-        return;
-    }
+    spice_return_if_fail(worker->display_channel);
+
     display_channel = worker->display_channel;
     spice_info("add display channel client");
     dcc = dcc_new(display_channel, client, stream, migrate,
@@ -6721,14 +6533,6 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
     if (!dcc) {
         return;
     }
-    spice_info("New display (client %p) dcc %p stream %p", client, dcc, stream);
-    stream_buf_size = 32*1024;
-    dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size);
-    dcc->send_data.stream_outbuf_size = stream_buf_size;
-    dcc->send_data.free_list.res =
-        spice_malloc(sizeof(SpiceResourceList) +
-                     DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID));
-    dcc->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
 
     if (dcc->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
         display_channel->enable_jpeg = dcc->common.is_low_bandwidth;
@@ -6742,14 +6546,11 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
         display_channel->enable_zlib_glz_wrap = (dcc->zlib_glz_state ==
                                                  SPICE_WAN_COMPRESSION_ALWAYS);
     }
-
     spice_info("jpeg %s", display_channel->enable_jpeg ? "enabled" : "disabled");
     spice_info("zlib-over-glz %s", display_channel->enable_zlib_glz_wrap ? "enabled" : "disabled");
 
     guest_set_client_capabilities(worker);
-
-    dcc_init_stream_agents(dcc);
-    on_new_display_channel_client(dcc);
+    dcc_start(dcc);
 }
 
 static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream *stream,
@@ -7066,7 +6867,7 @@ static void flush_all_surfaces(DisplayChannel *display)
 
     for (x = 0; x < NUM_SURFACES; ++x) {
         if (display->surfaces[x].context.canvas) {
-            red_current_flush(display, x);
+            display_channel_current_flush(display, x);
         }
     }
 }
commit 85920bb2e9715bc9317c2717cb14cc58f31f28ef
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Sep 17 15:53:05 2013 +0200

    worker: start a DisplayChannelClient unit
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Fabiano Fidêncio <fidencio at redhat.com>

diff --git a/server/Makefile.am b/server/Makefile.am
index 5907dd2..669664a 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -138,6 +138,9 @@ libspice_server_la_SOURCES =			\
 	utils.h					\
 	stream.c					\
 	stream.h					\
+	dcc.c					\
+	dcc.h					\
+	display-limits.h			\
 	dcc-encoders.c					\
 	dcc-encoders.h					\
 	$(NULL)
diff --git a/server/dcc-encoders.c b/server/dcc-encoders.c
index 9916d20..90d0ce0 100644
--- a/server/dcc-encoders.c
+++ b/server/dcc-encoders.c
@@ -20,7 +20,6 @@
 #endif
 
 #include <glib.h>
-#include <setjmp.h>
 
 #include "dcc-encoders.h"
 #include "display-channel.h"
diff --git a/server/dcc-encoders.h b/server/dcc-encoders.h
index e22610f..cdb44ac 100644
--- a/server/dcc-encoders.h
+++ b/server/dcc-encoders.h
@@ -18,6 +18,7 @@
 #ifndef DCC_ENCODERS_H_
 #define DCC_ENCODERS_H_
 
+#include <setjmp.h>
 #include "common/marshaller.h"
 #include "common/quic.h"
 #include "red_channel.h"
diff --git a/server/dcc.c b/server/dcc.c
new file mode 100644
index 0000000..4a95735
--- /dev/null
+++ b/server/dcc.c
@@ -0,0 +1,141 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "dcc.h"
+#include "display-channel.h"
+
+DisplayChannelClient *dcc_new(DisplayChannel *display,
+                              RedClient *client, RedsStream *stream,
+                              int mig_target,
+                              uint32_t *common_caps, int num_common_caps,
+                              uint32_t *caps, int num_caps,
+                              SpiceImageCompression image_compression,
+                              spice_wan_compression_t jpeg_state,
+                              spice_wan_compression_t zlib_glz_state)
+
+{
+    DisplayChannelClient *dcc;
+
+    dcc = (DisplayChannelClient*)common_channel_new_client(
+        COMMON_CHANNEL(display), sizeof(DisplayChannelClient),
+        client, stream, mig_target, TRUE,
+        common_caps, num_common_caps,
+        caps, num_caps);
+    spice_return_val_if_fail(dcc, NULL);
+
+    ring_init(&dcc->palette_cache_lru);
+    dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
+    dcc->image_compression = image_compression;
+    dcc->jpeg_state = jpeg_state;
+    dcc->zlib_glz_state = zlib_glz_state;
+    // TODO: tune quality according to bandwidth
+    dcc->jpeg_quality = 85;
+
+    dcc_encoders_init(dcc);
+
+    return dcc;
+}
+
+void dcc_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent)
+{
+    StreamClipItem *item = stream_clip_item_new(dcc, agent);
+    int n_rects;
+
+    item->clip_type = SPICE_CLIP_TYPE_RECTS;
+
+    n_rects = pixman_region32_n_rects(&agent->clip);
+    item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
+    item->rects->num_rects = n_rects;
+    region_ret_rects(&agent->clip, item->rects->rects, n_rects);
+
+    red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), (PipeItem *)item);
+}
+
+static MonitorsConfigItem *monitors_config_item_new(RedChannel* channel,
+                                                    MonitorsConfig *monitors_config)
+{
+    MonitorsConfigItem *mci;
+
+    mci = (MonitorsConfigItem *)spice_malloc(sizeof(*mci));
+    mci->monitors_config = monitors_config;
+
+    red_channel_pipe_item_init(channel,
+                               &mci->pipe_item, PIPE_ITEM_TYPE_MONITORS_CONFIG);
+    return mci;
+}
+
+void dcc_push_monitors_config(DisplayChannelClient *dcc)
+{
+    DisplayChannel *dc = DCC_TO_DC(dcc);
+    MonitorsConfig *monitors_config = dc->monitors_config;
+    MonitorsConfigItem *mci;
+
+    if (monitors_config == NULL) {
+        spice_warning("monitors_config is NULL");
+        return;
+    }
+
+    if (!red_channel_client_test_remote_cap(&dcc->common.base,
+                                            SPICE_DISPLAY_CAP_MONITORS_CONFIG)) {
+        return;
+    }
+
+    mci = monitors_config_item_new(dcc->common.base.channel,
+                                   monitors_config_ref(dc->monitors_config));
+    red_channel_client_pipe_add(&dcc->common.base, &mci->pipe_item);
+    red_channel_client_push(&dcc->common.base);
+}
+
+static SurfaceDestroyItem *surface_destroy_item_new(RedChannel *channel,
+                                                    uint32_t surface_id)
+{
+    SurfaceDestroyItem *destroy;
+
+    destroy = spice_malloc(sizeof(SurfaceDestroyItem));
+    destroy->surface_destroy.surface_id = surface_id;
+    red_channel_pipe_item_init(channel, &destroy->pipe_item,
+                               PIPE_ITEM_TYPE_DESTROY_SURFACE);
+
+    return destroy;
+}
+
+void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
+{
+    DisplayChannel *display;
+    RedChannel *channel;
+    SurfaceDestroyItem *destroy;
+
+    if (!dcc) {
+        return;
+    }
+
+    display = DCC_TO_DC(dcc);
+    channel = RED_CHANNEL(display);
+
+    if (COMMON_CHANNEL(display)->during_target_migrate ||
+        !dcc->surface_client_created[surface_id]) {
+        return;
+    }
+
+    dcc->surface_client_created[surface_id] = FALSE;
+    destroy = surface_destroy_item_new(channel, surface_id);
+    red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy->pipe_item);
+}
diff --git a/server/dcc.h b/server/dcc.h
new file mode 100644
index 0000000..ee2e75f
--- /dev/null
+++ b/server/dcc.h
@@ -0,0 +1,134 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef DCC_H_
+# define DCC_H_
+
+#include "red_worker.h"
+#include "pixmap-cache.h"
+#include "cache-item.h"
+#include "dcc-encoders.h"
+#include "stream.h"
+#include "display-limits.h"
+
+#define PALETTE_CACHE_HASH_SHIFT 8
+#define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT)
+#define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1)
+#define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK)
+#define CLIENT_PALETTE_CACHE_SIZE 128
+
+/* Each drawable can refer to at most 3 images: src, brush and mask */
+#define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3
+
+typedef struct WaitForChannels {
+    SpiceMsgWaitForChannels header;
+    SpiceWaitForChannel buf[MAX_CACHE_CLIENTS];
+} WaitForChannels;
+
+typedef struct FreeList {
+    int res_size;
+    SpiceResourceList *res;
+    uint64_t sync[MAX_CACHE_CLIENTS];
+    WaitForChannels wait;
+} FreeList;
+
+struct DisplayChannelClient {
+    CommonChannelClient common;
+    SpiceImageCompression image_compression;
+    spice_wan_compression_t jpeg_state;
+    spice_wan_compression_t zlib_glz_state;
+    int jpeg_quality;
+    int zlib_level;
+
+    QuicData quic_data;
+    QuicContext *quic;
+    LzData lz_data;
+    LzContext  *lz;
+    JpegData jpeg_data;
+    JpegEncoderContext *jpeg;
+#ifdef USE_LZ4
+    Lz4Data lz4_data;
+    Lz4EncoderContext *lz4;
+#endif
+    ZlibData zlib_data;
+    ZlibEncoder *zlib;
+
+    int expect_init;
+
+    PixmapCache *pixmap_cache;
+    uint32_t pixmap_cache_generation;
+    int pending_pixmaps_sync;
+
+    CacheItem *palette_cache[PALETTE_CACHE_HASH_SIZE];
+    Ring palette_cache_lru;
+    long palette_cache_available;
+    uint32_t palette_cache_items;
+
+    struct {
+        uint32_t stream_outbuf_size;
+        uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
+
+        FreeList free_list;
+        uint64_t pixmap_cache_items[MAX_DRAWABLE_PIXMAP_CACHE_ITEMS];
+        int num_pixmap_cache_items;
+    } send_data;
+
+    /* global lz encoding entities */
+    GlzSharedDictionary *glz_dict;
+    GlzEncoderContext   *glz;
+    GlzData glz_data;
+
+    Ring glz_drawables;               // all the living lz drawable, ordered by encoding time
+    Ring glz_drawables_inst_to_free;               // list of instances to be freed
+    pthread_mutex_t glz_drawables_inst_to_free_lock;
+
+    uint8_t surface_client_created[NUM_SURFACES];
+    QRegion surface_client_lossy_region[NUM_SURFACES];
+
+    StreamAgent stream_agents[NUM_STREAMS];
+    int use_mjpeg_encoder_rate_control;
+    uint32_t streams_max_latency;
+    uint64_t streams_max_bit_rate;
+};
+
+#define DCC_TO_WORKER(dcc)                                              \
+    (SPICE_CONTAINEROF((dcc)->common.base.channel, CommonChannel, base)->worker)
+#define DCC_TO_DC(dcc)                                                  \
+     SPICE_CONTAINEROF((dcc)->common.base.channel, DisplayChannel, common.base)
+#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
+
+
+DisplayChannelClient*      dcc_new                                   (DisplayChannel *display,
+                                                                      RedClient *client,
+                                                                      RedsStream *stream,
+                                                                      int mig_target,
+                                                                      uint32_t *common_caps,
+                                                                      int num_common_caps,
+                                                                      uint32_t *caps,
+                                                                      int num_caps,
+                                                                      SpiceImageCompression image_compression,
+                                                                      spice_wan_compression_t jpeg_state,
+                                                                      spice_wan_compression_t zlib_glz_state);
+void                       dcc_push_monitors_config                  (DisplayChannelClient *dcc);
+void                       dcc_destroy_surface                       (DisplayChannelClient *dcc,
+                                                                      uint32_t surface_id);
+void                       dcc_stream_agent_clip                     (DisplayChannelClient* dcc,
+                                                                      StreamAgent *agent);
+void                       dcc_create_stream                         (DisplayChannelClient *dcc,
+                                                                      Stream *stream);
+
+#endif /* DCC_H_ */
diff --git a/server/display-channel.c b/server/display-channel.c
index d4fcc7e..9990c71 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -135,53 +135,6 @@ void display_channel_compress_stats_print(const DisplayChannel *display_channel)
 #endif
 }
 
-DisplayChannelClient *dcc_new(DisplayChannel *display,
-                              RedClient *client, RedsStream *stream,
-                              int mig_target,
-                              uint32_t *common_caps, int num_common_caps,
-                              uint32_t *caps, int num_caps,
-                              SpiceImageCompression image_compression,
-                              spice_wan_compression_t jpeg_state,
-                              spice_wan_compression_t zlib_glz_state)
-
-{
-    DisplayChannelClient *dcc;
-
-    dcc = (DisplayChannelClient*)common_channel_new_client(
-        (CommonChannel *)display, sizeof(DisplayChannelClient),
-        client, stream, mig_target, TRUE,
-        common_caps, num_common_caps,
-        caps, num_caps);
-    spice_return_val_if_fail(dcc, NULL);
-
-    ring_init(&dcc->palette_cache_lru);
-    dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
-    dcc->image_compression = image_compression;
-    dcc->jpeg_state = jpeg_state;
-    dcc->zlib_glz_state = zlib_glz_state;
-    // todo: tune quality according to bandwidth
-    dcc->jpeg_quality = 85;
-
-    dcc_encoders_init(dcc);
-
-    return dcc;
-}
-
-void dcc_add_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent)
-{
-    StreamClipItem *item = stream_clip_item_new(dcc, agent);
-    int n_rects;
-
-    item->clip_type = SPICE_CLIP_TYPE_RECTS;
-
-    n_rects = pixman_region32_n_rects(&agent->clip);
-    item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
-    item->rects->num_rects = n_rects;
-    region_ret_rects(&agent->clip, item->rects->rects, n_rects);
-
-    red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), (PipeItem *)item);
-}
-
 MonitorsConfig* monitors_config_ref(MonitorsConfig *monitors_config)
 {
     monitors_config->refs++;
@@ -227,82 +180,6 @@ MonitorsConfig* monitors_config_new(QXLHead *heads, ssize_t nheads, ssize_t max)
     return mc;
 }
 
-static MonitorsConfigItem *monitors_config_item_new(RedChannel* channel,
-                                                    MonitorsConfig *monitors_config)
-{
-    MonitorsConfigItem *mci;
-
-    mci = (MonitorsConfigItem *)spice_malloc(sizeof(*mci));
-    mci->monitors_config = monitors_config;
-
-    red_channel_pipe_item_init(channel,
-                               &mci->pipe_item, PIPE_ITEM_TYPE_MONITORS_CONFIG);
-    return mci;
-}
-
-static void red_monitors_config_item_add(DisplayChannelClient *dcc)
-{
-    DisplayChannel *dc = DCC_TO_DC(dcc);
-    MonitorsConfigItem *mci;
-
-    mci = monitors_config_item_new(dcc->common.base.channel,
-                                   monitors_config_ref(dc->monitors_config));
-    red_channel_client_pipe_add(&dcc->common.base, &mci->pipe_item);
-}
-
-void dcc_push_monitors_config(DisplayChannelClient *dcc)
-{
-    MonitorsConfig *monitors_config = DCC_TO_DC(dcc)->monitors_config;
-
-    if (monitors_config == NULL) {
-        spice_warning("monitors_config is NULL");
-        return;
-    }
-
-    if (!red_channel_client_test_remote_cap(&dcc->common.base,
-                                            SPICE_DISPLAY_CAP_MONITORS_CONFIG)) {
-        return;
-    }
-    red_monitors_config_item_add(dcc);
-    red_channel_client_push(&dcc->common.base);
-}
-
-static SurfaceDestroyItem *surface_destroy_item_new(RedChannel *channel,
-                                                    uint32_t surface_id)
-{
-    SurfaceDestroyItem *destroy;
-
-    destroy = spice_malloc(sizeof(SurfaceDestroyItem));
-    destroy->surface_destroy.surface_id = surface_id;
-    red_channel_pipe_item_init(channel, &destroy->pipe_item,
-                               PIPE_ITEM_TYPE_DESTROY_SURFACE);
-
-    return destroy;
-}
-
-void dcc_push_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
-{
-    DisplayChannel *display;
-    RedChannel *channel;
-    SurfaceDestroyItem *destroy;
-
-    if (!dcc) {
-        return;
-    }
-
-    display = DCC_TO_DC(dcc);
-    channel = RED_CHANNEL(display);
-
-    if (COMMON_CHANNEL(display)->during_target_migrate ||
-        !dcc->surface_client_created[surface_id]) {
-        return;
-    }
-
-    dcc->surface_client_created[surface_id] = FALSE;
-    destroy = surface_destroy_item_new(channel, surface_id);
-    red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy->pipe_item);
-}
-
 int display_channel_get_streams_timeout(DisplayChannel *display)
 {
     int timeout = INT_MAX;
@@ -395,7 +272,7 @@ void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id)
     region_destroy(&surface->draw_dirty_region);
     surface->context.canvas = NULL;
     FOREACH_DCC(display, link, next, dcc) {
-        dcc_push_destroy_surface(dcc, surface_id);
+        dcc_destroy_surface(dcc, surface_id);
     }
 
     spice_warn_if(!ring_is_empty(&surface->depend_on_me));
@@ -442,7 +319,7 @@ static void streams_update_visible_region(DisplayChannel *display, Drawable *dra
             if (region_intersects(&agent->vis_region, &drawable->tree_item.base.rgn)) {
                 region_exclude(&agent->vis_region, &drawable->tree_item.base.rgn);
                 region_exclude(&agent->clip, &drawable->tree_item.base.rgn);
-                dcc_add_stream_agent_clip(dcc, agent);
+                dcc_stream_agent_clip(dcc, agent);
             }
         }
     }
diff --git a/server/display-channel.h b/server/display-channel.h
index 90f8455..aba7dce 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -49,32 +49,9 @@
 #include "utils.h"
 #include "tree.h"
 #include "stream.h"
-#include "dcc-encoders.h"
+#include "dcc.h"
+#include "display-limits.h"
 
-#define PALETTE_CACHE_HASH_SHIFT 8
-#define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT)
-#define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1)
-#define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK)
-
-#define CLIENT_PALETTE_CACHE_SIZE 128
-
-/* Each drawable can refer to at most 3 images: src, brush and mask */
-#define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3
-
-#define NUM_STREAMS 50
-#define NUM_SURFACES 10000
-
-typedef struct WaitForChannels {
-    SpiceMsgWaitForChannels header;
-    SpiceWaitForChannel buf[MAX_CACHE_CLIENTS];
-} WaitForChannels;
-
-typedef struct FreeList {
-    int res_size;
-    SpiceResourceList *res;
-    uint64_t sync[MAX_CACHE_CLIENTS];
-    WaitForChannels wait;
-} FreeList;
 
 typedef struct DependItem {
     Drawable *drawable;
@@ -115,72 +92,6 @@ struct Drawable {
     SAFE_FOREACH(link, next, drawable,  &(drawable)->pipes, dpi, LINK_TO_DPI(link))
 
 
-struct DisplayChannelClient {
-    CommonChannelClient common;
-    SpiceImageCompression image_compression;
-    spice_wan_compression_t jpeg_state;
-    spice_wan_compression_t zlib_glz_state;
-    int jpeg_quality;
-    int zlib_level;
-
-    QuicData quic_data;
-    QuicContext *quic;
-    LzData lz_data;
-    LzContext  *lz;
-    JpegData jpeg_data;
-    JpegEncoderContext *jpeg;
-#ifdef USE_LZ4
-    Lz4Data lz4_data;
-    Lz4EncoderContext *lz4;
-#endif
-    ZlibData zlib_data;
-    ZlibEncoder *zlib;
-
-    int expect_init;
-
-    PixmapCache *pixmap_cache;
-    uint32_t pixmap_cache_generation;
-    int pending_pixmaps_sync;
-
-    CacheItem *palette_cache[PALETTE_CACHE_HASH_SIZE];
-    Ring palette_cache_lru;
-    long palette_cache_available;
-    uint32_t palette_cache_items;
-
-    struct {
-        uint32_t stream_outbuf_size;
-        uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
-
-        FreeList free_list;
-        uint64_t pixmap_cache_items[MAX_DRAWABLE_PIXMAP_CACHE_ITEMS];
-        int num_pixmap_cache_items;
-    } send_data;
-
-    /* global lz encoding entities */
-    GlzSharedDictionary *glz_dict;
-    GlzEncoderContext   *glz;
-    GlzData glz_data;
-
-    Ring glz_drawables;               // all the living lz drawable, ordered by encoding time
-    Ring glz_drawables_inst_to_free;               // list of instances to be freed
-    pthread_mutex_t glz_drawables_inst_to_free_lock;
-
-    uint8_t surface_client_created[NUM_SURFACES];
-    QRegion surface_client_lossy_region[NUM_SURFACES];
-
-    StreamAgent stream_agents[NUM_STREAMS];
-    int use_mjpeg_encoder_rate_control;
-    uint32_t streams_max_latency;
-    uint64_t streams_max_bit_rate;
-};
-
-#define DCC_TO_WORKER(dcc)                                              \
-    (SPICE_CONTAINEROF((dcc)->common.base.channel, CommonChannel, base)->worker)
-#define DCC_TO_DC(dcc)                                                  \
-     SPICE_CONTAINEROF((dcc)->common.base.channel, DisplayChannel, common.base)
-#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
-
-
 enum {
     PIPE_ITEM_TYPE_DRAW = PIPE_ITEM_TYPE_COMMON_LAST,
     PIPE_ITEM_TYPE_IMAGE,
@@ -198,25 +109,6 @@ enum {
     PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
 };
 
-DisplayChannelClient*      dcc_new                                   (DisplayChannel *display,
-                                                                      RedClient *client,
-                                                                      RedsStream *stream,
-                                                                      int mig_target,
-                                                                      uint32_t *common_caps,
-                                                                      int num_common_caps,
-                                                                      uint32_t *caps,
-                                                                      int num_caps,
-                                                                      SpiceImageCompression image_compression,
-                                                                      spice_wan_compression_t jpeg_state,
-                                                                      spice_wan_compression_t zlib_glz_state);
-void                       dcc_push_monitors_config                  (DisplayChannelClient *dcc);
-void                       dcc_push_destroy_surface                  (DisplayChannelClient *dcc,
-                                                                      uint32_t surface_id);
-void                       dcc_add_stream_agent_clip                 (DisplayChannelClient* dcc,
-                                                                      StreamAgent *agent);
-void                       dcc_create_stream                         (DisplayChannelClient *dcc,
-                                                                      Stream *stream);
-
 typedef struct DrawablePipeItem {
     RingItem base;  /* link for a list of pipe items held by Drawable */
     PipeItem dpi_pipe_item; /* link for the client's pipe itself */
diff --git a/server/display-limits.h b/server/display-limits.h
new file mode 100644
index 0000000..ce9206c
--- /dev/null
+++ b/server/display-limits.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef DISPLAY_LIMITS_H_
+#define DISPLAY_LIMITS_H_
+
+/** Maximum number of surfaces a guest can create */
+#define NUM_SURFACES 10000
+
+/** Maximum number of streams created by spice-server */
+#define NUM_STREAMS 50
+
+#endif /* DISPLAY_LIMITS_H_ */
diff --git a/server/red_worker.c b/server/red_worker.c
index 08048a9..7669854 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -274,7 +274,7 @@ void attach_stream(DisplayChannel *display, Drawable *drawable, Stream *stream)
         if (!region_is_equal(&clip_in_draw_dest, &drawable->tree_item.base.rgn)) {
             region_remove(&agent->clip, &drawable->red_drawable->bbox);
             region_or(&agent->clip, &drawable->tree_item.base.rgn);
-            dcc_add_stream_agent_clip(dcc, agent);
+            dcc_stream_agent_clip(dcc, agent);
         }
 #ifdef STREAM_STATS
         agent->stats.num_input_frames++;
@@ -933,7 +933,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
 
     /* stopping the client from playing older frames at once*/
     region_clear(&agent->clip);
-    dcc_add_stream_agent_clip(dcc, agent);
+    dcc_stream_agent_clip(dcc, agent);
 
     if (region_is_empty(&agent->vis_region)) {
         spice_debug("stream %d: vis region empty", stream_id);


More information about the Spice-commits mailing list