[Spice-commits] 10 commits - server/dcc.c server/dcc-encoders.c server/dcc-encoders.h server/dcc.h server/display-channel.c server/display-channel.h server/red_worker.c server/stream.c server/stream.h

Frediano Ziglio fziglio at kemper.freedesktop.org
Tue Nov 24 01:10:13 PST 2015


 server/dcc-encoders.c    |  131 +++++-
 server/dcc-encoders.h    |    7 
 server/dcc.c             |  427 +++++++++++++++++++
 server/dcc.h             |   29 +
 server/display-channel.c |  301 +++++++++++++-
 server/display-channel.h |   34 -
 server/red_worker.c      | 1009 +----------------------------------------------
 server/stream.c          |   56 ++
 server/stream.h          |    1 
 9 files changed, 980 insertions(+), 1015 deletions(-)

New commits:
commit 2efb507adb66343ef47ecb7b6c53b82ced331e65
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Nov 22 20:12:34 2015 +0000

    worker: fix constant
    
    Use mnemonic instead of constant to return enumeration value
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Fabiano Fidêncio <fidencio at redhat.com>

diff --git a/server/red_worker.c b/server/red_worker.c
index ea957b6..e0eebce 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1492,7 +1492,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
         spice_error("invalid image type %u", image.descriptor.type);
     }
     pthread_mutex_unlock(&dcc->pixmap_cache->lock);
-    return 0;
+    return FILL_BITS_TYPE_INVALID;
 }
 
 static void fill_mask(RedChannelClient *rcc, SpiceMarshaller *m,
commit 4e8f24e3510ce8cb3fa6b1ce5509b94cc1478917
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Thu Sep 26 23:04:01 2013 +0200

    worker: move drawable_draw
    
    Acked-by: Fabiano Fidêncio <fabiano at fidencio.org>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/display-channel.c b/server/display-channel.c
index ba7f443..5e75019 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -1000,6 +1000,22 @@ static Drawable* drawable_try_new(DisplayChannel *display)
     return drawable;
 }
 
+static void drawable_free(DisplayChannel *display, Drawable *drawable)
+{
+    ((_Drawable *)drawable)->u.next = display->free_drawables;
+    display->free_drawables = (_Drawable *)drawable;
+}
+
+void drawables_init(DisplayChannel *display)
+{
+    int i;
+
+    display->free_drawables = NULL;
+    for (i = 0; i < NUM_DRAWABLES; i++) {
+        drawable_free(display, &display->drawables[i].u.drawable);
+    }
+}
+
 Drawable *display_channel_drawable_try_new(DisplayChannel *display,
                                            int group_id, int process_commands_generation)
 {
@@ -1025,3 +1041,223 @@ Drawable *display_channel_drawable_try_new(DisplayChannel *display,
 
     return drawable;
 }
+
+static void depended_item_remove(DependItem *item)
+{
+    spice_return_if_fail(item->drawable);
+    spice_return_if_fail(ring_item_is_linked(&item->ring_item));
+
+    item->drawable = NULL;
+    ring_remove(&item->ring_item);
+}
+
+static void drawable_remove_dependencies(DisplayChannel *display, Drawable *drawable)
+{
+    int x;
+    int surface_id;
+
+    for (x = 0; x < 3; ++x) {
+        surface_id = drawable->surface_deps[x];
+        if (surface_id != -1 && drawable->depend_items[x].drawable) {
+            depended_item_remove(&drawable->depend_items[x]);
+        }
+    }
+}
+
+static void drawable_unref_surface_deps(DisplayChannel *display, Drawable *drawable)
+{
+    int x;
+    int surface_id;
+
+    for (x = 0; x < 3; ++x) {
+        surface_id = drawable->surface_deps[x];
+        if (surface_id == -1) {
+            continue;
+        }
+        display_channel_surface_unref(display, surface_id);
+    }
+}
+
+void display_channel_drawable_unref(DisplayChannel *display, Drawable *drawable)
+{
+    RingItem *item, *next;
+
+    if (--drawable->refs != 0)
+        return;
+
+    spice_warn_if_fail(!drawable->tree_item.shadow);
+    spice_warn_if_fail(ring_is_empty(&drawable->pipes));
+
+    if (drawable->stream) {
+        detach_stream(display, drawable->stream, TRUE);
+    }
+    region_destroy(&drawable->tree_item.base.rgn);
+
+    drawable_remove_dependencies(display, drawable);
+    drawable_unref_surface_deps(display, drawable);
+    display_channel_surface_unref(display, drawable->surface_id);
+
+    RING_FOREACH_SAFE(item, next, &drawable->glz_ring) {
+        SPICE_CONTAINEROF(item, RedGlzDrawable, drawable_link)->drawable = NULL;
+        ring_remove(item);
+    }
+    if (drawable->red_drawable) {
+        red_drawable_unref(COMMON_CHANNEL(display)->worker, drawable->red_drawable, drawable->group_id);
+    }
+    drawable_free(display, drawable);
+    display->drawable_count--;
+}
+
+static void drawable_deps_draw(DisplayChannel *display, Drawable *drawable)
+{
+    int x;
+    int surface_id;
+
+    for (x = 0; x < 3; ++x) {
+        surface_id = drawable->surface_deps[x];
+        if (surface_id != -1 && drawable->depend_items[x].drawable) {
+            depended_item_remove(&drawable->depend_items[x]);
+            display_channel_draw(display, &drawable->red_drawable->surfaces_rects[x], surface_id);
+        }
+    }
+}
+
+void drawable_draw(DisplayChannel *display, Drawable *drawable)
+{
+    RedSurface *surface;
+    SpiceCanvas *canvas;
+    SpiceClip clip = drawable->red_drawable->clip;
+
+    drawable_deps_draw(display, drawable);
+
+    surface = &display->surfaces[drawable->surface_id];
+    canvas = surface->context.canvas;
+    spice_return_if_fail(canvas);
+
+    image_cache_aging(&display->image_cache);
+
+    region_add(&surface->draw_dirty_region, &drawable->red_drawable->bbox);
+
+    switch (drawable->red_drawable->type) {
+    case QXL_DRAW_FILL: {
+        SpiceFill fill = drawable->red_drawable->u.fill;
+        SpiceImage img1, img2;
+        image_cache_localize_brush(&display->image_cache, &fill.brush, &img1);
+        image_cache_localize_mask(&display->image_cache, &fill.mask, &img2);
+        canvas->ops->draw_fill(canvas, &drawable->red_drawable->bbox,
+                               &clip, &fill);
+        break;
+    }
+    case QXL_DRAW_OPAQUE: {
+        SpiceOpaque opaque = drawable->red_drawable->u.opaque;
+        SpiceImage img1, img2, img3;
+        image_cache_localize_brush(&display->image_cache, &opaque.brush, &img1);
+        image_cache_localize(&display->image_cache, &opaque.src_bitmap, &img2, drawable);
+        image_cache_localize_mask(&display->image_cache, &opaque.mask, &img3);
+        canvas->ops->draw_opaque(canvas, &drawable->red_drawable->bbox, &clip, &opaque);
+        break;
+    }
+    case QXL_DRAW_COPY: {
+        SpiceCopy copy = drawable->red_drawable->u.copy;
+        SpiceImage img1, img2;
+        image_cache_localize(&display->image_cache, &copy.src_bitmap, &img1, drawable);
+        image_cache_localize_mask(&display->image_cache, &copy.mask, &img2);
+        canvas->ops->draw_copy(canvas, &drawable->red_drawable->bbox,
+                               &clip, &copy);
+        break;
+    }
+    case QXL_DRAW_TRANSPARENT: {
+        SpiceTransparent transparent = drawable->red_drawable->u.transparent;
+        SpiceImage img1;
+        image_cache_localize(&display->image_cache, &transparent.src_bitmap, &img1, drawable);
+        canvas->ops->draw_transparent(canvas,
+                                      &drawable->red_drawable->bbox, &clip, &transparent);
+        break;
+    }
+    case QXL_DRAW_ALPHA_BLEND: {
+        SpiceAlphaBlend alpha_blend = drawable->red_drawable->u.alpha_blend;
+        SpiceImage img1;
+        image_cache_localize(&display->image_cache, &alpha_blend.src_bitmap, &img1, drawable);
+        canvas->ops->draw_alpha_blend(canvas,
+                                      &drawable->red_drawable->bbox, &clip, &alpha_blend);
+        break;
+    }
+    case QXL_COPY_BITS: {
+        canvas->ops->copy_bits(canvas, &drawable->red_drawable->bbox,
+                               &clip, &drawable->red_drawable->u.copy_bits.src_pos);
+        break;
+    }
+    case QXL_DRAW_BLEND: {
+        SpiceBlend blend = drawable->red_drawable->u.blend;
+        SpiceImage img1, img2;
+        image_cache_localize(&display->image_cache, &blend.src_bitmap, &img1, drawable);
+        image_cache_localize_mask(&display->image_cache, &blend.mask, &img2);
+        canvas->ops->draw_blend(canvas, &drawable->red_drawable->bbox,
+                                &clip, &blend);
+        break;
+    }
+    case QXL_DRAW_BLACKNESS: {
+        SpiceBlackness blackness = drawable->red_drawable->u.blackness;
+        SpiceImage img1;
+        image_cache_localize_mask(&display->image_cache, &blackness.mask, &img1);
+        canvas->ops->draw_blackness(canvas,
+                                    &drawable->red_drawable->bbox, &clip, &blackness);
+        break;
+    }
+    case QXL_DRAW_WHITENESS: {
+        SpiceWhiteness whiteness = drawable->red_drawable->u.whiteness;
+        SpiceImage img1;
+        image_cache_localize_mask(&display->image_cache, &whiteness.mask, &img1);
+        canvas->ops->draw_whiteness(canvas,
+                                    &drawable->red_drawable->bbox, &clip, &whiteness);
+        break;
+    }
+    case QXL_DRAW_INVERS: {
+        SpiceInvers invers = drawable->red_drawable->u.invers;
+        SpiceImage img1;
+        image_cache_localize_mask(&display->image_cache, &invers.mask, &img1);
+        canvas->ops->draw_invers(canvas,
+                                 &drawable->red_drawable->bbox, &clip, &invers);
+        break;
+    }
+    case QXL_DRAW_ROP3: {
+        SpiceRop3 rop3 = drawable->red_drawable->u.rop3;
+        SpiceImage img1, img2, img3;
+        image_cache_localize_brush(&display->image_cache, &rop3.brush, &img1);
+        image_cache_localize(&display->image_cache, &rop3.src_bitmap, &img2, drawable);
+        image_cache_localize_mask(&display->image_cache, &rop3.mask, &img3);
+        canvas->ops->draw_rop3(canvas, &drawable->red_drawable->bbox,
+                               &clip, &rop3);
+        break;
+    }
+    case QXL_DRAW_COMPOSITE: {
+        SpiceComposite composite = drawable->red_drawable->u.composite;
+        SpiceImage src, mask;
+        image_cache_localize(&display->image_cache, &composite.src_bitmap, &src, drawable);
+        if (composite.mask_bitmap)
+            image_cache_localize(&display->image_cache, &composite.mask_bitmap, &mask, drawable);
+        canvas->ops->draw_composite(canvas, &drawable->red_drawable->bbox,
+                                    &clip, &composite);
+        break;
+    }
+    case QXL_DRAW_STROKE: {
+        SpiceStroke stroke = drawable->red_drawable->u.stroke;
+        SpiceImage img1;
+        image_cache_localize_brush(&display->image_cache, &stroke.brush, &img1);
+        canvas->ops->draw_stroke(canvas,
+                                 &drawable->red_drawable->bbox, &clip, &stroke);
+        break;
+    }
+    case QXL_DRAW_TEXT: {
+        SpiceText text = drawable->red_drawable->u.text;
+        SpiceImage img1, img2;
+        image_cache_localize_brush(&display->image_cache, &text.fore_brush, &img1);
+        image_cache_localize_brush(&display->image_cache, &text.back_brush, &img2);
+        canvas->ops->draw_text(canvas, &drawable->red_drawable->bbox,
+                               &clip, &text);
+        break;
+    }
+    default:
+        spice_warning("invalid type");
+    }
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index e624a6b..391e4ab 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -251,6 +251,13 @@ typedef struct UpgradeItem {
 } UpgradeItem;
 
 
+void                       display_channel_draw                      (DisplayChannel *display,
+                                                                      const SpiceRect *area,
+                                                                      int surface_id);
+void                       display_channel_draw_till                 (DisplayChannel *display,
+                                                                      const SpiceRect *area,
+                                                                      int surface_id,
+                                                                      Drawable *last);
 void                       display_channel_free_some                 (DisplayChannel *display);
 void                       display_channel_set_stream_video          (DisplayChannel *display,
                                                                       int stream_video);
@@ -395,5 +402,6 @@ void current_remove(DisplayChannel *display, TreeItem *item);
 void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable);
 void drawable_draw(DisplayChannel *display, Drawable *item);
 void current_remove_all(DisplayChannel *display, int surface_id);
+void drawables_init(DisplayChannel *display);
 
 #endif /* DISPLAY_CHANNEL_H_ */
diff --git a/server/red_worker.c b/server/red_worker.c
index 78af6cb..ea957b6 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -137,9 +137,6 @@ typedef struct BitmapData {
 
 static inline int validate_surface(DisplayChannel *display, uint32_t surface_id);
 
-static void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int surface_id);
-static void display_channel_draw_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
-                                      Drawable *last);
 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,
@@ -251,24 +248,6 @@ static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32
     }
 }
 
-
-static void drawable_free(DisplayChannel *display, Drawable *drawable)
-{
-    ((_Drawable *)drawable)->u.next = display->free_drawables;
-    display->free_drawables = (_Drawable *)drawable;
-}
-
-static void drawables_init(DisplayChannel *display)
-{
-    int i;
-
-    display->free_drawables = NULL;
-    for (i = 0; i < NUM_DRAWABLES; i++) {
-        drawable_free(display, &display->drawables[i].u.drawable);
-    }
-}
-
-
 static inline void set_surface_release_info(QXLReleaseInfoExt *release_info_ext,
                                             QXLReleaseInfo *release_info, uint32_t group_id)
 {
@@ -292,69 +271,6 @@ void red_drawable_unref(RedWorker *worker, RedDrawable *red_drawable,
     free(red_drawable);
 }
 
-static void remove_depended_item(DependItem *item)
-{
-    spice_assert(item->drawable);
-    spice_assert(ring_item_is_linked(&item->ring_item));
-    item->drawable = NULL;
-    ring_remove(&item->ring_item);
-}
-
-static void drawable_unref_surface_deps(DisplayChannel *display, Drawable *drawable)
-{
-    int x;
-    int surface_id;
-
-    for (x = 0; x < 3; ++x) {
-        surface_id = drawable->surface_deps[x];
-        if (surface_id == -1) {
-            continue;
-        }
-        display_channel_surface_unref(display, surface_id);
-    }
-}
-
-static void drawable_remove_dependencies(DisplayChannel *display, Drawable *drawable)
-{
-    int x;
-    int surface_id;
-
-    for (x = 0; x < 3; ++x) {
-        surface_id = drawable->surface_deps[x];
-        if (surface_id != -1 && drawable->depend_items[x].drawable) {
-            remove_depended_item(&drawable->depend_items[x]);
-        }
-    }
-}
-
-void display_channel_drawable_unref(DisplayChannel *display, Drawable *drawable)
-{
-    RingItem *item, *next;
-
-    if (--drawable->refs != 0)
-        return;
-
-    spice_warn_if_fail(!drawable->tree_item.shadow);
-    spice_warn_if_fail(ring_is_empty(&drawable->pipes));
-
-    if (drawable->stream) {
-        detach_stream(display, drawable->stream, TRUE);
-    }
-    region_destroy(&drawable->tree_item.base.rgn);
-
-    drawable_remove_dependencies(display, drawable);
-    drawable_unref_surface_deps(display, drawable);
-    display_channel_surface_unref(display, drawable->surface_id);
-
-    RING_FOREACH_SAFE(item, next, &drawable->glz_ring) {
-        SPICE_CONTAINEROF(item, RedGlzDrawable, drawable_link)->drawable = NULL;
-        ring_remove(item);
-    }
-    red_drawable_unref(COMMON_CHANNEL(display)->worker, drawable->red_drawable, drawable->group_id);
-    drawable_free(display, drawable);
-    display->drawable_count--;
-}
-
 static void display_stream_trace_add_drawable(DisplayChannel *display, Drawable *item)
 {
     ItemTrace *trace;
@@ -374,25 +290,6 @@ static void display_stream_trace_add_drawable(DisplayChannel *display, Drawable
     trace->dest_area = item->red_drawable->bbox;
 }
 
-static void surface_flush(DisplayChannel *display, int surface_id, SpiceRect *rect)
-{
-    display_channel_draw(display, rect, surface_id);
-}
-
-static void red_flush_source_surfaces(DisplayChannel *display, Drawable *drawable)
-{
-    int x;
-    int surface_id;
-
-    for (x = 0; x < 3; ++x) {
-        surface_id = drawable->surface_deps[x];
-        if (surface_id != -1 && drawable->depend_items[x].drawable) {
-            remove_depended_item(&drawable->depend_items[x]);
-            surface_flush(display, surface_id, &drawable->red_drawable->surfaces_rects[x]);
-        }
-    }
-}
-
 void current_remove_drawable(DisplayChannel *display, Drawable *item)
 {
     /* todo: move all to unref? */
@@ -843,7 +740,7 @@ static inline int red_handle_depends_on_target_surface(DisplayChannel *display,
         Drawable *drawable;
         DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item);
         drawable = depended_item->drawable;
-        surface_flush(display, drawable->surface_id, &drawable->red_drawable->bbox);
+        display_channel_draw(display, &drawable->red_drawable->bbox, drawable->surface_id);
     }
 
     return TRUE;
@@ -1039,146 +936,6 @@ static void image_surface_init(DisplayChannel *display)
     display->image_surfaces.ops = &image_surfaces_ops;
 }
 
-void drawable_draw(DisplayChannel *display, Drawable *drawable)
-{
-    RedSurface *surface;
-    SpiceCanvas *canvas;
-    SpiceClip clip = drawable->red_drawable->clip;
-
-    red_flush_source_surfaces(display, drawable);
-
-    surface = &display->surfaces[drawable->surface_id];
-    canvas = surface->context.canvas;
-    spice_return_if_fail(canvas);
-
-    image_cache_aging(&display->image_cache);
-
-    region_add(&surface->draw_dirty_region, &drawable->red_drawable->bbox);
-
-    switch (drawable->red_drawable->type) {
-    case QXL_DRAW_FILL: {
-        SpiceFill fill = drawable->red_drawable->u.fill;
-        SpiceImage img1, img2;
-        image_cache_localize_brush(&display->image_cache, &fill.brush, &img1);
-        image_cache_localize_mask(&display->image_cache, &fill.mask, &img2);
-        canvas->ops->draw_fill(canvas, &drawable->red_drawable->bbox,
-                               &clip, &fill);
-        break;
-    }
-    case QXL_DRAW_OPAQUE: {
-        SpiceOpaque opaque = drawable->red_drawable->u.opaque;
-        SpiceImage img1, img2, img3;
-        image_cache_localize_brush(&display->image_cache, &opaque.brush, &img1);
-        image_cache_localize(&display->image_cache, &opaque.src_bitmap, &img2, drawable);
-        image_cache_localize_mask(&display->image_cache, &opaque.mask, &img3);
-        canvas->ops->draw_opaque(canvas, &drawable->red_drawable->bbox, &clip, &opaque);
-        break;
-    }
-    case QXL_DRAW_COPY: {
-        SpiceCopy copy = drawable->red_drawable->u.copy;
-        SpiceImage img1, img2;
-        image_cache_localize(&display->image_cache, &copy.src_bitmap, &img1, drawable);
-        image_cache_localize_mask(&display->image_cache, &copy.mask, &img2);
-        canvas->ops->draw_copy(canvas, &drawable->red_drawable->bbox,
-                               &clip, &copy);
-        break;
-    }
-    case QXL_DRAW_TRANSPARENT: {
-        SpiceTransparent transparent = drawable->red_drawable->u.transparent;
-        SpiceImage img1;
-        image_cache_localize(&display->image_cache, &transparent.src_bitmap, &img1, drawable);
-        canvas->ops->draw_transparent(canvas,
-                                      &drawable->red_drawable->bbox, &clip, &transparent);
-        break;
-    }
-    case QXL_DRAW_ALPHA_BLEND: {
-        SpiceAlphaBlend alpha_blend = drawable->red_drawable->u.alpha_blend;
-        SpiceImage img1;
-        image_cache_localize(&display->image_cache, &alpha_blend.src_bitmap, &img1, drawable);
-        canvas->ops->draw_alpha_blend(canvas,
-                                      &drawable->red_drawable->bbox, &clip, &alpha_blend);
-        break;
-    }
-    case QXL_COPY_BITS: {
-        canvas->ops->copy_bits(canvas, &drawable->red_drawable->bbox,
-                               &clip, &drawable->red_drawable->u.copy_bits.src_pos);
-        break;
-    }
-    case QXL_DRAW_BLEND: {
-        SpiceBlend blend = drawable->red_drawable->u.blend;
-        SpiceImage img1, img2;
-        image_cache_localize(&display->image_cache, &blend.src_bitmap, &img1, drawable);
-        image_cache_localize_mask(&display->image_cache, &blend.mask, &img2);
-        canvas->ops->draw_blend(canvas, &drawable->red_drawable->bbox,
-                                &clip, &blend);
-        break;
-    }
-    case QXL_DRAW_BLACKNESS: {
-        SpiceBlackness blackness = drawable->red_drawable->u.blackness;
-        SpiceImage img1;
-        image_cache_localize_mask(&display->image_cache, &blackness.mask, &img1);
-        canvas->ops->draw_blackness(canvas,
-                                    &drawable->red_drawable->bbox, &clip, &blackness);
-        break;
-    }
-    case QXL_DRAW_WHITENESS: {
-        SpiceWhiteness whiteness = drawable->red_drawable->u.whiteness;
-        SpiceImage img1;
-        image_cache_localize_mask(&display->image_cache, &whiteness.mask, &img1);
-        canvas->ops->draw_whiteness(canvas,
-                                    &drawable->red_drawable->bbox, &clip, &whiteness);
-        break;
-    }
-    case QXL_DRAW_INVERS: {
-        SpiceInvers invers = drawable->red_drawable->u.invers;
-        SpiceImage img1;
-        image_cache_localize_mask(&display->image_cache, &invers.mask, &img1);
-        canvas->ops->draw_invers(canvas,
-                                 &drawable->red_drawable->bbox, &clip, &invers);
-        break;
-    }
-    case QXL_DRAW_ROP3: {
-        SpiceRop3 rop3 = drawable->red_drawable->u.rop3;
-        SpiceImage img1, img2, img3;
-        image_cache_localize_brush(&display->image_cache, &rop3.brush, &img1);
-        image_cache_localize(&display->image_cache, &rop3.src_bitmap, &img2, drawable);
-        image_cache_localize_mask(&display->image_cache, &rop3.mask, &img3);
-        canvas->ops->draw_rop3(canvas, &drawable->red_drawable->bbox,
-                               &clip, &rop3);
-        break;
-    }
-    case QXL_DRAW_COMPOSITE: {
-        SpiceComposite composite = drawable->red_drawable->u.composite;
-        SpiceImage src, mask;
-        image_cache_localize(&display->image_cache, &composite.src_bitmap, &src, drawable);
-        if (composite.mask_bitmap)
-            image_cache_localize(&display->image_cache, &composite.mask_bitmap, &mask, drawable);
-        canvas->ops->draw_composite(canvas, &drawable->red_drawable->bbox,
-                                    &clip, &composite);
-        break;
-    }
-    case QXL_DRAW_STROKE: {
-        SpiceStroke stroke = drawable->red_drawable->u.stroke;
-        SpiceImage img1;
-        image_cache_localize_brush(&display->image_cache, &stroke.brush, &img1);
-        canvas->ops->draw_stroke(canvas,
-                                 &drawable->red_drawable->bbox, &clip, &stroke);
-        break;
-    }
-    case QXL_DRAW_TEXT: {
-        SpiceText text = drawable->red_drawable->u.text;
-        SpiceImage img1, img2;
-        image_cache_localize_brush(&display->image_cache, &text.fore_brush, &img1);
-        image_cache_localize_brush(&display->image_cache, &text.back_brush, &img2);
-        canvas->ops->draw_text(canvas, &drawable->red_drawable->bbox,
-                               &clip, &text);
-        break;
-    }
-    default:
-        spice_warning("invalid type");
-    }
-}
-
 static void validate_area(DisplayChannel *display, const SpiceRect *area, uint32_t surface_id)
 {
     RedSurface *surface;
@@ -1205,8 +962,8 @@ static void validate_area(DisplayChannel *display, const SpiceRect *area, uint32
     Renders drawables for updating the requested area, but only drawables that are older
     than 'last' (exclusive).
 */
-static void display_channel_draw_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
-                                 Drawable *last)
+void display_channel_draw_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
+                          Drawable *last)
 {
     RedSurface *surface;
     Drawable *surface_last = NULL;
@@ -1283,7 +1040,7 @@ static void display_channel_draw_till(DisplayChannel *display, const SpiceRect *
     validate_area(display, area, surface_id);
 }
 
-static void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int surface_id)
+void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int surface_id)
 {
     RedSurface *surface;
     Ring *ring;
commit 56e0ef7c33e5cb4b87dcf38a99b86316c9962839
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Nov 23 16:44:32 2015 +0100

    worker: remove display_channel prefix from channel callbacks
    
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/red_worker.c b/server/red_worker.c
index 1880c30..78af6cb 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -3847,7 +3847,7 @@ static void red_marshall_stream_activate_report(RedChannelClient *rcc,
     spice_marshall_msg_display_stream_activate_report(base_marshaller, &msg);
 }
 
-static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
+static void send_item(RedChannelClient *rcc, PipeItem *pipe_item)
 {
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -3946,7 +3946,7 @@ static inline void red_push(RedWorker *worker)
     }
 }
 
-static void display_channel_client_on_disconnect(RedChannelClient *rcc)
+static void on_disconnect(RedChannelClient *rcc)
 {
     DisplayChannel *display;
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -4223,7 +4223,7 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
     flush_cursor_commands(worker);
 }
 
-static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
+static int handle_migrate_flush_mark(RedChannelClient *rcc)
 {
     DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedChannel *channel = RED_CHANNEL(display_channel);
@@ -4428,7 +4428,7 @@ RedChannel *red_worker_new_channel(RedWorker *worker, int size,
     return channel;
 }
 
-static void display_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
+static void hold_item(RedChannelClient *rcc, PipeItem *item)
 {
     spice_assert(item);
     switch (item->type) {
@@ -4449,7 +4449,7 @@ static void display_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item
     }
 }
 
-static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
+static void release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
 {
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
 
@@ -4462,11 +4462,11 @@ static void display_channel_create(RedWorker *worker, int migrate, int stream_vi
 {
     DisplayChannel *display_channel;
     ChannelCbs cbs = {
-        .on_disconnect = display_channel_client_on_disconnect,
-        .send_item = display_channel_send_item,
-        .hold_item = display_channel_hold_pipe_item,
-        .release_item = display_channel_release_item,
-        .handle_migrate_flush_mark = display_channel_handle_migrate_mark,
+        .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
     };
commit 742e3666ab354bd9e91b69586b981c475069f08b
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Nov 23 16:44:31 2015 +0100

    worker: move dcc_release_item
    
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/dcc.c b/server/dcc.c
index 5be3769..5d666cb 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -1394,3 +1394,127 @@ int dcc_handle_migrate_data(DisplayChannelClient *dcc, uint32_t size, void *mess
     red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
     return TRUE;
 }
+
+static void image_item_unref(ImageItem *item)
+{
+    if (--item->refs != 0)
+        return;
+
+    free(item);
+}
+
+static void upgrade_item_unref(DisplayChannel *display, UpgradeItem *item)
+{
+    if (--item->refs != 0)
+        return;
+
+    display_channel_drawable_unref(display, item->drawable);
+    free(item->rects);
+    free(item);
+}
+
+static void release_item_after_push(DisplayChannelClient *dcc, PipeItem *item)
+{
+    DisplayChannel *display = DCC_TO_DC(dcc);
+
+    switch (item->type) {
+    case PIPE_ITEM_TYPE_DRAW:
+        drawable_pipe_item_unref(SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item));
+        break;
+    case PIPE_ITEM_TYPE_STREAM_CLIP:
+        stream_clip_item_unref(dcc, (StreamClipItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_UPGRADE:
+        upgrade_item_unref(display, (UpgradeItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_IMAGE:
+        image_item_unref((ImageItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_VERB:
+        free(item);
+        break;
+    case PIPE_ITEM_TYPE_MONITORS_CONFIG: {
+        MonitorsConfigItem *monconf_item = SPICE_CONTAINEROF(item,
+                                                             MonitorsConfigItem, pipe_item);
+        monitors_config_unref(monconf_item->monitors_config);
+        free(item);
+        break;
+    }
+    default:
+        spice_critical("invalid item type");
+    }
+}
+
+// TODO: share code between before/after_push since most of the items need the same
+// release
+static void release_item_before_push(DisplayChannelClient *dcc, PipeItem *item)
+{
+    DisplayChannel *display = DCC_TO_DC(dcc);
+
+    spice_debug("item.type: %d", item->type);
+    switch (item->type) {
+    case PIPE_ITEM_TYPE_DRAW: {
+        DrawablePipeItem *dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
+        ring_remove(&dpi->base);
+        drawable_pipe_item_unref(dpi);
+        break;
+    }
+    case PIPE_ITEM_TYPE_STREAM_CREATE: {
+        StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent, create_item);
+        stream_agent_unref(display, agent);
+        break;
+    }
+    case PIPE_ITEM_TYPE_STREAM_CLIP:
+        stream_clip_item_unref(dcc, (StreamClipItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_STREAM_DESTROY: {
+        StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent, destroy_item);
+        stream_agent_unref(display, agent);
+        break;
+    }
+    case PIPE_ITEM_TYPE_UPGRADE:
+        upgrade_item_unref(display, (UpgradeItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_IMAGE:
+        image_item_unref((ImageItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_CREATE_SURFACE: {
+        SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(item, SurfaceCreateItem,
+                                                              pipe_item);
+        free(surface_create);
+        break;
+    }
+    case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
+        SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(item, SurfaceDestroyItem,
+                                                                pipe_item);
+        free(surface_destroy);
+        break;
+    }
+    case PIPE_ITEM_TYPE_MONITORS_CONFIG: {
+        MonitorsConfigItem *monconf_item = SPICE_CONTAINEROF(item,
+                                                             MonitorsConfigItem, pipe_item);
+        monitors_config_unref(monconf_item->monitors_config);
+        free(item);
+        break;
+    }
+    case PIPE_ITEM_TYPE_INVAL_ONE:
+    case PIPE_ITEM_TYPE_VERB:
+    case PIPE_ITEM_TYPE_MIGRATE_DATA:
+    case PIPE_ITEM_TYPE_PIXMAP_SYNC:
+    case PIPE_ITEM_TYPE_PIXMAP_RESET:
+    case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE:
+    case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT:
+        free(item);
+        break;
+    default:
+        spice_critical("invalid item type");
+    }
+}
+
+void dcc_release_item(DisplayChannelClient *dcc, PipeItem *item, int item_pushed)
+{
+    if (item_pushed)
+        release_item_after_push(dcc, item);
+    else
+        release_item_before_push(dcc, item);
+}
diff --git a/server/dcc.h b/server/dcc.h
index 94b9195..62261e8 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -195,6 +195,9 @@ void                       dcc_append_drawable                       (DisplayCha
 void                       dcc_add_drawable_after                    (DisplayChannelClient *dcc,
                                                                       Drawable *drawable,
                                                                       PipeItem *pos);
+void                       dcc_release_item                          (DisplayChannelClient *dcc,
+                                                                      PipeItem *item,
+                                                                      int item_pushed);
 
 typedef struct compress_send_data_t {
     void*    comp_buf;
diff --git a/server/display-channel.h b/server/display-channel.h
index e26a1d8..e624a6b 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -243,6 +243,13 @@ typedef struct SurfaceDestroyItem {
     PipeItem pipe_item;
 } SurfaceDestroyItem;
 
+typedef struct UpgradeItem {
+    PipeItem base;
+    int refs;
+    Drawable *drawable;
+    SpiceClipRects *rects;
+} UpgradeItem;
+
 
 void                       display_channel_free_some                 (DisplayChannel *display);
 void                       display_channel_set_stream_video          (DisplayChannel *display,
diff --git a/server/red_worker.c b/server/red_worker.c
index 549cd8b..1880c30 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -85,13 +85,6 @@ struct SpiceWatch {
 
 #define MAX_PIPE_SIZE 50
 
-typedef struct UpgradeItem {
-    PipeItem base;
-    int refs;
-    Drawable *drawable;
-    SpiceClipRects *rects;
-} UpgradeItem;
-
 struct RedWorker {
     pthread_t thread;
     clockid_t clockid;
@@ -148,10 +141,6 @@ static void display_channel_draw(DisplayChannel *display, const SpiceRect *area,
 static void display_channel_draw_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
                                       Drawable *last);
 static inline void display_begin_send_message(RedChannelClient *rcc);
-static void display_channel_client_release_item_before_push(DisplayChannelClient *dcc,
-                                                            PipeItem *item);
-static void display_channel_client_release_item_after_push(DisplayChannelClient *dcc,
-                                                           PipeItem *item);
 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);
@@ -238,23 +227,6 @@ void red_pipes_remove_drawable(Drawable *drawable)
     }
 }
 
-static void release_image_item(ImageItem *item)
-{
-    if (!--item->refs) {
-        free(item);
-    }
-}
-
-static void upgrade_item_unref(DisplayChannel *display, UpgradeItem *item)
-{
-    if (--item->refs != 0)
-        return;
-
-    display_channel_drawable_unref(display, item->drawable);
-    free(item->rects);
-    free(item);
-}
-
 static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size)
 {
     CommonChannel *common = SPICE_CONTAINEROF(rcc->channel, CommonChannel, base);
@@ -3956,7 +3928,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
         spice_error("invalid pipe item type");
     }
 
-    display_channel_client_release_item_before_push(dcc, pipe_item);
+    dcc_release_item(dcc, pipe_item, FALSE);
 
     // a message is pending
     if (red_channel_client_send_message_pending(rcc)) {
@@ -4477,116 +4449,12 @@ static void display_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item
     }
 }
 
-static void display_channel_client_release_item_after_push(DisplayChannelClient *dcc,
-                                                           PipeItem *item)
-{
-    DisplayChannel *display = DCC_TO_DC(dcc);
-
-    switch (item->type) {
-    case PIPE_ITEM_TYPE_DRAW:
-        drawable_pipe_item_unref(SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item));
-        break;
-    case PIPE_ITEM_TYPE_STREAM_CLIP:
-        stream_clip_item_unref(dcc, (StreamClipItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_UPGRADE:
-        upgrade_item_unref(display, (UpgradeItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_IMAGE:
-        release_image_item((ImageItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_VERB:
-        free(item);
-        break;
-    case PIPE_ITEM_TYPE_MONITORS_CONFIG: {
-        MonitorsConfigItem *monconf_item = SPICE_CONTAINEROF(item,
-                                                             MonitorsConfigItem, pipe_item);
-        monitors_config_unref(monconf_item->monitors_config);
-        free(item);
-        break;
-    }
-    default:
-        spice_critical("invalid item type");
-    }
-}
-
-// TODO: share code between before/after_push since most of the items need the same
-// release
-static void display_channel_client_release_item_before_push(DisplayChannelClient *dcc,
-                                                            PipeItem *item)
-{
-    DisplayChannel *display = DCC_TO_DC(dcc);
-
-    switch (item->type) {
-    case PIPE_ITEM_TYPE_DRAW: {
-        DrawablePipeItem *dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
-        ring_remove(&dpi->base);
-        drawable_pipe_item_unref(dpi);
-        break;
-    }
-    case PIPE_ITEM_TYPE_STREAM_CREATE: {
-        StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent, create_item);
-        stream_agent_unref(display, agent);
-        break;
-    }
-    case PIPE_ITEM_TYPE_STREAM_CLIP:
-        stream_clip_item_unref(dcc, (StreamClipItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_STREAM_DESTROY: {
-        StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent, destroy_item);
-        stream_agent_unref(display, agent);
-        break;
-    }
-    case PIPE_ITEM_TYPE_UPGRADE:
-        upgrade_item_unref(display, (UpgradeItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_IMAGE:
-        release_image_item((ImageItem *)item);
-        break;
-    case PIPE_ITEM_TYPE_CREATE_SURFACE: {
-        SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(item, SurfaceCreateItem,
-                                                              pipe_item);
-        free(surface_create);
-        break;
-    }
-    case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
-        SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(item, SurfaceDestroyItem,
-                                                                pipe_item);
-        free(surface_destroy);
-        break;
-    }
-    case PIPE_ITEM_TYPE_MONITORS_CONFIG: {
-        MonitorsConfigItem *monconf_item = SPICE_CONTAINEROF(item,
-                                                             MonitorsConfigItem, pipe_item);
-        monitors_config_unref(monconf_item->monitors_config);
-        free(item);
-        break;
-    }
-    case PIPE_ITEM_TYPE_INVAL_ONE:
-    case PIPE_ITEM_TYPE_VERB:
-    case PIPE_ITEM_TYPE_MIGRATE_DATA:
-    case PIPE_ITEM_TYPE_PIXMAP_SYNC:
-    case PIPE_ITEM_TYPE_PIXMAP_RESET:
-    case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE:
-    case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT:
-        free(item);
-        break;
-    default:
-        spice_critical("invalid item type");
-    }
-}
-
 static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
 {
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
 
     spice_assert(item);
-    if (item_pushed) {
-        display_channel_client_release_item_after_push(dcc, item);
-    } else {
-        spice_debug("not pushed (%d)", item->type);
-        display_channel_client_release_item_before_push(dcc, item);
-    }
+    dcc_release_item(dcc, item, item_pushed);
 }
 
 static void display_channel_create(RedWorker *worker, int migrate, int stream_video,
commit 956600cbc550b4bdbd5e156e148c022f12120b47
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Thu Sep 26 14:22:15 2013 +0200

    worker: simplify handle_migrate_data functions
    
    Acked-by: Fabiano Fidêncio <fidencio at redhat.com>

diff --git a/server/red_worker.c b/server/red_worker.c
index ae2bc7d..549cd8b 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4260,7 +4260,7 @@ static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
     return TRUE;
 }
 
-static uint64_t display_channel_handle_migrate_data_get_serial(RedChannelClient *rcc, uint32_t size, void *message)
+static uint64_t handle_migrate_data_get_serial(RedChannelClient *rcc, uint32_t size, void *message)
 {
     SpiceMigrateDataDisplay *migrate_data;
 
@@ -4269,7 +4269,7 @@ static uint64_t display_channel_handle_migrate_data_get_serial(RedChannelClient
     return migrate_data->message_serial;
 }
 
-static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
+static int handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
 {
     return dcc_handle_migrate_data(RCC_TO_DCC(rcc), size, message);
 }
@@ -4599,8 +4599,8 @@ static void display_channel_create(RedWorker *worker, int migrate, int stream_vi
         .hold_item = display_channel_hold_pipe_item,
         .release_item = display_channel_release_item,
         .handle_migrate_flush_mark = display_channel_handle_migrate_mark,
-        .handle_migrate_data = display_channel_handle_migrate_data,
-        .handle_migrate_data_get_serial = display_channel_handle_migrate_data_get_serial
+        .handle_migrate_data = handle_migrate_data,
+        .handle_migrate_data_get_serial = handle_migrate_data_get_serial
     };
 
     spice_return_if_fail(num_renderers > 0);
commit 5bd0fd9fe41593b344e2eaa0ca1982d3a4f8b836
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Thu Sep 26 14:22:15 2013 +0200

    worker: move dcc_handle_migrate_data
    
    Acked-by: Fabiano Fidêncio <fabiano at fidencio.org>

diff --git a/server/dcc.c b/server/dcc.c
index 1c82139..5be3769 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -1259,3 +1259,138 @@ int dcc_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void
         return red_channel_client_handle_message(rcc, size, type, msg);
     }
 }
+
+static int dcc_handle_migrate_glz_dictionary(DisplayChannelClient *dcc,
+                                             SpiceMigrateDataDisplay *migrate)
+{
+    spice_return_val_if_fail(!dcc->glz_dict, FALSE);
+
+    ring_init(&dcc->glz_drawables);
+    ring_init(&dcc->glz_drawables_inst_to_free);
+    pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
+    dcc->glz_dict = dcc_restore_glz_dictionary(dcc,
+                                               migrate->glz_dict_id,
+                                               &migrate->glz_dict_data);
+    return dcc->glz_dict != NULL;
+}
+
+static int restore_surface(DisplayChannelClient *dcc, uint32_t surface_id)
+{
+    /* we don't process commands till we receive the migration data, thus,
+     * we should have not sent any surface to the client. */
+    if (dcc->surface_client_created[surface_id]) {
+        spice_warning("surface %u is already marked as client_created", surface_id);
+        return FALSE;
+    }
+    dcc->surface_client_created[surface_id] = TRUE;
+    return TRUE;
+}
+
+static int restore_surfaces_lossless(DisplayChannelClient *dcc,
+                                         MigrateDisplaySurfacesAtClientLossless *mig_surfaces)
+{
+    uint32_t i;
+
+    spice_debug(NULL);
+    for (i = 0; i < mig_surfaces->num_surfaces; i++) {
+        uint32_t surface_id = mig_surfaces->surfaces[i].id;
+
+        if (!restore_surface(dcc, surface_id))
+            return FALSE;
+    }
+    return TRUE;
+}
+
+static int restore_surfaces_lossy(DisplayChannelClient *dcc,
+                                  MigrateDisplaySurfacesAtClientLossy *mig_surfaces)
+{
+    uint32_t i;
+
+    spice_debug(NULL);
+    for (i = 0; i < mig_surfaces->num_surfaces; i++) {
+        uint32_t surface_id = mig_surfaces->surfaces[i].id;
+        SpiceMigrateDataRect *mig_lossy_rect;
+        SpiceRect lossy_rect;
+
+        if (!restore_surface(dcc, surface_id))
+            return FALSE;
+
+        mig_lossy_rect = &mig_surfaces->surfaces[i].lossy_rect;
+        lossy_rect.left = mig_lossy_rect->left;
+        lossy_rect.top = mig_lossy_rect->top;
+        lossy_rect.right = mig_lossy_rect->right;
+        lossy_rect.bottom = mig_lossy_rect->bottom;
+        region_init(&dcc->surface_client_lossy_region[surface_id]);
+        region_add(&dcc->surface_client_lossy_region[surface_id], &lossy_rect);
+    }
+    return TRUE;
+}
+
+int dcc_handle_migrate_data(DisplayChannelClient *dcc, uint32_t size, void *message)
+{
+    DisplayChannel *display = DCC_TO_DC(dcc);
+    int surfaces_restored = FALSE;
+    SpiceMigrateDataHeader *header = (SpiceMigrateDataHeader *)message;
+    SpiceMigrateDataDisplay *migrate_data = (SpiceMigrateDataDisplay *)(header + 1);
+    uint8_t *surfaces;
+    int i;
+
+    spice_return_val_if_fail(
+        size >= (sizeof(*migrate_data) + sizeof(SpiceMigrateDataHeader)), FALSE);
+    spice_return_val_if_fail(
+         migration_protocol_validate_header(header,
+             SPICE_MIGRATE_DATA_DISPLAY_MAGIC, SPICE_MIGRATE_DATA_DISPLAY_VERSION), FALSE);
+
+    /* size is set to -1 in order to keep the cache frozen until the original
+     * channel client that froze the cache on the src size receives the migrate
+     * data and unfreezes the cache by setting its size > 0 and by triggering
+     * pixmap_cache_reset */
+    dcc->pixmap_cache = pixmap_cache_get(RED_CHANNEL_CLIENT(dcc)->client,
+                                         migrate_data->pixmap_cache_id, -1);
+    spice_return_val_if_fail(dcc->pixmap_cache, FALSE);
+
+    pthread_mutex_lock(&dcc->pixmap_cache->lock);
+    for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
+        dcc->pixmap_cache->sync[i] = MAX(dcc->pixmap_cache->sync[i],
+                                         migrate_data->pixmap_cache_clients[i]);
+    }
+    pthread_mutex_unlock(&dcc->pixmap_cache->lock);
+
+    if (migrate_data->pixmap_cache_freezer) {
+        /* activating the cache. The cache will start to be active after
+         * pixmap_cache_reset is called, when handling PIPE_ITEM_TYPE_PIXMAP_RESET */
+        dcc->pixmap_cache->size = migrate_data->pixmap_cache_size;
+        red_channel_client_pipe_add_type(RED_CHANNEL_CLIENT(dcc), PIPE_ITEM_TYPE_PIXMAP_RESET);
+    }
+
+    if (dcc_handle_migrate_glz_dictionary(dcc, migrate_data)) {
+        dcc->glz =
+            glz_encoder_create(dcc->common.id, dcc->glz_dict->dict, &dcc->glz_data.usr);
+    } else {
+        spice_critical("restoring global lz dictionary failed");
+    }
+
+    dcc->common.is_low_bandwidth = migrate_data->low_bandwidth_setting;
+
+    if (migrate_data->low_bandwidth_setting) {
+        red_channel_client_ack_set_client_window(RED_CHANNEL_CLIENT(dcc), WIDE_CLIENT_ACK_WINDOW);
+        if (dcc->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
+            display->enable_jpeg = TRUE;
+        }
+        if (dcc->zlib_glz_state == SPICE_WAN_COMPRESSION_AUTO) {
+            display->enable_zlib_glz_wrap = TRUE;
+        }
+    }
+
+    surfaces = (uint8_t *)message + migrate_data->surfaces_at_client_ptr;
+    surfaces_restored = display->enable_jpeg ?
+        restore_surfaces_lossy(dcc, (MigrateDisplaySurfacesAtClientLossy *)surfaces) :
+        restore_surfaces_lossless(dcc, (MigrateDisplaySurfacesAtClientLossless*)surfaces);
+
+    spice_return_val_if_fail(surfaces_restored, FALSE);
+
+    red_channel_client_pipe_add_type(RED_CHANNEL_CLIENT(dcc), PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
+    /* enable sending messages */
+    red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
+    return TRUE;
+}
diff --git a/server/dcc.h b/server/dcc.h
index 12bb38e..94b9195 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -38,6 +38,9 @@
 /* Each drawable can refer to at most 3 images: src, brush and mask */
 #define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3
 
+#define WIDE_CLIENT_ACK_WINDOW 40
+#define NARROW_CLIENT_ACK_WINDOW 20
+
 typedef struct WaitForChannels {
     SpiceMsgWaitForChannels header;
     SpiceWaitForChannel buf[MAX_CACHE_CLIENTS];
@@ -161,6 +164,8 @@ void                       dcc_start                                 (DisplayCha
 int                        dcc_handle_message                        (RedChannelClient *rcc,
                                                                       uint32_t size,
                                                                       uint16_t type, void *msg);
+int                        dcc_handle_migrate_data                   (DisplayChannelClient *dcc,
+                                                                      uint32_t size, void *message);
 void                       dcc_push_monitors_config                  (DisplayChannelClient *dcc);
 void                       dcc_destroy_surface                       (DisplayChannelClient *dcc,
                                                                       uint32_t surface_id);
diff --git a/server/red_worker.c b/server/red_worker.c
index f64befa..ae2bc7d 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -85,9 +85,6 @@ struct SpiceWatch {
 
 #define MAX_PIPE_SIZE 50
 
-#define WIDE_CLIENT_ACK_WINDOW 40
-#define NARROW_CLIENT_ACK_WINDOW 20
-
 typedef struct UpgradeItem {
     PipeItem base;
     int refs;
@@ -4254,20 +4251,6 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
     flush_cursor_commands(worker);
 }
 
-static int dcc_handle_migrate_glz_dictionary(DisplayChannelClient *dcc,
-                                             SpiceMigrateDataDisplay *migrate)
-{
-    spice_return_val_if_fail(!dcc->glz_dict, FALSE);
-
-    ring_init(&dcc->glz_drawables);
-    ring_init(&dcc->glz_drawables_inst_to_free);
-    pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
-    dcc->glz_dict = dcc_restore_glz_dictionary(dcc,
-                                               migrate->glz_dict_id,
-                                               &migrate->glz_dict_data);
-    return dcc->glz_dict != NULL;
-}
-
 static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
 {
     DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
@@ -4277,8 +4260,7 @@ static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
     return TRUE;
 }
 
-static uint64_t display_channel_handle_migrate_data_get_serial(
-                RedChannelClient *rcc, uint32_t size, void *message)
+static uint64_t display_channel_handle_migrate_data_get_serial(RedChannelClient *rcc, uint32_t size, void *message)
 {
     SpiceMigrateDataDisplay *migrate_data;
 
@@ -4287,146 +4269,9 @@ static uint64_t display_channel_handle_migrate_data_get_serial(
     return migrate_data->message_serial;
 }
 
-static int display_channel_client_restore_surface(DisplayChannelClient *dcc, uint32_t surface_id)
-{
-    /* we don't process commands till we receive the migration data, thus,
-     * we should have not sent any surface to the client. */
-    if (dcc->surface_client_created[surface_id]) {
-        spice_warning("surface %u is already marked as client_created", surface_id);
-        return FALSE;
-    }
-    dcc->surface_client_created[surface_id] = TRUE;
-    return TRUE;
-}
-
-static int display_channel_client_restore_surfaces_lossless(DisplayChannelClient *dcc,
-                                                            MigrateDisplaySurfacesAtClientLossless *mig_surfaces)
+static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
 {
-    uint32_t i;
-
-    spice_debug(NULL);
-    for (i = 0; i < mig_surfaces->num_surfaces; i++) {
-        uint32_t surface_id = mig_surfaces->surfaces[i].id;
-
-        if (!display_channel_client_restore_surface(dcc, surface_id)) {
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-static int display_channel_client_restore_surfaces_lossy(DisplayChannelClient *dcc,
-                                                          MigrateDisplaySurfacesAtClientLossy *mig_surfaces)
-{
-    uint32_t i;
-
-    spice_debug(NULL);
-    for (i = 0; i < mig_surfaces->num_surfaces; i++) {
-        uint32_t surface_id = mig_surfaces->surfaces[i].id;
-        SpiceMigrateDataRect *mig_lossy_rect;
-        SpiceRect lossy_rect;
-
-        if (!display_channel_client_restore_surface(dcc, surface_id)) {
-            return FALSE;
-        }
-        spice_assert(dcc->surface_client_created[surface_id]);
-
-        mig_lossy_rect = &mig_surfaces->surfaces[i].lossy_rect;
-        lossy_rect.left = mig_lossy_rect->left;
-        lossy_rect.top = mig_lossy_rect->top;
-        lossy_rect.right = mig_lossy_rect->right;
-        lossy_rect.bottom = mig_lossy_rect->bottom;
-        region_init(&dcc->surface_client_lossy_region[surface_id]);
-        region_add(&dcc->surface_client_lossy_region[surface_id], &lossy_rect);
-    }
-    return TRUE;
-}
-static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size,
-                                               void *message)
-{
-    SpiceMigrateDataHeader *header;
-    SpiceMigrateDataDisplay *migrate_data;
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
-    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
-    uint8_t *surfaces;
-    int surfaces_restored = FALSE;
-    int i;
-
-    spice_debug(NULL);
-    if (size < sizeof(*migrate_data) + sizeof(SpiceMigrateDataHeader)) {
-        spice_error("bad message size");
-        return FALSE;
-    }
-    header = (SpiceMigrateDataHeader *)message;
-    migrate_data = (SpiceMigrateDataDisplay *)(header + 1);
-    if (!migration_protocol_validate_header(header,
-                                            SPICE_MIGRATE_DATA_DISPLAY_MAGIC,
-                                            SPICE_MIGRATE_DATA_DISPLAY_VERSION)) {
-        spice_error("bad header");
-        return FALSE;
-    }
-    /* size is set to -1 in order to keep the cache frozen until the original
-     * channel client that froze the cache on the src size receives the migrate
-     * data and unfreezes the cache by setting its size > 0 and by triggering
-     * pixmap_cache_reset */
-    dcc->pixmap_cache = pixmap_cache_get(RED_CHANNEL_CLIENT(dcc)->client,
-                                         migrate_data->pixmap_cache_id, -1);
-    if (!dcc->pixmap_cache) {
-        return FALSE;
-    }
-    pthread_mutex_lock(&dcc->pixmap_cache->lock);
-    for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
-        dcc->pixmap_cache->sync[i] = MAX(dcc->pixmap_cache->sync[i],
-                                         migrate_data->pixmap_cache_clients[i]);
-    }
-    pthread_mutex_unlock(&dcc->pixmap_cache->lock);
-
-    if (migrate_data->pixmap_cache_freezer) {
-        /* activating the cache. The cache will start to be active after
-         * pixmap_cache_reset is called, when handling PIPE_ITEM_TYPE_PIXMAP_RESET */
-        dcc->pixmap_cache->size = migrate_data->pixmap_cache_size;
-        red_channel_client_pipe_add_type(rcc,
-                                         PIPE_ITEM_TYPE_PIXMAP_RESET);
-    }
-
-    if (dcc_handle_migrate_glz_dictionary(dcc, migrate_data)) {
-        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");
-        }
-    } else {
-        spice_critical("restoring global lz dictionary failed");
-    }
-
-    dcc->common.is_low_bandwidth = migrate_data->low_bandwidth_setting;
-
-    if (migrate_data->low_bandwidth_setting) {
-        red_channel_client_ack_set_client_window(rcc, WIDE_CLIENT_ACK_WINDOW);
-        if (dcc->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
-            display_channel->enable_jpeg = TRUE;
-        }
-        if (dcc->zlib_glz_state == SPICE_WAN_COMPRESSION_AUTO) {
-            display_channel->enable_zlib_glz_wrap = TRUE;
-        }
-    }
-
-    surfaces = (uint8_t *)message + migrate_data->surfaces_at_client_ptr;
-    if (display_channel->enable_jpeg) {
-        surfaces_restored = display_channel_client_restore_surfaces_lossy(dcc,
-                                (MigrateDisplaySurfacesAtClientLossy *)surfaces);
-    } else {
-        surfaces_restored = display_channel_client_restore_surfaces_lossless(dcc,
-                                (MigrateDisplaySurfacesAtClientLossless*)surfaces);
-    }
-
-    if (!surfaces_restored) {
-        return FALSE;
-    }
-    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
-    /* enable sending messages */
-    red_channel_client_ack_zero_messages_window(rcc);
-    return TRUE;
+    return dcc_handle_migrate_data(RCC_TO_DCC(rcc), size, message);
 }
 
 static int common_channel_config_socket(RedChannelClient *rcc)
commit acba59bb9b0e3a5e362139b00f49006e90bbde11
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Wed Sep 25 16:05:30 2013 +0200

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

diff --git a/server/red_worker.c b/server/red_worker.c
index 443e00a..f64befa 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -159,50 +159,6 @@ static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uin
                                uint32_t height, int32_t stride, uint32_t format,
                                void *line_0, int data_is_valid, int send_client);
 
-void attach_stream(DisplayChannel *display, Drawable *drawable, Stream *stream)
-{
-    DisplayChannelClient *dcc;
-    RingItem *item, *next;
-
-    spice_assert(!drawable->stream && !stream->current);
-    spice_assert(drawable && stream);
-    stream->current = drawable;
-    drawable->stream = stream;
-    stream->last_time = drawable->creation_time;
-
-    uint64_t duration = drawable->creation_time - stream->input_fps_start_time;
-    if (duration >= RED_STREAM_INPUT_FPS_TIMEOUT) {
-        /* Round to the nearest integer, for instance 24 for 23.976 */
-        stream->input_fps = ((uint64_t)stream->num_input_frames * 1000 * 1000 * 1000 + duration / 2) / duration;
-        spice_debug("input-fps=%u", stream->input_fps);
-        stream->num_input_frames = 0;
-        stream->input_fps_start_time = drawable->creation_time;
-    } else {
-        stream->num_input_frames++;
-    }
-
-    FOREACH_DCC(display, item, next, dcc) {
-        StreamAgent *agent;
-        QRegion clip_in_draw_dest;
-
-        agent = &dcc->stream_agents[get_stream_id(display, stream)];
-        region_or(&agent->vis_region, &drawable->tree_item.base.rgn);
-
-        region_init(&clip_in_draw_dest);
-        region_add(&clip_in_draw_dest, &drawable->red_drawable->bbox);
-        region_and(&clip_in_draw_dest, &agent->clip);
-
-        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_stream_agent_clip(dcc, agent);
-        }
-#ifdef STREAM_STATS
-        agent->stats.num_input_frames++;
-#endif
-    }
-}
-
 QXLInstance* red_worker_get_qxl(RedWorker *worker)
 {
     spice_return_val_if_fail(worker != NULL, NULL);
@@ -624,18 +580,6 @@ static void red_clear_surface_drawables_from_pipes(DisplayChannel *display,
     }
 }
 
-void detach_stream(DisplayChannel *display, Stream *stream,
-                   int detach_sized)
-{
-    spice_assert(stream->current && stream->current->stream);
-    spice_assert(stream->current->stream == stream);
-    stream->current->stream = NULL;
-    if (detach_sized) {
-        stream->current->sized_stream = NULL;
-    }
-    stream->current = NULL;
-}
-
 static int red_display_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
 {
     DrawablePipeItem *dpi;
diff --git a/server/stream.c b/server/stream.c
index 518e2d8..8d16658 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -258,6 +258,62 @@ static int is_next_stream_frame(DisplayChannel *display,
     }
 }
 
+static void attach_stream(DisplayChannel *display, Drawable *drawable, Stream *stream)
+{
+    DisplayChannelClient *dcc;
+    RingItem *item, *next;
+
+    spice_assert(!drawable->stream && !stream->current);
+    spice_assert(drawable && stream);
+    stream->current = drawable;
+    drawable->stream = stream;
+    stream->last_time = drawable->creation_time;
+
+    uint64_t duration = drawable->creation_time - stream->input_fps_start_time;
+    if (duration >= RED_STREAM_INPUT_FPS_TIMEOUT) {
+        /* Round to the nearest integer, for instance 24 for 23.976 */
+        stream->input_fps = ((uint64_t)stream->num_input_frames * 1000 * 1000 * 1000 + duration / 2) / duration;
+        spice_debug("input-fps=%u", stream->input_fps);
+        stream->num_input_frames = 0;
+        stream->input_fps_start_time = drawable->creation_time;
+    } else {
+        stream->num_input_frames++;
+    }
+
+    FOREACH_DCC(display, item, next, dcc) {
+        StreamAgent *agent;
+        QRegion clip_in_draw_dest;
+
+        agent = &dcc->stream_agents[get_stream_id(display, stream)];
+        region_or(&agent->vis_region, &drawable->tree_item.base.rgn);
+
+        region_init(&clip_in_draw_dest);
+        region_add(&clip_in_draw_dest, &drawable->red_drawable->bbox);
+        region_and(&clip_in_draw_dest, &agent->clip);
+
+        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_stream_agent_clip(dcc, agent);
+        }
+#ifdef STREAM_STATS
+        agent->stats.num_input_frames++;
+#endif
+    }
+}
+
+void detach_stream(DisplayChannel *display, Stream *stream,
+                   int detach_sized)
+{
+    spice_assert(stream->current && stream->current->stream);
+    spice_assert(stream->current->stream == stream);
+    stream->current->stream = NULL;
+    if (detach_sized) {
+        stream->current->sized_stream = NULL;
+    }
+    stream->current = NULL;
+}
+
 static void before_reattach_stream(DisplayChannel *display,
                                    Stream *stream, Drawable *new_frame)
 {
diff --git a/server/stream.h b/server/stream.h
index 65de2f4..7c589e4 100644
--- a/server/stream.h
+++ b/server/stream.h
@@ -154,7 +154,6 @@ void                  stream_agent_unref                            (DisplayChan
 void                  stream_agent_stats_print                      (StreamAgent *agent);
 void                  stream_agent_stop                             (StreamAgent *agent);
 
-void attach_stream(DisplayChannel *display, Drawable *drawable, Stream *stream);
 void detach_stream(DisplayChannel *display, Stream *stream, int detach_sized);
 
 #endif /* STREAM_H */
commit 6df1558523c624dbbf414a034e673d277fe8a439
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Wed Sep 25 18:31:39 2013 +0200

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

diff --git a/server/dcc.c b/server/dcc.c
index ec0295a..1c82139 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -155,6 +155,93 @@ void dcc_push_surface_image(DisplayChannelClient *dcc, int surface_id)
     red_channel_client_push(RED_CHANNEL_CLIENT(dcc));
 }
 
+static void add_drawable_surface_images(DisplayChannelClient *dcc, Drawable *drawable)
+{
+    DisplayChannel *display = DCC_TO_DC(dcc);
+    int x;
+
+    for (x = 0; x < 3; ++x) {
+        int surface_id;
+
+        surface_id = drawable->surface_deps[x];
+        if (surface_id != -1) {
+            if (dcc->surface_client_created[surface_id] == TRUE) {
+                continue;
+            }
+            dcc_create_surface(dcc, surface_id);
+            display_channel_current_flush(display, surface_id);
+            dcc_push_surface_image(dcc, surface_id);
+        }
+    }
+
+    if (dcc->surface_client_created[drawable->surface_id] == TRUE) {
+        return;
+    }
+
+    dcc_create_surface(dcc, drawable->surface_id);
+    display_channel_current_flush(display, drawable->surface_id);
+    dcc_push_surface_image(dcc, drawable->surface_id);
+}
+
+DrawablePipeItem *drawable_pipe_item_ref(DrawablePipeItem *dpi)
+{
+    dpi->refs++;
+    return dpi;
+}
+
+void drawable_pipe_item_unref(DrawablePipeItem *dpi)
+{
+    DisplayChannel *display = DCC_TO_DC(dpi->dcc);
+
+    if (--dpi->refs != 0)
+        return;
+
+    spice_warn_if_fail(!ring_item_is_linked(&dpi->dpi_pipe_item.link));
+    spice_warn_if_fail(!ring_item_is_linked(&dpi->base));
+    display_channel_drawable_unref(display, dpi->drawable);
+    free(dpi);
+}
+
+static DrawablePipeItem *drawable_pipe_item_new(DisplayChannelClient *dcc, Drawable *drawable)
+{
+    DrawablePipeItem *dpi;
+
+    dpi = spice_malloc0(sizeof(*dpi));
+    dpi->drawable = drawable;
+    dpi->dcc = dcc;
+    ring_item_init(&dpi->base);
+    ring_add(&drawable->pipes, &dpi->base);
+    red_channel_pipe_item_init(RED_CHANNEL_CLIENT(dcc)->channel,
+                               &dpi->dpi_pipe_item, PIPE_ITEM_TYPE_DRAW);
+    dpi->refs++;
+    drawable->refs++;
+    return dpi;
+}
+
+void dcc_prepend_drawable(DisplayChannelClient *dcc, Drawable *drawable)
+{
+    DrawablePipeItem *dpi = drawable_pipe_item_new(dcc, drawable);
+
+    add_drawable_surface_images(dcc, drawable);
+    red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item);
+}
+
+void dcc_append_drawable(DisplayChannelClient *dcc, Drawable *drawable)
+{
+    DrawablePipeItem *dpi = drawable_pipe_item_new(dcc, drawable);
+
+    add_drawable_surface_images(dcc, drawable);
+    red_channel_client_pipe_add_tail(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item);
+}
+
+void dcc_add_drawable_after(DisplayChannelClient *dcc, Drawable *drawable, PipeItem *pos)
+{
+    DrawablePipeItem *dpi = drawable_pipe_item_new(dcc, drawable);
+
+    add_drawable_surface_images(dcc, drawable);
+    red_channel_client_pipe_add_after(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item, pos);
+}
+
 static void dcc_init_stream_agents(DisplayChannelClient *dcc)
 {
     int i;
diff --git a/server/dcc.h b/server/dcc.h
index a6e1cc7..12bb38e 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -135,6 +135,17 @@ typedef struct ImageItem {
     uint8_t data[0];
 } ImageItem;
 
+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 */
+    Drawable *drawable;
+    DisplayChannelClient *dcc;
+    uint8_t refs;
+} DrawablePipeItem;
+
+void                       drawable_pipe_item_unref                  (DrawablePipeItem *dpi);
+DrawablePipeItem*          drawable_pipe_item_ref                    (DrawablePipeItem *dpi);
+
 DisplayChannelClient*      dcc_new                                   (DisplayChannel *display,
                                                                       RedClient *client,
                                                                       RedsStream *stream,
@@ -172,6 +183,13 @@ void                       dcc_palette_cache_palette                 (DisplayCha
                                                                       uint8_t *flags);
 int                        dcc_pixmap_cache_unlocked_add             (DisplayChannelClient *dcc,
                                                                       uint64_t id, uint32_t size, int lossy);
+void                       dcc_prepend_drawable                      (DisplayChannelClient *dcc,
+                                                                      Drawable *drawable);
+void                       dcc_append_drawable                       (DisplayChannelClient *dcc,
+                                                                      Drawable *drawable);
+void                       dcc_add_drawable_after                    (DisplayChannelClient *dcc,
+                                                                      Drawable *drawable,
+                                                                      PipeItem *pos);
 
 typedef struct compress_send_data_t {
     void*    comp_buf;
diff --git a/server/display-channel.c b/server/display-channel.c
index 0be3e42..ba7f443 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -325,6 +325,50 @@ static void streams_update_visible_region(DisplayChannel *display, Drawable *dra
     }
 }
 
+static void pipes_add_drawable(DisplayChannel *display, Drawable *drawable)
+{
+    DisplayChannelClient *dcc;
+    RingItem *dcc_ring_item, *next;
+
+    spice_warn_if(!ring_is_empty(&drawable->pipes));
+    FOREACH_DCC(display, dcc_ring_item, next, dcc) {
+        dcc_prepend_drawable(dcc, drawable);
+    }
+}
+
+static void pipes_add_drawable_after(DisplayChannel *display,
+                                     Drawable *drawable, Drawable *pos_after)
+{
+    DrawablePipeItem *dpi_pos_after;
+    RingItem *dpi_link, *dpi_next;
+    DisplayChannelClient *dcc;
+    int num_other_linked = 0;
+
+    DRAWABLE_FOREACH_DPI_SAFE(pos_after, dpi_link, dpi_next, dpi_pos_after) {
+        num_other_linked++;
+        dcc_add_drawable_after(dpi_pos_after->dcc, drawable, &dpi_pos_after->dpi_pipe_item);
+    }
+    if (num_other_linked == 0) {
+        pipes_add_drawable(display, drawable);
+        return;
+    }
+    if (num_other_linked != display->common.base.clients_num) {
+        RingItem *item, *next;
+        spice_debug("TODO: not O(n^2)");
+        FOREACH_DCC(display, item, next, dcc) {
+            int sent = 0;
+            DRAWABLE_FOREACH_DPI_SAFE(pos_after, dpi_link, dpi_next, dpi_pos_after) {
+                if (dpi_pos_after->dcc == dcc) {
+                    sent = 1;
+                    break;
+                }
+            }
+            if (!sent) {
+                dcc_prepend_drawable(dcc, drawable);
+            }
+        }
+    }
+}
 
 static void current_add_drawable(DisplayChannel *display,
                                  Drawable *drawable, RingItem *pos)
@@ -366,9 +410,9 @@ static int current_add_equal(DisplayChannel *display, DrawItem *item, TreeItem *
         other_drawable->refs++;
         current_remove_drawable(display, other_drawable);
         if (add_after) {
-            red_pipes_add_drawable_after(display, drawable, other_drawable);
+            pipes_add_drawable_after(display, drawable, other_drawable);
         } else {
-            red_pipes_add_drawable(display, drawable);
+            pipes_add_drawable(display, drawable);
         }
         red_pipes_remove_drawable(other_drawable);
         display_channel_drawable_unref(display, other_drawable);
@@ -396,7 +440,7 @@ static int current_add_equal(DisplayChannel *display, DrawItem *item, TreeItem *
                                         common.base.channel_link);
                 dpi = SPICE_CONTAINEROF(dpi_ring_item, DrawablePipeItem, base);
                 while (worker_ring_item && (!dpi || dcc != dpi->dcc)) {
-                    dcc_add_drawable(dcc, drawable);
+                    dcc_prepend_drawable(dcc, drawable);
                     worker_ring_item = ring_next(&RED_CHANNEL(display)->clients,
                                                  worker_ring_item);
                     dcc = SPICE_CONTAINEROF(worker_ring_item, DisplayChannelClient,
@@ -423,7 +467,7 @@ static int current_add_equal(DisplayChannel *display, DrawItem *item, TreeItem *
             current_add_drawable(display, drawable, &other->siblings_link);
             red_pipes_remove_drawable(other_drawable);
             current_remove_drawable(display, other_drawable);
-            red_pipes_add_drawable(display, drawable);
+            pipes_add_drawable(display, drawable);
             return TRUE;
         }
         break;
@@ -788,25 +832,26 @@ void display_channel_print_stats(DisplayChannel *display)
 #endif
 }
 
-int display_channel_add_drawable(DisplayChannel *display, Drawable *drawable)
+void display_channel_add_drawable(DisplayChannel *display, Drawable *drawable)
 {
-    int ret = FALSE, surface_id = drawable->surface_id;
+    int success = FALSE, surface_id = drawable->surface_id;
     RedDrawable *red_drawable = drawable->red_drawable;
     Ring *ring = &display->surfaces[surface_id].current;
 
     if (has_shadow(red_drawable)) {
-        ret = current_add_with_shadow(display, ring, drawable);
+        success = current_add_with_shadow(display, ring, drawable);
     } else {
         drawable->streamable = drawable_can_stream(display, drawable);
-        ret = current_add(display, ring, drawable);
+        success = current_add(display, ring, drawable);
     }
 
+    if (success)
+        pipes_add_drawable(display, drawable);
+
 #ifdef RED_WORKER_STAT
     if ((++display->add_count % 100) == 0)
         display_channel_print_stats(display);
 #endif
-
-    return ret;
 }
 
 int display_channel_wait_for_migrate_data(DisplayChannel *display)
diff --git a/server/display-channel.h b/server/display-channel.h
index 29c1151..e26a1d8 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -109,19 +109,6 @@ enum {
     PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
 };
 
-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 */
-    Drawable *drawable;
-    DisplayChannelClient *dcc;
-    uint8_t refs;
-} DrawablePipeItem;
-
-DrawablePipeItem*          drawable_pipe_item_new                    (DisplayChannelClient *dcc,
-                                                                      Drawable *drawable);
-void                       drawable_pipe_item_unref                  (DrawablePipeItem *dpi);
-DrawablePipeItem*          drawable_pipe_item_ref                    (DrawablePipeItem *dpi);
-
 typedef struct MonitorsConfig {
     int refs;
     int count;
@@ -271,7 +258,7 @@ void                       display_channel_surface_unref             (DisplayCha
                                                                       uint32_t surface_id);
 bool                       display_channel_surface_has_canvas        (DisplayChannel *display,
                                                                       uint32_t surface_id);
-int                        display_channel_add_drawable              (DisplayChannel *display,
+void                       display_channel_add_drawable              (DisplayChannel *display,
                                                                       Drawable *drawable);
 void                       display_channel_current_flush             (DisplayChannel *display,
                                                                       int surface_id);
@@ -395,12 +382,8 @@ static inline void region_add_clip_rects(QRegion *rgn, SpiceClipRects *data)
     }
 }
 
-void red_pipes_add_drawable(DisplayChannel *display, Drawable *drawable);
 void current_remove_drawable(DisplayChannel *display, Drawable *item);
-void red_pipes_add_drawable_after(DisplayChannel *display,
-                                  Drawable *drawable, Drawable *pos_after);
 void red_pipes_remove_drawable(Drawable *drawable);
-void dcc_add_drawable(DisplayChannelClient *dcc, Drawable *drawable);
 void current_remove(DisplayChannel *display, TreeItem *item);
 void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable);
 void drawable_draw(DisplayChannel *display, Drawable *item);
diff --git a/server/red_worker.c b/server/red_worker.c
index e655876..443e00a 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -203,44 +203,6 @@ void attach_stream(DisplayChannel *display, Drawable *drawable, Stream *stream)
     }
 }
 
-/* fixme: move to display channel */
-DrawablePipeItem *drawable_pipe_item_new(DisplayChannelClient *dcc,
-                                         Drawable *drawable)
-{
-    DrawablePipeItem *dpi;
-
-    dpi = spice_malloc0(sizeof(*dpi));
-    dpi->drawable = drawable;
-    dpi->dcc = dcc;
-    ring_item_init(&dpi->base);
-    ring_add(&drawable->pipes, &dpi->base);
-    red_channel_pipe_item_init(RED_CHANNEL_CLIENT(dcc)->channel,
-                               &dpi->dpi_pipe_item, PIPE_ITEM_TYPE_DRAW);
-    dpi->refs++;
-    drawable->refs++;
-    return dpi;
-}
-
-DrawablePipeItem *drawable_pipe_item_ref(DrawablePipeItem *dpi)
-{
-    dpi->refs++;
-    return dpi;
-}
-
-void drawable_pipe_item_unref(DrawablePipeItem *dpi)
-{
-    DisplayChannel *display = DCC_TO_DC(dpi->dcc);
-
-    if (--dpi->refs != 0) {
-        return;
-    }
-
-    spice_warn_if_fail(!ring_item_is_linked(&dpi->dpi_pipe_item.link));
-    spice_warn_if_fail(!ring_item_is_linked(&dpi->base));
-    display_channel_drawable_unref(display, dpi->drawable);
-    free(dpi);
-}
-
 QXLInstance* red_worker_get_qxl(RedWorker *worker)
 {
     spice_return_val_if_fail(worker != NULL, NULL);
@@ -292,35 +254,6 @@ static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
     return 1;
 }
 
-static inline void red_handle_drawable_surfaces_client_synced(
-                        DisplayChannelClient *dcc, Drawable *drawable)
-{
-    DisplayChannel *display = DCC_TO_DC(dcc);
-    int x;
-
-    for (x = 0; x < 3; ++x) {
-        int surface_id;
-
-        surface_id = drawable->surface_deps[x];
-        if (surface_id != -1) {
-            if (dcc->surface_client_created[surface_id] == TRUE) {
-                continue;
-            }
-            dcc_create_surface(dcc, surface_id);
-            display_channel_current_flush(display, surface_id);
-            dcc_push_surface_image(dcc, surface_id);
-        }
-    }
-
-    if (dcc->surface_client_created[drawable->surface_id] == TRUE) {
-        return;
-    }
-
-    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)
 {
     return (worker->display_channel && red_channel_is_connected(
@@ -333,76 +266,6 @@ static int cursor_is_connected(RedWorker *worker)
         red_channel_is_connected(RED_CHANNEL(worker->cursor_channel));
 }
 
-void dcc_add_drawable(DisplayChannelClient *dcc, Drawable *drawable)
-{
-    DrawablePipeItem *dpi;
-
-    red_handle_drawable_surfaces_client_synced(dcc, drawable);
-    dpi = drawable_pipe_item_new(dcc, drawable);
-    red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item);
-}
-
-void red_pipes_add_drawable(DisplayChannel *display, Drawable *drawable)
-{
-    DisplayChannelClient *dcc;
-    RingItem *dcc_ring_item, *next;
-
-    spice_warn_if(!ring_is_empty(&drawable->pipes));
-    FOREACH_DCC(display, dcc_ring_item, next, dcc) {
-        dcc_add_drawable(dcc, drawable);
-    }
-}
-
-static void dcc_add_drawable_to_tail(DisplayChannelClient *dcc, Drawable *drawable)
-{
-    DrawablePipeItem *dpi;
-
-    if (!dcc) {
-        return;
-    }
-    red_handle_drawable_surfaces_client_synced(dcc, drawable);
-    dpi = drawable_pipe_item_new(dcc, drawable);
-    red_channel_client_pipe_add_tail(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item);
-}
-
-void red_pipes_add_drawable_after(DisplayChannel *display,
-                                  Drawable *drawable, Drawable *pos_after)
-{
-    DrawablePipeItem *dpi, *dpi_pos_after;
-    RingItem *dpi_link, *dpi_next;
-    DisplayChannelClient *dcc;
-    int num_other_linked = 0;
-
-    DRAWABLE_FOREACH_DPI_SAFE(pos_after, dpi_link, dpi_next, dpi_pos_after) {
-        num_other_linked++;
-        dcc = dpi_pos_after->dcc;
-        red_handle_drawable_surfaces_client_synced(dcc, drawable);
-        dpi = drawable_pipe_item_new(dcc, drawable);
-        red_channel_client_pipe_add_after(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item,
-                                          &dpi_pos_after->dpi_pipe_item);
-    }
-    if (num_other_linked == 0) {
-        red_pipes_add_drawable(display, drawable);
-        return;
-    }
-    if (num_other_linked != display->common.base.clients_num) {
-        RingItem *item, *next;
-        spice_debug("TODO: not O(n^2)");
-        FOREACH_DCC(display, item, next, dcc) {
-            int sent = 0;
-            DRAWABLE_FOREACH_DPI_SAFE(pos_after, dpi_link, dpi_next, dpi_pos_after) {
-                if (dpi_pos_after->dcc == dcc) {
-                    sent = 1;
-                    break;
-                }
-            }
-            if (!sent) {
-                dcc_add_drawable(dcc, drawable);
-            }
-        }
-    }
-}
-
 static PipeItem *dcc_get_tail(DisplayChannelClient *dcc)
 {
     return (PipeItem*)ring_get_tail(&RED_CHANNEL_CLIENT(dcc)->pipe);
@@ -1179,9 +1042,8 @@ static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable
         goto cleanup;
     }
 
-    if (display_channel_add_drawable(worker->display_channel, drawable)) {
-        red_pipes_add_drawable(worker->display_channel, drawable);
-    }
+    display_channel_add_drawable(worker->display_channel, drawable);
+
 cleanup:
     display_channel_drawable_unref(display, drawable);
 }
@@ -2338,7 +2200,7 @@ static void red_add_lossless_drawable_dependencies(RedChannelClient *rcc,
 
     if (!sync_rendered) {
         // pushing the pipe item back to the pipe
-        dcc_add_drawable_to_tail(dcc, item);
+        dcc_append_drawable(dcc, item);
         // 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++) {
commit 1549f751b8b9cdaf17b721a8400b6cffce7e36ed
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Thu Sep 26 14:01:41 2013 +0200

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

diff --git a/server/dcc-encoders.c b/server/dcc-encoders.c
index 24064a8..1eaa604 100644
--- a/server/dcc-encoders.c
+++ b/server/dcc-encoders.c
@@ -584,8 +584,133 @@ void dcc_free_glz_drawables(DisplayChannelClient *dcc)
 void dcc_freeze_glz(DisplayChannelClient *dcc)
 {
     pthread_rwlock_wrlock(&dcc->glz_dict->encode_lock);
-    if (!dcc->glz_dict->migrate_freeze) {
-        dcc->glz_dict->migrate_freeze = TRUE;
-    }
+    dcc->glz_dict->migrate_freeze = TRUE;
     pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
 }
+
+static GlzSharedDictionary *glz_shared_dictionary_new(RedClient *client, uint8_t id,
+                                                      GlzEncDictContext *dict)
+{
+    spice_return_val_if_fail(dict != NULL, NULL);
+
+    GlzSharedDictionary *shared_dict = spice_new0(GlzSharedDictionary, 1);
+
+    shared_dict->dict = dict;
+    shared_dict->id = id;
+    shared_dict->refs = 1;
+    shared_dict->migrate_freeze = FALSE;
+    shared_dict->client = client;
+    ring_item_init(&shared_dict->base);
+    pthread_rwlock_init(&shared_dict->encode_lock, NULL);
+
+    return shared_dict;
+}
+
+static pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER;
+static Ring glz_dictionary_list = {&glz_dictionary_list, &glz_dictionary_list};
+
+static GlzSharedDictionary *find_glz_dictionary(RedClient *client, uint8_t dict_id)
+{
+    RingItem *now;
+    GlzSharedDictionary *ret = NULL;
+
+    now = &glz_dictionary_list;
+    while ((now = ring_next(&glz_dictionary_list, now))) {
+        GlzSharedDictionary *dict = (GlzSharedDictionary *)now;
+        if ((dict->client == client) && (dict->id == dict_id)) {
+            ret = dict;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+#define MAX_LZ_ENCODERS MAX_CACHE_CLIENTS
+
+static GlzSharedDictionary *create_glz_dictionary(DisplayChannelClient *dcc,
+                                                  uint8_t id, int window_size)
+{
+    spice_info("Lz Window %d Size=%d", id, window_size);
+
+    GlzEncDictContext *glz_dict =
+        glz_enc_dictionary_create(window_size, MAX_LZ_ENCODERS, &dcc->glz_data.usr);
+
+    return glz_shared_dictionary_new(RED_CHANNEL_CLIENT(dcc)->client, id, glz_dict);
+}
+
+GlzSharedDictionary *dcc_get_glz_dictionary(DisplayChannelClient *dcc,
+                                            uint8_t id, int window_size)
+{
+    GlzSharedDictionary *shared_dict;
+
+    pthread_mutex_lock(&glz_dictionary_list_lock);
+
+    shared_dict = find_glz_dictionary(RED_CHANNEL_CLIENT(dcc)->client, id);
+    if (shared_dict) {
+        shared_dict->refs++;
+    } else {
+        shared_dict = create_glz_dictionary(dcc, id, window_size);
+        ring_add(&glz_dictionary_list, &shared_dict->base);
+    }
+
+    pthread_mutex_unlock(&glz_dictionary_list_lock);
+    return shared_dict;
+}
+
+static GlzSharedDictionary *restore_glz_dictionary(DisplayChannelClient *dcc,
+                                                   uint8_t id,
+                                                   GlzEncDictRestoreData *restore_data)
+{
+    GlzEncDictContext *glz_dict =
+        glz_enc_dictionary_restore(restore_data, &dcc->glz_data.usr);
+
+    return glz_shared_dictionary_new(RED_CHANNEL_CLIENT(dcc)->client, id, glz_dict);
+}
+
+GlzSharedDictionary *dcc_restore_glz_dictionary(DisplayChannelClient *dcc,
+                                                uint8_t id,
+                                                GlzEncDictRestoreData *restore_data)
+{
+    GlzSharedDictionary *shared_dict = NULL;
+
+    pthread_mutex_lock(&glz_dictionary_list_lock);
+
+    shared_dict = find_glz_dictionary(RED_CHANNEL_CLIENT(dcc)->client, id);
+
+    if (shared_dict) {
+        shared_dict->refs++;
+    } else {
+        shared_dict = restore_glz_dictionary(dcc, id, restore_data);
+        ring_add(&glz_dictionary_list, &shared_dict->base);
+    }
+
+    pthread_mutex_unlock(&glz_dictionary_list_lock);
+    return shared_dict;
+}
+
+/* destroy encoder, and dictionary if no one uses it*/
+void dcc_release_glz(DisplayChannelClient *dcc)
+{
+    GlzSharedDictionary *shared_dict;
+
+    dcc_free_glz_drawables(dcc);
+
+    glz_encoder_destroy(dcc->glz);
+    dcc->glz = NULL;
+
+    if (!(shared_dict = dcc->glz_dict)) {
+        return;
+    }
+
+    dcc->glz_dict = NULL;
+    pthread_mutex_lock(&glz_dictionary_list_lock);
+    if (--shared_dict->refs != 0) {
+        pthread_mutex_unlock(&glz_dictionary_list_lock);
+        return;
+    }
+    ring_remove(&shared_dict->base);
+    pthread_mutex_unlock(&glz_dictionary_list_lock);
+    glz_enc_dictionary_destroy(shared_dict->dict, &dcc->glz_data.usr);
+    free(shared_dict);
+}
diff --git a/server/dcc-encoders.h b/server/dcc-encoders.h
index 05fd29e..5de66f7 100644
--- a/server/dcc-encoders.h
+++ b/server/dcc-encoders.h
@@ -46,6 +46,7 @@ int              dcc_free_some_independent_glz_drawables     (DisplayChannelClie
 void             dcc_free_glz_drawables                      (DisplayChannelClient *dcc);
 void             dcc_free_glz_drawables_to_free              (DisplayChannelClient* dcc);
 void             dcc_freeze_glz                              (DisplayChannelClient *dcc);
+void             dcc_release_glz                             (DisplayChannelClient *dcc);
 
 void             marshaller_add_compressed                   (SpiceMarshaller *m,
                                                               RedCompressBuf *comp_buf,
@@ -77,6 +78,12 @@ typedef struct GlzSharedDictionary {
     RedClient *client; // channel clients of the same client share the dict
 } GlzSharedDictionary;
 
+GlzSharedDictionary* dcc_get_glz_dictionary                  (DisplayChannelClient *dcc,
+                                                              uint8_t id, int window_size);
+GlzSharedDictionary* dcc_restore_glz_dictionary              (DisplayChannelClient *dcc,
+                                                              uint8_t id,
+                                                              GlzEncDictRestoreData *restore_data);
+
 typedef struct  {
     DisplayChannelClient *dcc;
     RedCompressBuf *bufs_head;
diff --git a/server/dcc.c b/server/dcc.c
index 6115569..ec0295a 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -1091,3 +1091,84 @@ int dcc_pixmap_cache_unlocked_add(DisplayChannelClient *dcc, uint64_t id,
     cache->sync[dcc->common.id] = serial;
     return TRUE;
 }
+
+static int dcc_handle_init(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init)
+{
+    spice_return_val_if_fail(dcc->expect_init, FALSE);
+    dcc->expect_init = FALSE;
+
+    spice_return_val_if_fail(!dcc->pixmap_cache, FALSE);
+    dcc->pixmap_cache = pixmap_cache_get(RED_CHANNEL_CLIENT(dcc)->client,
+                                         init->pixmap_cache_id,
+                                         init->pixmap_cache_size);
+    spice_return_val_if_fail(dcc->pixmap_cache, FALSE);
+
+    spice_return_val_if_fail(!dcc->glz_dict, FALSE);
+    ring_init(&dcc->glz_drawables);
+    ring_init(&dcc->glz_drawables_inst_to_free);
+    pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
+    dcc->glz_dict = dcc_get_glz_dictionary(dcc,
+                                           init->glz_dictionary_id,
+                                           init->glz_dictionary_window_size);
+    spice_return_val_if_fail(dcc->glz_dict, FALSE);
+
+    return TRUE;
+}
+
+static int dcc_handle_stream_report(DisplayChannelClient *dcc,
+                                    SpiceMsgcDisplayStreamReport *report)
+{
+    StreamAgent *agent;
+
+    spice_return_val_if_fail(report->stream_id < NUM_STREAMS, FALSE);
+    agent = &dcc->stream_agents[report->stream_id];
+    spice_return_val_if_fail(agent->mjpeg_encoder, TRUE);
+    spice_return_val_if_fail(report->unique_id == agent->report_id, TRUE);
+
+    mjpeg_encoder_client_stream_report(agent->mjpeg_encoder,
+                                       report->num_frames,
+                                       report->num_drops,
+                                       report->start_frame_mm_time,
+                                       report->end_frame_mm_time,
+                                       report->last_frame_delay,
+                                       report->audio_delay);
+    return TRUE;
+}
+
+static int dcc_handle_preferred_compression(DisplayChannelClient *dcc,
+        SpiceMsgcDisplayPreferredCompression *pc)
+{
+    switch (pc->image_compression) {
+    case SPICE_IMAGE_COMPRESSION_AUTO_LZ:
+    case SPICE_IMAGE_COMPRESSION_AUTO_GLZ:
+    case SPICE_IMAGE_COMPRESSION_QUIC:
+#ifdef USE_LZ4
+    case SPICE_IMAGE_COMPRESSION_LZ4:
+#endif
+    case SPICE_IMAGE_COMPRESSION_LZ:
+    case SPICE_IMAGE_COMPRESSION_GLZ:
+    case SPICE_IMAGE_COMPRESSION_OFF:
+        dcc->image_compression = pc->image_compression;
+        return TRUE;
+    default:
+        spice_warning("preferred-compression: unsupported image compression setting");
+        return FALSE;
+    }
+}
+
+int dcc_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void *msg)
+{
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+
+    switch (type) {
+    case SPICE_MSGC_DISPLAY_INIT:
+        return dcc_handle_init(dcc, (SpiceMsgcDisplayInit *)msg);
+    case SPICE_MSGC_DISPLAY_STREAM_REPORT:
+        return dcc_handle_stream_report(dcc, (SpiceMsgcDisplayStreamReport *)msg);
+    case SPICE_MSGC_DISPLAY_PREFERRED_COMPRESSION:
+        return dcc_handle_preferred_compression(dcc,
+            (SpiceMsgcDisplayPreferredCompression *)msg);
+    default:
+        return red_channel_client_handle_message(rcc, size, type, msg);
+    }
+}
diff --git a/server/dcc.h b/server/dcc.h
index c62c3c9..a6e1cc7 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -147,6 +147,9 @@ DisplayChannelClient*      dcc_new                                   (DisplayCha
                                                                       spice_wan_compression_t jpeg_state,
                                                                       spice_wan_compression_t zlib_glz_state);
 void                       dcc_start                                 (DisplayChannelClient *dcc);
+int                        dcc_handle_message                        (RedChannelClient *rcc,
+                                                                      uint32_t size,
+                                                                      uint16_t type, void *msg);
 void                       dcc_push_monitors_config                  (DisplayChannelClient *dcc);
 void                       dcc_destroy_surface                       (DisplayChannelClient *dcc,
                                                                       uint32_t surface_id);
diff --git a/server/red_worker.c b/server/red_worker.c
index 188cb16..e655876 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -83,16 +83,11 @@ struct SpiceWatch {
     void *watch_func_opaque;
 };
 
-#define MAX_LZ_ENCODERS MAX_CACHE_CLIENTS
-
 #define MAX_PIPE_SIZE 50
 
 #define WIDE_CLIENT_ACK_WINDOW 40
 #define NARROW_CLIENT_ACK_WINDOW 20
 
-pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER;
-Ring glz_dictionary_list = {&glz_dictionary_list, &glz_dictionary_list};
-
 typedef struct UpgradeItem {
     PipeItem base;
     int refs;
@@ -156,7 +151,6 @@ static void display_channel_draw(DisplayChannel *display, const SpiceRect *area,
 static void display_channel_draw_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
                                       Drawable *last);
 static inline void display_begin_send_message(RedChannelClient *rcc);
-static void dcc_release_glz(DisplayChannelClient *dcc);
 static void display_channel_client_release_item_before_push(DisplayChannelClient *dcc,
                                                             PipeItem *item);
 static void display_channel_client_release_item_after_push(DisplayChannelClient *dcc,
@@ -4454,167 +4448,18 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
     flush_cursor_commands(worker);
 }
 
-static GlzSharedDictionary *_red_find_glz_dictionary(RedClient *client, uint8_t dict_id)
-{
-    RingItem *now;
-    GlzSharedDictionary *ret = NULL;
-
-    now = &glz_dictionary_list;
-    while ((now = ring_next(&glz_dictionary_list, now))) {
-        GlzSharedDictionary *dict = (GlzSharedDictionary *)now;
-        if ((dict->client == client) && (dict->id == dict_id)) {
-            ret = dict;
-            break;
-        }
-    }
-
-    return ret;
-}
-
-static GlzSharedDictionary *_red_create_glz_dictionary(RedClient *client, uint8_t id,
-                                                       GlzEncDictContext *opaque_dict)
-{
-    GlzSharedDictionary *shared_dict = spice_new0(GlzSharedDictionary, 1);
-    shared_dict->dict = opaque_dict;
-    shared_dict->id = id;
-    shared_dict->refs = 1;
-    shared_dict->migrate_freeze = FALSE;
-    shared_dict->client = client;
-    ring_item_init(&shared_dict->base);
-    pthread_rwlock_init(&shared_dict->encode_lock, NULL);
-    return shared_dict;
-}
-
-static GlzSharedDictionary *red_create_glz_dictionary(DisplayChannelClient *dcc,
-                                                      uint8_t id, int window_size)
-{
-    GlzEncDictContext *glz_dict = glz_enc_dictionary_create(window_size,
-                                                            MAX_LZ_ENCODERS,
-                                                            &dcc->glz_data.usr);
-#ifdef COMPRESS_DEBUG
-    spice_info("Lz Window %d Size=%d", id, window_size);
-#endif
-    if (!glz_dict) {
-        spice_critical("failed creating lz dictionary");
-        return NULL;
-    }
-    return _red_create_glz_dictionary(RED_CHANNEL_CLIENT(dcc)->client, id, glz_dict);
-}
-
-static GlzSharedDictionary *red_create_restored_glz_dictionary(DisplayChannelClient *dcc,
-                                                               uint8_t id,
-                                                               GlzEncDictRestoreData *restore_data)
-{
-    GlzEncDictContext *glz_dict = glz_enc_dictionary_restore(restore_data,
-                                                             &dcc->glz_data.usr);
-    if (!glz_dict) {
-        spice_critical("failed creating lz dictionary");
-        return NULL;
-    }
-    return _red_create_glz_dictionary(RED_CHANNEL_CLIENT(dcc)->client, id, glz_dict);
-}
-
-static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannelClient *dcc,
-                                                   uint8_t id, int window_size)
-{
-    GlzSharedDictionary *shared_dict = NULL;
-
-    pthread_mutex_lock(&glz_dictionary_list_lock);
-
-    shared_dict = _red_find_glz_dictionary(RED_CHANNEL_CLIENT(dcc)->client, id);
-
-    if (!shared_dict) {
-        shared_dict = red_create_glz_dictionary(dcc, id, window_size);
-        ring_add(&glz_dictionary_list, &shared_dict->base);
-    } else {
-        shared_dict->refs++;
-    }
-    pthread_mutex_unlock(&glz_dictionary_list_lock);
-    return shared_dict;
-}
-
-static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannelClient *dcc,
-                                                       uint8_t id,
-                                                       GlzEncDictRestoreData *restore_data)
-{
-    GlzSharedDictionary *shared_dict = NULL;
-
-    pthread_mutex_lock(&glz_dictionary_list_lock);
-
-    shared_dict = _red_find_glz_dictionary(RED_CHANNEL_CLIENT(dcc)->client, id);
-
-    if (!shared_dict) {
-        shared_dict = red_create_restored_glz_dictionary(dcc, id, restore_data);
-        ring_add(&glz_dictionary_list, &shared_dict->base);
-    } else {
-        shared_dict->refs++;
-    }
-    pthread_mutex_unlock(&glz_dictionary_list_lock);
-    return shared_dict;
-}
-
-/* destroy encoder, and dictionary if no one uses it*/
-static void dcc_release_glz(DisplayChannelClient *dcc)
-{
-    GlzSharedDictionary *shared_dict;
-
-    dcc_free_glz_drawables(dcc);
-
-    glz_encoder_destroy(dcc->glz);
-    dcc->glz = NULL;
-
-    if (!(shared_dict = dcc->glz_dict)) {
-        return;
-    }
-
-    dcc->glz_dict = NULL;
-    pthread_mutex_lock(&glz_dictionary_list_lock);
-    if (--shared_dict->refs) {
-        pthread_mutex_unlock(&glz_dictionary_list_lock);
-        return;
-    }
-    ring_remove(&shared_dict->base);
-    pthread_mutex_unlock(&glz_dictionary_list_lock);
-    glz_enc_dictionary_destroy(shared_dict->dict, &dcc->glz_data.usr);
-    free(shared_dict);
-}
-
-static int display_channel_init_cache(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init_info)
+static int dcc_handle_migrate_glz_dictionary(DisplayChannelClient *dcc,
+                                             SpiceMigrateDataDisplay *migrate)
 {
-    spice_assert(!dcc->pixmap_cache);
-    return !!(dcc->pixmap_cache = pixmap_cache_get(RED_CHANNEL_CLIENT(dcc)->client,
-                                                   init_info->pixmap_cache_id,
-                                                   init_info->pixmap_cache_size));
-}
+    spice_return_val_if_fail(!dcc->glz_dict, FALSE);
 
-static int display_channel_init_glz_dictionary(DisplayChannelClient *dcc,
-                                               SpiceMsgcDisplayInit *init_info)
-{
-    spice_assert(!dcc->glz_dict);
     ring_init(&dcc->glz_drawables);
     ring_init(&dcc->glz_drawables_inst_to_free);
     pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
-    return !!(dcc->glz_dict = red_get_glz_dictionary(dcc,
-                                                     init_info->glz_dictionary_id,
-                                                     init_info->glz_dictionary_window_size));
-}
-
-static int display_channel_init(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init_info)
-{
-    return (display_channel_init_cache(dcc, init_info) &&
-            display_channel_init_glz_dictionary(dcc, init_info));
-}
-
-static int display_channel_handle_migrate_glz_dictionary(DisplayChannelClient *dcc,
-                                                         SpiceMigrateDataDisplay *migrate_info)
-{
-    spice_assert(!dcc->glz_dict);
-    ring_init(&dcc->glz_drawables);
-    ring_init(&dcc->glz_drawables_inst_to_free);
-    pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
-    return !!(dcc->glz_dict = red_restore_glz_dictionary(dcc,
-                                                         migrate_info->glz_dict_id,
-                                                         &migrate_info->glz_dict_data));
+    dcc->glz_dict = dcc_restore_glz_dictionary(dcc,
+                                               migrate->glz_dict_id,
+                                               &migrate->glz_dict_data);
+    return dcc->glz_dict != NULL;
 }
 
 static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
@@ -4738,7 +4583,7 @@ static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t s
                                          PIPE_ITEM_TYPE_PIXMAP_RESET);
     }
 
-    if (display_channel_handle_migrate_glz_dictionary(dcc, migrate_data)) {
+    if (dcc_handle_migrate_glz_dictionary(dcc, migrate_data)) {
         dcc->glz = glz_encoder_create(dcc->common.id,
                                       dcc->glz_dict->dict, &dcc->glz_data.usr);
         if (!dcc->glz) {
@@ -4778,83 +4623,6 @@ static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t s
     return TRUE;
 }
 
-static int display_channel_handle_stream_report(DisplayChannelClient *dcc,
-                                                SpiceMsgcDisplayStreamReport *stream_report)
-{
-    StreamAgent *stream_agent;
-
-    if (stream_report->stream_id >= NUM_STREAMS) {
-        spice_warning("stream_report: invalid stream id %u", stream_report->stream_id);
-        return FALSE;
-    }
-    stream_agent = &dcc->stream_agents[stream_report->stream_id];
-    if (!stream_agent->mjpeg_encoder) {
-        spice_info("stream_report: no encoder for stream id %u."
-                    "Probably the stream has been destroyed", stream_report->stream_id);
-        return TRUE;
-    }
-
-    if (stream_report->unique_id != stream_agent->report_id) {
-        spice_warning("local reoprt-id (%u) != msg report-id (%u)",
-                      stream_agent->report_id, stream_report->unique_id);
-        return TRUE;
-    }
-    mjpeg_encoder_client_stream_report(stream_agent->mjpeg_encoder,
-                                       stream_report->num_frames,
-                                       stream_report->num_drops,
-                                       stream_report->start_frame_mm_time,
-                                       stream_report->end_frame_mm_time,
-                                       stream_report->last_frame_delay,
-                                       stream_report->audio_delay);
-    return TRUE;
-}
-
-static int display_channel_handle_preferred_compression(DisplayChannelClient *dcc,
-        SpiceMsgcDisplayPreferredCompression *pc)
-{
-    switch (pc->image_compression) {
-    case SPICE_IMAGE_COMPRESSION_AUTO_LZ:
-    case SPICE_IMAGE_COMPRESSION_AUTO_GLZ:
-    case SPICE_IMAGE_COMPRESSION_QUIC:
-#ifdef USE_LZ4
-    case SPICE_IMAGE_COMPRESSION_LZ4:
-#endif
-    case SPICE_IMAGE_COMPRESSION_LZ:
-    case SPICE_IMAGE_COMPRESSION_GLZ:
-    case SPICE_IMAGE_COMPRESSION_OFF:
-        dcc->image_compression = pc->image_compression;
-        return TRUE;
-    default:
-        spice_warning("preferred-compression: unsupported image compression setting");
-        return FALSE;
-    }
-}
-
-static int display_channel_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type,
-                                          void *message)
-{
-    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
-
-    switch (type) {
-    case SPICE_MSGC_DISPLAY_INIT:
-        if (!dcc->expect_init) {
-            spice_warning("unexpected SPICE_MSGC_DISPLAY_INIT");
-            return FALSE;
-        }
-        dcc->expect_init = FALSE;
-        return display_channel_init(dcc, (SpiceMsgcDisplayInit *)message);
-    case SPICE_MSGC_DISPLAY_STREAM_REPORT:
-        return display_channel_handle_stream_report(dcc,
-                                                    (SpiceMsgcDisplayStreamReport *)message);
-    case SPICE_MSGC_DISPLAY_PREFERRED_COMPRESSION:
-        return display_channel_handle_preferred_compression(dcc,
-            (SpiceMsgcDisplayPreferredCompression *)message);
-
-    default:
-        return red_channel_client_handle_message(rcc, size, type, message);
-    }
-}
-
 static int common_channel_config_socket(RedChannelClient *rcc)
 {
     RedClient *client = red_channel_client_get_client(rcc);
@@ -5191,7 +4959,7 @@ static void display_channel_create(RedWorker *worker, int migrate, int stream_vi
             worker, sizeof(*display_channel), "display_channel",
             SPICE_CHANNEL_DISPLAY,
             SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
-            &cbs, display_channel_handle_message))) {
+            &cbs, dcc_handle_message))) {
         spice_warning("failed to create display channel");
         return;
     }
commit 1b6881c83b8838b9cd0e81ac40a02e67552e8dbe
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Thu Sep 26 14:01:41 2013 +0200

    worker: do not set worker image compression on client request
    
    Display client can ask to change the preferred compression.
    Previously this setting change the entire worker setting
    so every future client created would have this setting.
    Remove the setting in the worker make the change only to the
    current client.
    
    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/red_worker.c b/server/red_worker.c
index d3a675b..188cb16 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4810,8 +4810,8 @@ static int display_channel_handle_stream_report(DisplayChannelClient *dcc,
 }
 
 static int display_channel_handle_preferred_compression(DisplayChannelClient *dcc,
-        SpiceMsgcDisplayPreferredCompression *pc) {
-    DisplayChannel *display_channel = DCC_TO_DC(dcc);
+        SpiceMsgcDisplayPreferredCompression *pc)
+{
     switch (pc->image_compression) {
     case SPICE_IMAGE_COMPRESSION_AUTO_LZ:
     case SPICE_IMAGE_COMPRESSION_AUTO_GLZ:
@@ -4822,7 +4822,6 @@ static int display_channel_handle_preferred_compression(DisplayChannelClient *dc
     case SPICE_IMAGE_COMPRESSION_LZ:
     case SPICE_IMAGE_COMPRESSION_GLZ:
     case SPICE_IMAGE_COMPRESSION_OFF:
-        display_channel->common.worker->image_compression = pc->image_compression;
         dcc->image_compression = pc->image_compression;
         return TRUE;
     default:


More information about the Spice-commits mailing list