[Spice-commits] 10 commits - server/Makefile.am server/red_channel.c server/red_channel.h server/red_dispatcher.c server/red_time.c server/red_time.h server/red_worker.c server/red_worker.h server/spice_bitmap_utils.c server/spice_bitmap_utils.h server/spice_image_cache.c server/spice_image_cache.h server/spice_server_utils.h

Alon Levy alon at kemper.freedesktop.org
Wed Aug 14 03:24:55 PDT 2013


 server/Makefile.am          |    5 
 server/red_channel.c        |  106 +++++++++
 server/red_channel.h        |   10 
 server/red_dispatcher.c     |    4 
 server/red_time.c           |    1 
 server/red_time.h           |   15 +
 server/red_worker.c         |  511 +++-----------------------------------------
 server/red_worker.h         |   18 -
 server/spice_bitmap_utils.c |  167 ++++++++++++++
 server/spice_bitmap_utils.h |    8 
 server/spice_image_cache.c  |  135 +++++++++++
 server/spice_image_cache.h  |   39 +++
 server/spice_server_utils.h |   23 +
 13 files changed, 548 insertions(+), 494 deletions(-)

New commits:
commit ee382109a6d59c3e6591d49f9e25a6314d0d5b5f
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 12 15:31:56 2013 +0300

    server: split spice_image_cache from red_worker

diff --git a/server/Makefile.am b/server/Makefile.am
index feee2f1..815f65e 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -100,6 +100,8 @@ libspice_server_la_SOURCES =			\
 	spice_bitmap_utils.h		\
 	spice_bitmap_utils.c		\
 	spice_server_utils.h		\
+	spice_image_cache.h			\
+	spice_image_cache.c			\
 	$(NULL)
 
 if SUPPORT_TUNNEL
diff --git a/server/red_worker.c b/server/red_worker.c
index df5d01c..7f1aeda 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -85,6 +85,7 @@
 #include "spice_server_utils.h"
 #include "red_time.h"
 #include "spice_bitmap_utils.h"
+#include "spice_image_cache.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -757,29 +758,6 @@ typedef struct CursorChannel {
 #endif
 } CursorChannel;
 
-typedef struct ImageCacheItem {
-    RingItem lru_link;
-    uint64_t id;
-#ifdef IMAGE_CACHE_AGE
-    uint32_t age;
-#endif
-    struct ImageCacheItem *next;
-    pixman_image_t *image;
-} ImageCacheItem;
-
-#define IMAGE_CACHE_HASH_SIZE 1024
-
-typedef struct ImageCache {
-    SpiceImageCache base;
-    ImageCacheItem *hash_table[IMAGE_CACHE_HASH_SIZE];
-    Ring lru;
-#ifdef IMAGE_CACHE_AGE
-    uint32_t age;
-#else
-    uint32_t num_items;
-#endif
-} ImageCache;
-
 enum {
     TREE_ITEM_TYPE_DRAWABLE,
     TREE_ITEM_TYPE_CONTAINER,
@@ -4300,140 +4278,6 @@ static void image_surface_init(RedWorker *worker)
     worker->image_surfaces.ops = &image_surfaces_ops;
 }
 
-static ImageCacheItem *image_cache_find(ImageCache *cache, uint64_t id)
-{
-    ImageCacheItem *item = cache->hash_table[id % IMAGE_CACHE_HASH_SIZE];
-
-    while (item) {
-        if (item->id == id) {
-            return item;
-        }
-        item = item->next;
-    }
-    return NULL;
-}
-
-static int image_cache_hit(ImageCache *cache, uint64_t id)
-{
-    ImageCacheItem *item;
-    if (!(item = image_cache_find(cache, id))) {
-        return FALSE;
-    }
-#ifdef IMAGE_CACHE_AGE
-    item->age = cache->age;
-#endif
-    ring_remove(&item->lru_link);
-    ring_add(&cache->lru, &item->lru_link);
-    return TRUE;
-}
-
-static void image_cache_remove(ImageCache *cache, ImageCacheItem *item)
-{
-    ImageCacheItem **now;
-
-    now = &cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE];
-    for (;;) {
-        spice_assert(*now);
-        if (*now == item) {
-            *now = item->next;
-            break;
-        }
-        now = &(*now)->next;
-    }
-    ring_remove(&item->lru_link);
-    pixman_image_unref(item->image);
-    free(item);
-#ifndef IMAGE_CACHE_AGE
-    cache->num_items--;
-#endif
-}
-
-#define IMAGE_CACHE_MAX_ITEMS 2
-
-static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, pixman_image_t *image)
-{
-    ImageCache *cache = (ImageCache *)spice_cache;
-    ImageCacheItem *item;
-
-#ifndef IMAGE_CACHE_AGE
-    if (cache->num_items == IMAGE_CACHE_MAX_ITEMS) {
-        ImageCacheItem *tail = (ImageCacheItem *)ring_get_tail(&cache->lru);
-        spice_assert(tail);
-        image_cache_remove(cache, tail);
-    }
-#endif
-
-    item = spice_new(ImageCacheItem, 1);
-    item->id = id;
-#ifdef IMAGE_CACHE_AGE
-    item->age = cache->age;
-#else
-    cache->num_items++;
-#endif
-    item->image = pixman_image_ref(image);
-    ring_item_init(&item->lru_link);
-
-    item->next = cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE];
-    cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE] = item;
-
-    ring_add(&cache->lru, &item->lru_link);
-}
-
-static pixman_image_t *image_cache_get(SpiceImageCache *spice_cache, uint64_t id)
-{
-    ImageCache *cache = (ImageCache *)spice_cache;
-
-    ImageCacheItem *item = image_cache_find(cache, id);
-    if (!item) {
-        spice_error("not found");
-    }
-    return pixman_image_ref(item->image);
-}
-
-static void image_cache_init(ImageCache *cache)
-{
-    static SpiceImageCacheOps image_cache_ops = {
-        image_cache_put,
-        image_cache_get,
-    };
-
-    cache->base.ops = &image_cache_ops;
-    memset(cache->hash_table, 0, sizeof(cache->hash_table));
-    ring_init(&cache->lru);
-#ifdef IMAGE_CACHE_AGE
-    cache->age = 0;
-#else
-    cache->num_items = 0;
-#endif
-}
-
-static void image_cache_reset(ImageCache *cache)
-{
-    ImageCacheItem *item;
-
-    while ((item = (ImageCacheItem *)ring_get_head(&cache->lru))) {
-        image_cache_remove(cache, item);
-    }
-#ifdef IMAGE_CACHE_AGE
-    cache->age = 0;
-#endif
-}
-
-#define IMAGE_CACHE_DEPTH 4
-
-static void image_cache_aging(ImageCache *cache)
-{
-#ifdef IMAGE_CACHE_AGE
-    ImageCacheItem *item;
-
-    cache->age++;
-    while ((item = (ImageCacheItem *)ring_get_tail(&cache->lru)) &&
-           cache->age - item->age > IMAGE_CACHE_DEPTH) {
-        image_cache_remove(cache, item);
-    }
-#endif
-}
-
 static void localize_bitmap(RedWorker *worker, SpiceImage **image_ptr, SpiceImage *image_store,
                             Drawable *drawable)
 {
diff --git a/server/spice_image_cache.c b/server/spice_image_cache.c
new file mode 100644
index 0000000..291094c
--- /dev/null
+++ b/server/spice_image_cache.c
@@ -0,0 +1,135 @@
+#include "spice_image_cache.h"
+
+static ImageCacheItem *image_cache_find(ImageCache *cache, uint64_t id)
+{
+    ImageCacheItem *item = cache->hash_table[id % IMAGE_CACHE_HASH_SIZE];
+
+    while (item) {
+        if (item->id == id) {
+            return item;
+        }
+        item = item->next;
+    }
+    return NULL;
+}
+
+int image_cache_hit(ImageCache *cache, uint64_t id)
+{
+    ImageCacheItem *item;
+    if (!(item = image_cache_find(cache, id))) {
+        return FALSE;
+    }
+#ifdef IMAGE_CACHE_AGE
+    item->age = cache->age;
+#endif
+    ring_remove(&item->lru_link);
+    ring_add(&cache->lru, &item->lru_link);
+    return TRUE;
+}
+
+static void image_cache_remove(ImageCache *cache, ImageCacheItem *item)
+{
+    ImageCacheItem **now;
+
+    now = &cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE];
+    for (;;) {
+        spice_assert(*now);
+        if (*now == item) {
+            *now = item->next;
+            break;
+        }
+        now = &(*now)->next;
+    }
+    ring_remove(&item->lru_link);
+    pixman_image_unref(item->image);
+    free(item);
+#ifndef IMAGE_CACHE_AGE
+    cache->num_items--;
+#endif
+}
+
+#define IMAGE_CACHE_MAX_ITEMS 2
+
+static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, pixman_image_t *image)
+{
+    ImageCache *cache = (ImageCache *)spice_cache;
+    ImageCacheItem *item;
+
+#ifndef IMAGE_CACHE_AGE
+    if (cache->num_items == IMAGE_CACHE_MAX_ITEMS) {
+        ImageCacheItem *tail = (ImageCacheItem *)ring_get_tail(&cache->lru);
+        spice_assert(tail);
+        image_cache_remove(cache, tail);
+    }
+#endif
+
+    item = spice_new(ImageCacheItem, 1);
+    item->id = id;
+#ifdef IMAGE_CACHE_AGE
+    item->age = cache->age;
+#else
+    cache->num_items++;
+#endif
+    item->image = pixman_image_ref(image);
+    ring_item_init(&item->lru_link);
+
+    item->next = cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE];
+    cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE] = item;
+
+    ring_add(&cache->lru, &item->lru_link);
+}
+
+static pixman_image_t *image_cache_get(SpiceImageCache *spice_cache, uint64_t id)
+{
+    ImageCache *cache = (ImageCache *)spice_cache;
+
+    ImageCacheItem *item = image_cache_find(cache, id);
+    if (!item) {
+        spice_error("not found");
+    }
+    return pixman_image_ref(item->image);
+}
+
+void image_cache_init(ImageCache *cache)
+{
+    static SpiceImageCacheOps image_cache_ops = {
+        image_cache_put,
+        image_cache_get,
+    };
+
+    cache->base.ops = &image_cache_ops;
+    memset(cache->hash_table, 0, sizeof(cache->hash_table));
+    ring_init(&cache->lru);
+#ifdef IMAGE_CACHE_AGE
+    cache->age = 0;
+#else
+    cache->num_items = 0;
+#endif
+}
+
+void image_cache_reset(ImageCache *cache)
+{
+    ImageCacheItem *item;
+
+    while ((item = (ImageCacheItem *)ring_get_head(&cache->lru))) {
+        image_cache_remove(cache, item);
+    }
+#ifdef IMAGE_CACHE_AGE
+    cache->age = 0;
+#endif
+}
+
+#define IMAGE_CACHE_DEPTH 4
+
+void image_cache_aging(ImageCache *cache)
+{
+#ifdef IMAGE_CACHE_AGE
+    ImageCacheItem *item;
+
+    cache->age++;
+    while ((item = (ImageCacheItem *)ring_get_tail(&cache->lru)) &&
+           cache->age - item->age > IMAGE_CACHE_DEPTH) {
+        image_cache_remove(cache, item);
+    }
+#endif
+}
diff --git a/server/spice_image_cache.h b/server/spice_image_cache.h
new file mode 100644
index 0000000..f11cebc
--- /dev/null
+++ b/server/spice_image_cache.h
@@ -0,0 +1,39 @@
+#ifndef H_SPICE_IMAGE_CACHE
+#define H_SPICE_IMAGE_CACHE
+
+#include <inttypes.h>
+
+#include "common/pixman_utils.h"
+#include "common/canvas_base.h"
+
+#include "common/ring.h"
+
+typedef struct ImageCacheItem {
+    RingItem lru_link;
+    uint64_t id;
+#ifdef IMAGE_CACHE_AGE
+    uint32_t age;
+#endif
+    struct ImageCacheItem *next;
+    pixman_image_t *image;
+} ImageCacheItem;
+
+#define IMAGE_CACHE_HASH_SIZE 1024
+
+typedef struct ImageCache {
+    SpiceImageCache base;
+    ImageCacheItem *hash_table[IMAGE_CACHE_HASH_SIZE];
+    Ring lru;
+#ifdef IMAGE_CACHE_AGE
+    uint32_t age;
+#else
+    uint32_t num_items;
+#endif
+} ImageCache;
+
+int image_cache_hit(ImageCache *cache, uint64_t id);
+void image_cache_init(ImageCache *cache);
+void image_cache_reset(ImageCache *cache);
+void image_cache_aging(ImageCache *cache);
+
+#endif
commit 1bbce9ba05a63e50a4762b3adad773bb656b2c64
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 12 15:22:29 2013 +0300

    server/red_worker: s/image_cache_eaging/image_cache_aging/

diff --git a/server/red_worker.c b/server/red_worker.c
index 1caaa51..df5d01c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4421,7 +4421,7 @@ static void image_cache_reset(ImageCache *cache)
 
 #define IMAGE_CACHE_DEPTH 4
 
-static void image_cache_eaging(ImageCache *cache)
+static void image_cache_aging(ImageCache *cache)
 {
 #ifdef IMAGE_CACHE_AGE
     ImageCacheItem *item;
@@ -4500,7 +4500,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     surface = &worker->surfaces[drawable->surface_id];
     canvas = surface->context.canvas;
 
-    image_cache_eaging(&worker->image_cache);
+    image_cache_aging(&worker->image_cache);
 
     worker->preload_group_id = drawable->group_id;
 
commit 7241cc9544de818eb07de7dd99d72f8451ed8038
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 12 15:20:38 2013 +0300

    server: move surface_format_to_image_type to spice_bitmap_utils

diff --git a/server/red_worker.c b/server/red_worker.c
index 175cf92..1caaa51 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -84,6 +84,7 @@
 #include "main_dispatcher.h"
 #include "spice_server_utils.h"
 #include "red_time.h"
+#include "spice_bitmap_utils.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -95,10 +96,6 @@
 //#define ACYCLIC_SURFACE_DEBUG
 //#define DEBUG_CURSORS
 
-#ifdef DUMP_BITMAP
-#include "spice_bitmap_utils.h"
-#endif
-
 //#define UPDATE_AREA_BY_TREE
 
 #define CMD_RING_POLL_TIMEOUT 10 //milli
@@ -3931,23 +3928,6 @@ static void red_get_area(RedWorker *worker, int surface_id, const SpiceRect *are
     canvas->ops->read_bits(canvas, dest, dest_stride, area);
 }
 
-static int surface_format_to_image_type(uint32_t surface_format)
-{
-    switch (surface_format) {
-    case SPICE_SURFACE_FMT_16_555:
-        return SPICE_BITMAP_FMT_16BIT;
-    case SPICE_SURFACE_FMT_32_xRGB:
-        return SPICE_BITMAP_FMT_32BIT;
-    case SPICE_SURFACE_FMT_32_ARGB:
-        return SPICE_BITMAP_FMT_RGBA;
-    case SPICE_SURFACE_FMT_8_A:
-        return SPICE_BITMAP_FMT_8BIT_A;
-    default:
-        spice_critical("Unsupported surface format");
-    }
-    return 0;
-}
-
 static int rgb32_data_has_alpha(int width, int height, size_t stride,
                                 uint8_t *data, int *all_set_out)
 {
@@ -4008,7 +3988,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
 
     QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
     image->u.bitmap.flags = surface->context.top_down ? SPICE_BITMAP_FLAGS_TOP_DOWN : 0;
-    image->u.bitmap.format = surface_format_to_image_type(surface->context.format);
+    image->u.bitmap.format = spice_bitmap_from_surface_type(surface->context.format);
     image->u.bitmap.stride = dest_stride;
     image->descriptor.width = image->u.bitmap.x = width;
     image->descriptor.height = image->u.bitmap.y = height;
@@ -5309,7 +5289,7 @@ static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surf
     item->refs = 1;
     item->surface_id = surface_id;
     item->image_format =
-        surface_format_to_image_type(surface->context.format);
+        spice_bitmap_from_surface_type(surface->context.format);
     item->image_flags = 0;
     item->pos.x = area->left;
     item->pos.y = area->top;
@@ -9767,7 +9747,7 @@ static inline void flush_cursor_commands(RedWorker *worker)
     }
 }
 
-// TODO: on timeout, don't disconnect all channeld immeduiatly - try to disconnect the slowest ones
+// TODO: on timeout, don't disconnect all channels immediatly - try to disconnect the slowest ones
 // first and maybe turn timeouts to several timeouts in order to disconnect channels gradually.
 // Should use disconnect or shutdown?
 static inline void flush_all_qxl_commands(RedWorker *worker)
diff --git a/server/spice_bitmap_utils.c b/server/spice_bitmap_utils.c
index 9044622..ce0a5ed 100644
--- a/server/spice_bitmap_utils.c
+++ b/server/spice_bitmap_utils.c
@@ -5,6 +5,23 @@
 
 #include "spice_bitmap_utils.h"
 
+int spice_bitmap_from_surface_type(uint32_t surface_format)
+{
+    switch (surface_format) {
+    case SPICE_SURFACE_FMT_16_555:
+        return SPICE_BITMAP_FMT_16BIT;
+    case SPICE_SURFACE_FMT_32_xRGB:
+        return SPICE_BITMAP_FMT_32BIT;
+    case SPICE_SURFACE_FMT_32_ARGB:
+        return SPICE_BITMAP_FMT_RGBA;
+    case SPICE_SURFACE_FMT_8_A:
+        return SPICE_BITMAP_FMT_8BIT_A;
+    default:
+        spice_critical("Unsupported surface format");
+    }
+    return 0;
+}
+
 #define RAM_PATH "/tmp/tmpfs"
 
 static void dump_palette(FILE *f, SpicePalette* plt)
diff --git a/server/spice_bitmap_utils.h b/server/spice_bitmap_utils.h
index ae4939f..69860e5 100644
--- a/server/spice_bitmap_utils.h
+++ b/server/spice_bitmap_utils.h
@@ -3,4 +3,6 @@
 
 void dump_bitmap(SpiceBitmap *bitmap);
 
+int spice_bitmap_from_surface_type(uint32_t surface_format);
+
 #endif
commit 9b8ff0428468b7f081fe6f2b27774af2d0b4dadf
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 12 19:48:24 2013 +0300

    server: s/red_wait_all_sent/red_channel_wait_all_sent/

diff --git a/server/red_channel.c b/server/red_channel.c
index d0b979e..37b0c1c 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -2274,7 +2274,7 @@ static void rcc_shutdown_if_pending_send(RedChannelClient *rcc)
     }
 }
 
-void red_wait_all_sent(RedChannel *channel)
+void red_channel_wait_all_sent(RedChannel *channel)
 {
     uint64_t end_time;
     uint32_t max_pipe_size;
diff --git a/server/red_channel.h b/server/red_channel.h
index b2a3a6a..9021b3f 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -604,6 +604,6 @@ void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
 void red_wait_outgoing_item(RedChannelClient *rcc);
 
 /* blocking function */
-void red_wait_all_sent(RedChannel *channel);
+void red_channel_wait_all_sent(RedChannel *channel);
 
 #endif
diff --git a/server/red_worker.c b/server/red_worker.c
index 0e86cff..175cf92 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -11136,7 +11136,7 @@ static inline void red_cursor_reset(RedWorker *worker)
         if (!worker->cursor_channel->common.during_target_migrate) {
             red_pipes_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
         }
-        red_wait_all_sent(&worker->cursor_channel->common.base);
+        red_channel_wait_all_sent(&worker->cursor_channel->common.base);
     }
 }
 
@@ -11419,8 +11419,8 @@ void handle_dev_stop(void *opaque, void *payload)
      * purge the pipe, send destroy_all_surfaces
      * to the client (there is no such message right now), and start
      * from scratch on the destination side */
-    red_wait_all_sent(&worker->display_channel->common.base);
-    red_wait_all_sent(&worker->cursor_channel->common.base);
+    red_channel_wait_all_sent(&worker->display_channel->common.base);
+    red_channel_wait_all_sent(&worker->cursor_channel->common.base);
 }
 
 static int display_channel_wait_for_migrate_data(DisplayChannel *display)
commit bc50ff07676fa0b15df3aa2ae7e54936a8f81f95
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 12 15:01:42 2013 +0300

    server: move three functions to red_channel
    
    Three blocking functions, one was split to leave the display channel
    specific referencing of the DrawablePipeItem being sent inside
    red_worker, but the rest (most) of the timeout logic was moved to
    red_channel, including the associated constants.
    
    Moved functions:
    red_channel_client_wait_pipe_item_sent
    red_wait_outgoing_item
    red_wait_all_sent
    
    Introduces red_time.h & red_time.c for a small helper function dealing
    with time.h

diff --git a/server/red_channel.c b/server/red_channel.c
index d565634..d0b979e 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -41,6 +41,7 @@
 #include "red_channel.h"
 #include "reds.h"
 #include "main_dispatcher.h"
+#include "red_time.h"
 
 typedef struct EmptyMsgPipeItem {
     PipeItem base;
@@ -50,6 +51,12 @@ typedef struct EmptyMsgPipeItem {
 #define PING_TEST_TIMEOUT_MS 15000
 #define PING_TEST_IDLE_NET_TIMEOUT_MS 100
 
+#define DETACH_TIMEOUT 15000000000ULL //nano
+#define DETACH_SLEEP_DURATION 10000 //micro
+
+#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano
+#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro
+
 enum QosPingState {
     PING_STATE_NONE,
     PING_STATE_TIMER,
@@ -2195,3 +2202,102 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel)
     }
     return sum;
 }
+
+void red_wait_outgoing_item(RedChannelClient *rcc)
+{
+    uint64_t end_time;
+    int blocked;
+
+    if (!red_channel_client_blocked(rcc)) {
+        return;
+    }
+    end_time = red_now() + DETACH_TIMEOUT;
+    spice_info("blocked");
+
+    do {
+        usleep(DETACH_SLEEP_DURATION);
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
+    } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time);
+
+    if (blocked) {
+        spice_warning("timeout");
+        // TODO - shutting down the socket but we still need to trigger
+        // disconnection. Right now we wait for main channel to error for that.
+        red_channel_client_shutdown(rcc);
+    } else {
+        spice_assert(red_channel_client_no_item_being_sent(rcc));
+    }
+}
+
+/* TODO: more evil sync stuff. anything with the word wait in it's name. */
+void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
+                                            PipeItem *item)
+{
+    uint64_t end_time;
+    int item_in_pipe;
+
+    spice_info(NULL);
+
+    end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
+
+    rcc->channel->channel_cbs.hold_item(rcc, item);
+
+    if (red_channel_client_blocked(rcc)) {
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
+    }
+    red_channel_client_push(rcc);
+
+    while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
+        usleep(CHANNEL_PUSH_SLEEP_DURATION);
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
+        red_channel_client_push(rcc);
+    }
+
+    if (item_in_pipe) {
+        spice_warning("timeout");
+        red_channel_client_disconnect(rcc);
+    } else {
+        red_wait_outgoing_item(rcc);
+    }
+    red_channel_client_release_item(rcc, item, TRUE);
+}
+
+static void rcc_shutdown_if_pending_send(RedChannelClient *rcc)
+{
+    if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) {
+        red_channel_client_shutdown(rcc);
+    } else {
+        spice_assert(red_channel_client_no_item_being_sent(rcc));
+    }
+}
+
+void red_wait_all_sent(RedChannel *channel)
+{
+    uint64_t end_time;
+    uint32_t max_pipe_size;
+    int blocked = FALSE;
+
+    end_time = red_now() + DETACH_TIMEOUT;
+
+    red_channel_push(channel);
+    while (((max_pipe_size = red_channel_max_pipe_size(channel)) ||
+           (blocked = red_channel_any_blocked(channel))) &&
+           red_now() < end_time) {
+        spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked);
+        usleep(DETACH_SLEEP_DURATION);
+        red_channel_receive(channel);
+        red_channel_send(channel);
+        red_channel_push(channel);
+    }
+
+    if (max_pipe_size || blocked) {
+        spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)",
+                       max_pipe_size, blocked);
+        red_channel_apply_clients(channel, rcc_shutdown_if_pending_send);
+    } else {
+        spice_assert(red_channel_no_item_being_sent(channel));
+    }
+}
diff --git a/server/red_channel.h b/server/red_channel.h
index 0dd73ea..b2a3a6a 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -596,4 +596,14 @@ int red_client_during_migrate_at_target(RedClient *client);
 
 void red_client_migrate(RedClient *client);
 
+/* blocking function */
+void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
+                                            PipeItem *item);
+
+/* blocking function */
+void red_wait_outgoing_item(RedChannelClient *rcc);
+
+/* blocking function */
+void red_wait_all_sent(RedChannel *channel);
+
 #endif
diff --git a/server/red_time.c b/server/red_time.c
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/server/red_time.c
@@ -0,0 +1 @@
+
diff --git a/server/red_time.h b/server/red_time.h
new file mode 100644
index 0000000..ffa97f2
--- /dev/null
+++ b/server/red_time.h
@@ -0,0 +1,15 @@
+#ifndef H_RED_TIME
+#define H_RED_TIME
+
+#include <time.h>
+
+static inline uint64_t red_now(void)
+{
+    struct timespec time;
+
+    clock_gettime(CLOCK_MONOTONIC, &time);
+
+    return ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
+}
+
+#endif
diff --git a/server/red_worker.c b/server/red_worker.c
index 3b9c5b0..0e86cff 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -83,6 +83,7 @@
 #include "spice_timer_queue.h"
 #include "main_dispatcher.h"
 #include "spice_server_utils.h"
+#include "red_time.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -103,12 +104,6 @@
 #define CMD_RING_POLL_TIMEOUT 10 //milli
 #define CMD_RING_POLL_RETRIES 200
 
-#define DETACH_TIMEOUT 15000000000ULL //nano
-#define DETACH_SLEEP_DURATION 10000 //micro
-
-#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano
-#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro
-
 #define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano
 #define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
 #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
@@ -1104,10 +1099,8 @@ static void cursor_channel_client_release_item_before_push(CursorChannelClient *
                                                            PipeItem *item);
 static void cursor_channel_client_release_item_after_push(CursorChannelClient *ccc,
                                                           PipeItem *item);
-static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item);
 
 static void red_push_monitors_config(DisplayChannelClient *dcc);
-static inline uint64_t red_now(void);
 
 /*
  * Macros to make iterating over stuff easier
@@ -2095,12 +2088,10 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int
     }
 
     if (item) {
-        red_wait_pipe_item_sent(&dcc->common.base, item);
+        red_channel_client_wait_pipe_item_sent(&dcc->common.base, item);
     }
 }
 
-static void red_wait_outgoing_item(RedChannelClient *rcc);
-
 static void red_clear_surface_drawables_from_pipes(RedWorker *worker, int surface_id,
     int force, int wait_for_outgoing_item)
 {
@@ -5086,15 +5077,6 @@ static void qxl_process_cursor(RedWorker *worker, RedCursorCmd *cursor_cmd, uint
     red_release_cursor(worker, cursor_item);
 }
 
-static inline uint64_t red_now(void)
-{
-    struct timespec time;
-
-    clock_gettime(CLOCK_MONOTONIC, &time);
-
-    return ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
-}
-
 static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
 {
     QXLCommandExt ext_cmd;
@@ -10986,105 +10968,6 @@ typedef struct __attribute__ ((__packed__)) CursorData {
     SpiceCursor _cursor;
 } CursorData;
 
-static void red_wait_outgoing_item(RedChannelClient *rcc)
-{
-    uint64_t end_time;
-    int blocked;
-
-    if (!red_channel_client_blocked(rcc)) {
-        return;
-    }
-    end_time = red_now() + DETACH_TIMEOUT;
-    spice_info("blocked");
-
-    do {
-        usleep(DETACH_SLEEP_DURATION);
-        red_channel_client_receive(rcc);
-        red_channel_client_send(rcc);
-    } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time);
-
-    if (blocked) {
-        spice_warning("timeout");
-        // TODO - shutting down the socket but we still need to trigger
-        // disconnection. Right now we wait for main channel to error for that.
-        red_channel_client_shutdown(rcc);
-    } else {
-        spice_assert(red_channel_client_no_item_being_sent(rcc));
-    }
-}
-
-static void rcc_shutdown_if_pending_send(RedChannelClient *rcc)
-{
-    if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) {
-        red_channel_client_shutdown(rcc);
-    } else {
-        spice_assert(red_channel_client_no_item_being_sent(rcc));
-    }
-}
-
-static void red_wait_all_sent(RedChannel *channel)
-{
-    uint64_t end_time;
-    uint32_t max_pipe_size;
-    int blocked = FALSE;
-
-    end_time = red_now() + DETACH_TIMEOUT;
-
-    red_channel_push(channel);
-    while (((max_pipe_size = red_channel_max_pipe_size(channel)) ||
-           (blocked = red_channel_any_blocked(channel))) &&
-           red_now() < end_time) {
-        spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked);
-        usleep(DETACH_SLEEP_DURATION);
-        red_channel_receive(channel);
-        red_channel_send(channel);
-        red_channel_push(channel);
-    }
-
-    if (max_pipe_size || blocked) {
-        spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)",
-                       max_pipe_size, blocked);
-        red_channel_apply_clients(channel, rcc_shutdown_if_pending_send);
-    } else {
-        spice_assert(red_channel_no_item_being_sent(channel));
-    }
-}
-
-/* TODO: more evil sync stuff. anything with the word wait in it's name. */
-static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item)
-{
-    DrawablePipeItem *dpi;
-    uint64_t end_time;
-    int item_in_pipe;
-
-    spice_info(NULL);
-    dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
-    ref_drawable_pipe_item(dpi);
-
-    end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
-
-    if (red_channel_client_blocked(rcc)) {
-        red_channel_client_receive(rcc);
-        red_channel_client_send(rcc);
-    }
-    red_channel_client_push(rcc);
-
-    while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
-        usleep(CHANNEL_PUSH_SLEEP_DURATION);
-        red_channel_client_receive(rcc);
-        red_channel_client_send(rcc);
-        red_channel_client_push(rcc);
-    }
-
-    if (item_in_pipe) {
-        spice_warning("timeout");
-        red_channel_client_disconnect(rcc);
-    } else {
-        red_wait_outgoing_item(rcc);
-    }
-    put_drawable_pipe_item(dpi);
-}
-
 static void surface_dirty_region_to_rects(RedSurface *surface,
                                           QXLRect *qxl_dirty_rects,
                                           uint32_t num_dirty_rects,
commit fe38ddf724a7cd47fe8225ba6b10e9abaaf53c89
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 12 14:44:21 2013 +0300

    server: move bit set/clear utilities out of red_worker.h

diff --git a/server/Makefile.am b/server/Makefile.am
index e5392ba..feee2f1 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -99,6 +99,7 @@ libspice_server_la_SOURCES =			\
 	zlib_encoder.h				\
 	spice_bitmap_utils.h		\
 	spice_bitmap_utils.c		\
+	spice_server_utils.h		\
 	$(NULL)
 
 if SUPPORT_TUNNEL
diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index ef47c28..03a4c4a 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -39,8 +39,10 @@
 #endif // USE_OPENGL
 #include "reds.h"
 #include "dispatcher.h"
-#include "red_dispatcher.h"
 #include "red_parse_qxl.h"
+#include "spice_server_utils.h"
+
+#include "red_dispatcher.h"
 
 static int num_active_workers = 0;
 
diff --git a/server/red_worker.c b/server/red_worker.c
index 0704279..3b9c5b0 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -82,6 +82,7 @@
 #include "migration_protocol.h"
 #include "spice_timer_queue.h"
 #include "main_dispatcher.h"
+#include "spice_server_utils.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
diff --git a/server/red_worker.h b/server/red_worker.h
index 796b090..272661f 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -22,24 +22,6 @@
 #include <errno.h>
 #include "red_common.h"
 
-
-static inline void set_bit(int index, uint32_t *addr)
-{
-    uint32_t mask = 1 << index;
-    __sync_or_and_fetch(addr, mask);
-}
-
-static inline void clear_bit(int index, uint32_t *addr)
-{
-    uint32_t mask = ~(1 << index);
-    __sync_and_and_fetch(addr, mask);
-}
-
-static inline int test_bit(int index, uint32_t val)
-{
-    return val & (1u << index);
-}
-
 enum {
     RED_WORKER_PENDING_WAKEUP,
     RED_WORKER_PENDING_OOM,
diff --git a/server/spice_server_utils.h b/server/spice_server_utils.h
new file mode 100644
index 0000000..b3ddc27
--- /dev/null
+++ b/server/spice_server_utils.h
@@ -0,0 +1,23 @@
+#ifndef H_SPICE_SERVER_UTIL
+#define H_SPICE_SERVER_UTIL
+
+#include <unistd.h>
+
+static inline void set_bit(int index, uint32_t *addr)
+{
+    uint32_t mask = 1 << index;
+    __sync_or_and_fetch(addr, mask);
+}
+
+static inline void clear_bit(int index, uint32_t *addr)
+{
+    uint32_t mask = ~(1 << index);
+    __sync_and_and_fetch(addr, mask);
+}
+
+static inline int test_bit(int index, uint32_t val)
+{
+    return val & (1u << index);
+}
+
+#endif
commit 376264b00925ce417be2a8a5097c26d7cc58d608
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 12 14:43:53 2013 +0300

    server: move dump_bitmap to separate file

diff --git a/server/Makefile.am b/server/Makefile.am
index d351dae..e5392ba 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -97,6 +97,8 @@ libspice_server_la_SOURCES =			\
 	spice_timer_queue.h			\
 	zlib_encoder.c				\
 	zlib_encoder.h				\
+	spice_bitmap_utils.h		\
+	spice_bitmap_utils.c		\
 	$(NULL)
 
 if SUPPORT_TUNNEL
diff --git a/server/red_worker.c b/server/red_worker.c
index 0674174..0704279 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -93,6 +93,10 @@
 //#define ACYCLIC_SURFACE_DEBUG
 //#define DEBUG_CURSORS
 
+#ifdef DUMP_BITMAP
+#include "spice_bitmap_utils.h"
+#endif
+
 //#define UPDATE_AREA_BY_TREE
 
 #define CMD_RING_POLL_TIMEOUT 10 //milli
@@ -1101,10 +1105,6 @@ static void cursor_channel_client_release_item_after_push(CursorChannelClient *c
                                                           PipeItem *item);
 static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item);
 
-#ifdef DUMP_BITMAP
-static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
-#endif
-
 static void red_push_monitors_config(DisplayChannelClient *dcc);
 static inline uint64_t red_now(void);
 
@@ -12292,152 +12292,3 @@ SPICE_GNUC_NORETURN void *red_worker_main(void *arg)
     }
     abort();
 }
-
-#ifdef DUMP_BITMAP
-#include <stdio.h>
-static void dump_palette(FILE *f, SpicePalette* plt)
-{
-    int i;
-    for (i = 0; i < plt->num_ents; i++) {
-        fwrite(plt->ents + i, sizeof(uint32_t), 1, f);
-    }
-}
-
-static void dump_line(FILE *f, uint8_t* line, uint16_t n_pixel_bits, int width, int row_size)
-{
-    int i;
-    int copy_bytes_size = SPICE_ALIGN(n_pixel_bits * width, 8) / 8;
-
-    fwrite(line, 1, copy_bytes_size, f);
-    if (row_size > copy_bytes_size) {
-        // each line should be 4 bytes aligned
-        for (i = copy_bytes_size; i < row_size; i++) {
-            fprintf(f, "%c", 0);
-        }
-    }
-}
-
-#define RAM_PATH "/tmp/tmpfs"
-
-static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id)
-{
-    static uint32_t file_id = 0;
-
-    char file_str[200];
-    int rgb = TRUE;
-    uint16_t n_pixel_bits;
-    SpicePalette *plt = NULL;
-    uint32_t id;
-    int row_size;
-    uint32_t file_size;
-    int alpha = 0;
-    uint32_t header_size = 14 + 40;
-    uint32_t bitmap_data_offset;
-    uint32_t tmp_u32;
-    int32_t tmp_32;
-    uint16_t tmp_u16;
-    FILE *f;
-    int i;
-
-    switch (bitmap->format) {
-    case SPICE_BITMAP_FMT_1BIT_BE:
-    case SPICE_BITMAP_FMT_1BIT_LE:
-        rgb = FALSE;
-        n_pixel_bits = 1;
-        break;
-    case SPICE_BITMAP_FMT_4BIT_BE:
-    case SPICE_BITMAP_FMT_4BIT_LE:
-        rgb = FALSE;
-        n_pixel_bits = 4;
-        break;
-    case SPICE_BITMAP_FMT_8BIT:
-        rgb = FALSE;
-        n_pixel_bits = 8;
-        break;
-    case SPICE_BITMAP_FMT_16BIT:
-        n_pixel_bits = 16;
-        break;
-    case SPICE_BITMAP_FMT_24BIT:
-        n_pixel_bits = 24;
-        break;
-    case SPICE_BITMAP_FMT_32BIT:
-        n_pixel_bits = 32;
-        break;
-    case SPICE_BITMAP_FMT_RGBA:
-        n_pixel_bits = 32;
-        alpha = 1;
-        break;
-    default:
-        spice_error("invalid bitmap format  %u", bitmap->format);
-    }
-
-    if (!rgb) {
-        if (!bitmap->palette) {
-            return; // dont dump masks.
-        }
-        plt = bitmap->palette;
-    }
-    row_size = (((bitmap->x * n_pixel_bits) + 31) / 32) * 4;
-    bitmap_data_offset = header_size;
-
-    if (plt) {
-        bitmap_data_offset += plt->num_ents * 4;
-    }
-    file_size = bitmap_data_offset + (bitmap->y * row_size);
-
-    id = ++file_id;
-    sprintf(file_str, "%s/%u.bmp", RAM_PATH, id);
-
-    f = fopen(file_str, "wb");
-    if (!f) {
-        spice_error("Error creating bmp");
-        return;
-    }
-
-    /* writing the bmp v3 header */
-    fprintf(f, "BM");
-    fwrite(&file_size, sizeof(file_size), 1, f);
-    tmp_u16 = alpha ? 1 : 0;
-    fwrite(&tmp_u16, sizeof(tmp_u16), 1, f); // reserved for application
-    tmp_u16 = 0;
-    fwrite(&tmp_u16, sizeof(tmp_u16), 1, f);
-    fwrite(&bitmap_data_offset, sizeof(bitmap_data_offset), 1, f);
-    tmp_u32 = header_size - 14;
-    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f); // sub header size
-    tmp_32 = bitmap->x;
-    fwrite(&tmp_32, sizeof(tmp_32), 1, f);
-    tmp_32 = bitmap->y;
-    fwrite(&tmp_32, sizeof(tmp_32), 1, f);
-
-    tmp_u16 = 1;
-    fwrite(&tmp_u16, sizeof(tmp_u16), 1, f); // color plane
-    fwrite(&n_pixel_bits, sizeof(n_pixel_bits), 1, f); // pixel depth
-
-    tmp_u32 = 0;
-    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f); // compression method
-
-    tmp_u32 = 0; //file_size - bitmap_data_offset;
-    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f); // image size
-    tmp_32 = 0;
-    fwrite(&tmp_32, sizeof(tmp_32), 1, f);
-    fwrite(&tmp_32, sizeof(tmp_32), 1, f);
-    tmp_u32 = (!plt) ? 0 : plt->num_ents; // plt entries
-    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f);
-    tmp_u32 = 0;
-    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f);
-
-    if (plt) {
-        dump_palette(f, plt);
-    }
-    /* writing the data */
-    for (i = 0; i < bitmap->data->num_chunks; i++) {
-        SpiceChunk *chunk = &bitmap->data->chunk[i];
-        int num_lines = chunk->len / bitmap->stride;
-        for (i = 0; i < num_lines; i++) {
-            dump_line(f, chunk->data + (i * bitmap->stride), n_pixel_bits, bitmap->x, row_size);
-        }
-    }
-    fclose(f);
-}
-
-#endif
diff --git a/server/spice_bitmap_utils.c b/server/spice_bitmap_utils.c
new file mode 100644
index 0000000..9044622
--- /dev/null
+++ b/server/spice_bitmap_utils.c
@@ -0,0 +1,150 @@
+#include <stdio.h>
+
+#include "common/log.h"
+#include "common/draw.h"
+
+#include "spice_bitmap_utils.h"
+
+#define RAM_PATH "/tmp/tmpfs"
+
+static void dump_palette(FILE *f, SpicePalette* plt)
+{
+    int i;
+    for (i = 0; i < plt->num_ents; i++) {
+        fwrite(plt->ents + i, sizeof(uint32_t), 1, f);
+    }
+}
+
+static void dump_line(FILE *f, uint8_t* line, uint16_t n_pixel_bits, int width, int row_size)
+{
+    int i;
+    int copy_bytes_size = SPICE_ALIGN(n_pixel_bits * width, 8) / 8;
+
+    fwrite(line, 1, copy_bytes_size, f);
+    if (row_size > copy_bytes_size) {
+        // each line should be 4 bytes aligned
+        for (i = copy_bytes_size; i < row_size; i++) {
+            fprintf(f, "%c", 0);
+        }
+    }
+}
+void dump_bitmap(SpiceBitmap *bitmap)
+{
+    static uint32_t file_id = 0;
+
+    char file_str[200];
+    int rgb = TRUE;
+    uint16_t n_pixel_bits;
+    SpicePalette *plt = NULL;
+    uint32_t id;
+    int row_size;
+    uint32_t file_size;
+    int alpha = 0;
+    uint32_t header_size = 14 + 40;
+    uint32_t bitmap_data_offset;
+    uint32_t tmp_u32;
+    int32_t tmp_32;
+    uint16_t tmp_u16;
+    FILE *f;
+    int i;
+
+    switch (bitmap->format) {
+    case SPICE_BITMAP_FMT_1BIT_BE:
+    case SPICE_BITMAP_FMT_1BIT_LE:
+        rgb = FALSE;
+        n_pixel_bits = 1;
+        break;
+    case SPICE_BITMAP_FMT_4BIT_BE:
+    case SPICE_BITMAP_FMT_4BIT_LE:
+        rgb = FALSE;
+        n_pixel_bits = 4;
+        break;
+    case SPICE_BITMAP_FMT_8BIT:
+        rgb = FALSE;
+        n_pixel_bits = 8;
+        break;
+    case SPICE_BITMAP_FMT_16BIT:
+        n_pixel_bits = 16;
+        break;
+    case SPICE_BITMAP_FMT_24BIT:
+        n_pixel_bits = 24;
+        break;
+    case SPICE_BITMAP_FMT_32BIT:
+        n_pixel_bits = 32;
+        break;
+    case SPICE_BITMAP_FMT_RGBA:
+        n_pixel_bits = 32;
+        alpha = 1;
+        break;
+    default:
+        spice_error("invalid bitmap format  %u", bitmap->format);
+    }
+
+    if (!rgb) {
+        if (!bitmap->palette) {
+            return; // dont dump masks.
+        }
+        plt = bitmap->palette;
+    }
+    row_size = (((bitmap->x * n_pixel_bits) + 31) / 32) * 4;
+    bitmap_data_offset = header_size;
+
+    if (plt) {
+        bitmap_data_offset += plt->num_ents * 4;
+    }
+    file_size = bitmap_data_offset + (bitmap->y * row_size);
+
+    id = ++file_id;
+    sprintf(file_str, "%s/%u.bmp", RAM_PATH, id);
+
+    f = fopen(file_str, "wb");
+    if (!f) {
+        spice_error("Error creating bmp");
+        return;
+    }
+
+    /* writing the bmp v3 header */
+    fprintf(f, "BM");
+    fwrite(&file_size, sizeof(file_size), 1, f);
+    tmp_u16 = alpha ? 1 : 0;
+    fwrite(&tmp_u16, sizeof(tmp_u16), 1, f); // reserved for application
+    tmp_u16 = 0;
+    fwrite(&tmp_u16, sizeof(tmp_u16), 1, f);
+    fwrite(&bitmap_data_offset, sizeof(bitmap_data_offset), 1, f);
+    tmp_u32 = header_size - 14;
+    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f); // sub header size
+    tmp_32 = bitmap->x;
+    fwrite(&tmp_32, sizeof(tmp_32), 1, f);
+    tmp_32 = bitmap->y;
+    fwrite(&tmp_32, sizeof(tmp_32), 1, f);
+
+    tmp_u16 = 1;
+    fwrite(&tmp_u16, sizeof(tmp_u16), 1, f); // color plane
+    fwrite(&n_pixel_bits, sizeof(n_pixel_bits), 1, f); // pixel depth
+
+    tmp_u32 = 0;
+    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f); // compression method
+
+    tmp_u32 = 0; //file_size - bitmap_data_offset;
+    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f); // image size
+    tmp_32 = 0;
+    fwrite(&tmp_32, sizeof(tmp_32), 1, f);
+    fwrite(&tmp_32, sizeof(tmp_32), 1, f);
+    tmp_u32 = (!plt) ? 0 : plt->num_ents; // plt entries
+    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f);
+    tmp_u32 = 0;
+    fwrite(&tmp_u32, sizeof(tmp_u32), 1, f);
+
+    if (plt) {
+        dump_palette(f, plt);
+    }
+    /* writing the data */
+    for (i = 0; i < bitmap->data->num_chunks; i++) {
+        SpiceChunk *chunk = &bitmap->data->chunk[i];
+        int num_lines = chunk->len / bitmap->stride;
+        for (i = 0; i < num_lines; i++) {
+            dump_line(f, chunk->data + (i * bitmap->stride), n_pixel_bits, bitmap->x, row_size);
+        }
+    }
+    fclose(f);
+}
diff --git a/server/spice_bitmap_utils.h b/server/spice_bitmap_utils.h
new file mode 100644
index 0000000..ae4939f
--- /dev/null
+++ b/server/spice_bitmap_utils.h
@@ -0,0 +1,6 @@
+#ifndef H_SPICE_BITMAP_UTILS
+#define H_SPICE_BITMAP_UTILS
+
+void dump_bitmap(SpiceBitmap *bitmap);
+
+#endif
commit ff672924caf10c055e827ece9459e1fe2372456c
Author: Alon Levy <alevy at redhat.com>
Date:   Sat Aug 3 17:40:25 2013 +0200

    server/red_worker.c:red_process_drawable: rename item to drawable

diff --git a/server/red_worker.c b/server/red_worker.c
index 29a6295..0674174 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4189,23 +4189,23 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *red_draw
                                         uint32_t group_id)
 {
     int surface_id;
-    Drawable *item = get_drawable(worker, red_drawable->effect, red_drawable, group_id);
+    Drawable *drawable = get_drawable(worker, red_drawable->effect, red_drawable, group_id);
 
-    if (!item) {
+    if (!drawable) {
         rendering_incorrect("failed to get_drawable");
         return;
     }
 
-    surface_id = item->surface_id;
+    surface_id = drawable->surface_id;
 
     worker->surfaces[surface_id].refs++;
 
-    region_add(&item->tree_item.base.rgn, &red_drawable->bbox);
+    region_add(&drawable->tree_item.base.rgn, &red_drawable->bbox);
 #ifdef PIPE_DEBUG
     printf("TEST: DRAWABLE: id %u type %s effect %u bbox %u %u %u %u\n",
-           item->tree_item.base.id,
+           drawable->tree_item.base.id,
            draw_type_to_str(red_drawable->type),
-           item->tree_item.effect,
+           drawable->tree_item.effect,
            red_drawable->bbox.top, red_drawable->bbox.left,
            red_drawable->bbox.bottom, red_drawable->bbox.right);
 #endif
@@ -4215,7 +4215,7 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *red_draw
 
         region_init(&rgn);
         add_clip_rects(&rgn, red_drawable->clip.rects);
-        region_and(&item->tree_item.base.rgn, &rgn);
+        region_and(&drawable->tree_item.base.rgn, &rgn);
         region_destroy(&rgn);
     }
     /*
@@ -4224,13 +4224,13 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *red_draw
         However, surface->depend_on_me is affected by a drawable only
         as long as it is in the current tree (hasn't been rendered yet).
     */
-    red_inc_surfaces_drawable_dependencies(worker, item);
+    red_inc_surfaces_drawable_dependencies(worker, drawable);
 
-    if (region_is_empty(&item->tree_item.base.rgn)) {
+    if (region_is_empty(&drawable->tree_item.base.rgn)) {
         goto cleanup;
     }
 
-    if (!red_handle_self_bitmap(worker, item)) {
+    if (!red_handle_self_bitmap(worker, drawable)) {
         goto cleanup;
     }
 
@@ -4238,22 +4238,22 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *red_draw
         goto cleanup;
     }
 
-    if (!red_handle_surfaces_dependencies(worker, item)) {
+    if (!red_handle_surfaces_dependencies(worker, drawable)) {
         goto cleanup;
     }
 
-    if (red_current_add_qxl(worker, &worker->surfaces[surface_id].current, item,
+    if (red_current_add_qxl(worker, &worker->surfaces[surface_id].current, drawable,
                             red_drawable)) {
-        if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
+        if (drawable->tree_item.effect != QXL_EFFECT_OPAQUE) {
             worker->transparent_count++;
         }
-        red_pipes_add_drawable(worker, item);
+        red_pipes_add_drawable(worker, drawable);
 #ifdef DRAW_ALL
-        red_draw_qxl_drawable(worker, item);
+        red_draw_qxl_drawable(worker, drawable);
 #endif
     }
 cleanup:
-    release_drawable(worker, item);
+    release_drawable(worker, drawable);
 }
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
commit 3a25c2070440dffbf34be16a02e1ad1b341de626
Author: Alon Levy <alevy at redhat.com>
Date:   Sat Aug 3 17:39:39 2013 +0200

    server/red_worker.c:red_process_drawable: rename drawable to red_drawable

diff --git a/server/red_worker.c b/server/red_worker.c
index 08e2a43..29a6295 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4185,11 +4185,11 @@ static inline void red_inc_surfaces_drawable_dependencies(RedWorker *worker, Dra
     }
 }
 
-static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable,
+static inline void red_process_drawable(RedWorker *worker, RedDrawable *red_drawable,
                                         uint32_t group_id)
 {
     int surface_id;
-    Drawable *item = get_drawable(worker, drawable->effect, drawable, group_id);
+    Drawable *item = get_drawable(worker, red_drawable->effect, red_drawable, group_id);
 
     if (!item) {
         rendering_incorrect("failed to get_drawable");
@@ -4200,20 +4200,21 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable
 
     worker->surfaces[surface_id].refs++;
 
-    region_add(&item->tree_item.base.rgn, &drawable->bbox);
+    region_add(&item->tree_item.base.rgn, &red_drawable->bbox);
 #ifdef PIPE_DEBUG
     printf("TEST: DRAWABLE: id %u type %s effect %u bbox %u %u %u %u\n",
            item->tree_item.base.id,
-           draw_type_to_str(drawable->type),
+           draw_type_to_str(red_drawable->type),
            item->tree_item.effect,
-           drawable->bbox.top, drawable->bbox.left, drawable->bbox.bottom, drawable->bbox.right);
+           red_drawable->bbox.top, red_drawable->bbox.left,
+           red_drawable->bbox.bottom, red_drawable->bbox.right);
 #endif
 
-    if (drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
+    if (red_drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
         QRegion rgn;
 
         region_init(&rgn);
-        add_clip_rects(&rgn, drawable->clip.rects);
+        add_clip_rects(&rgn, red_drawable->clip.rects);
         region_and(&item->tree_item.base.rgn, &rgn);
         region_destroy(&rgn);
     }
@@ -4242,7 +4243,7 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable
     }
 
     if (red_current_add_qxl(worker, &worker->surfaces[surface_id].current, item,
-                            drawable)) {
+                            red_drawable)) {
         if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
             worker->transparent_count++;
         }
commit 478a1906b0e39b37a6cc8bc2e92161afe63bf57a
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Aug 12 12:45:56 2013 +0300

    red_worker: mark DRAW_ALL as broken
    
    setting DRAW_ALL define doesn't produce correct rendering. Using
    update_area instead of red_draw_qxl_drawable will work but it shouldn't
    be required. This is not work I intend to do right now, so marking it
    for anyone looking at this in the future.

diff --git a/server/red_worker.c b/server/red_worker.c
index 9896696..08e2a43 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -87,6 +87,7 @@
 //#define DUMP_BITMAP
 //#define PIPE_DEBUG
 //#define RED_WORKER_STAT
+/* TODO: DRAW_ALL is broken. */
 //#define DRAW_ALL
 //#define COMPRESS_DEBUG
 //#define ACYCLIC_SURFACE_DEBUG


More information about the Spice-commits mailing list