[Spice-commits] 9 commits - configure.ac server/red_dispatcher.c server/red_dispatcher.h server/red_parse_qxl.c server/red_parse_qxl.h server/red_worker.c server/red_worker.h server/spice.h server/spice-server.syms

Alon Levy alon at kemper.freedesktop.org
Wed Jul 20 06:08:23 PDT 2011


 configure.ac             |    2 
 server/red_dispatcher.c  |  474 +++++++++++++++++++++++++++++++++++++++++------
 server/red_dispatcher.h  |    3 
 server/red_parse_qxl.c   |    2 
 server/red_parse_qxl.h   |    2 
 server/red_worker.c      |  262 ++++++++++++++++++-------
 server/red_worker.h      |   12 +
 server/spice-server.syms |   32 ++-
 server/spice.h           |   38 +++
 9 files changed, 687 insertions(+), 140 deletions(-)

New commits:
commit 51628f512456cd26c8c6b417be6b34f3889b33d2
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Jul 13 13:42:52 2011 +0300

    server/red_worker: send surface images to client on-demand after S3/4 wakeup
    
    When surfaces are being reloaded to the worker, we
    will send them to the client only if and when it needs them.

diff --git a/server/red_worker.c b/server/red_worker.c
index 834c1c5..433af2c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -3405,9 +3405,9 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
                                       uint32_t height, int32_t stride, uint32_t format,
-                                      void *line_0, int data_is_valid);
+                                      void *line_0, int data_is_valid, int send_client);
 
-static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface, uint32_t group_id, int data_is_valid)
+static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface, uint32_t group_id, int loadvm)
 {
     int surface_id;
     RedSurface *red_surface;
@@ -3422,6 +3422,7 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
     case QXL_SURFACE_CMD_CREATE: {
         uint32_t height = surface->u.surface_create.height;
         int32_t stride = surface->u.surface_create.stride;
+        int reloaded_surface = loadvm || (surface->flags & QXL_SURF_FLAG_KEEP_DATA);
 
         data = surface->u.surface_create.data;
         if (stride < 0) {
@@ -3429,7 +3430,9 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
         }
         red_create_surface(worker, surface_id, surface->u.surface_create.width,
                            height, stride, surface->u.surface_create.format, data,
-                           data_is_valid);
+                           reloaded_surface,
+                           // reloaded surfaces will be sent on demand
+                           !reloaded_surface);
         set_surface_release_info(worker, surface_id, 1, surface->release_info, group_id);
         break;
     }
@@ -4294,7 +4297,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
 
             red_get_surface_cmd(&worker->mem_slots, ext_cmd.group_id,
                                 surface, ext_cmd.cmd.data);
-            red_process_surface(worker, surface, ext_cmd.group_id, 0);
+            red_process_surface(worker, surface, ext_cmd.group_id, FALSE);
             break;
         }
         default:
@@ -8392,7 +8395,7 @@ static inline void red_create_surface_item(RedWorker *worker, int surface_id)
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width,
                                       uint32_t height, int32_t stride, uint32_t format,
-                                      void *line_0, int data_is_valid)
+                                      void *line_0, int data_is_valid, int send_client)
 {
     uint32_t i;
     RedSurface *surface = &worker->surfaces[surface_id];
@@ -8425,7 +8428,12 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
             PANIC("drawing canvas creating failed - can`t create same type canvas");
         }
 
-        red_create_surface_item(worker, surface_id);
+        if (send_client) {
+            red_create_surface_item(worker, surface_id);
+            if (data_is_valid) {
+                red_add_surface_image(worker, surface_id);
+            }
+        }
         return;
     }
 
@@ -8435,7 +8443,12 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
                                                             surface->context.format, line_0);
         if (surface->context.canvas) { //no need canvas check
             worker->renderer = worker->renderers[i];
-            red_create_surface_item(worker, surface_id);
+            if (send_client) {
+                red_create_surface_item(worker, surface_id);
+                if (data_is_valid) {
+                    red_add_surface_image(worker, surface_id);
+                }
+            }
             return;
         }
     }
@@ -9644,7 +9657,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     }
 
     red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.format,
-                       line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA);
+                       line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA, TRUE);
 
     if (worker->display_channel) {
         red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_MARK);
@@ -9940,7 +9953,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
                 surface_cmd = spice_new0(RedSurfaceCmd, 1);
                 red_get_surface_cmd(&worker->mem_slots, ext.group_id,
                                     surface_cmd, ext.cmd.data);
-                red_process_surface(worker, surface_cmd, ext.group_id, 1);
+                red_process_surface(worker, surface_cmd, ext.group_id, TRUE);
                 break;
             default:
                 red_printf("unhandled loadvm command type (%d)", ext.cmd.type);
commit 3be08d68c01618c81e0dff6caab125a53b4c047e
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 7 12:22:55 2011 +0200

    server/spice.h: bump QXL_MINOR because of QXLWorker and QXLInterface changes

diff --git a/server/spice.h b/server/spice.h
index 549dd0c..15326b2 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -90,7 +90,7 @@ struct SpiceCoreInterface {
 
 #define SPICE_INTERFACE_QXL "qxl"
 #define SPICE_INTERFACE_QXL_MAJOR 3
-#define SPICE_INTERFACE_QXL_MINOR 0
+#define SPICE_INTERFACE_QXL_MINOR 1
 typedef struct QXLInterface QXLInterface;
 typedef struct QXLInstance QXLInstance;
 typedef struct QXLState QXLState;
commit 2a4d97fb780cf3ce2d9060751d0bec2fdc9800a9
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 7 17:25:19 2011 +0200

    server: add QXLWorker.flush_surfaces_async for S3/S4 support
    
    This does the following, all to remove any referenced memory on the pci bars:
        flush_all_qxl_commands(worker);
        flush_all_surfaces(worker);
        red_wait_outgoing_item((RedChannel *)worker->display_channel);
        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
    
    The added api is specifically async, i.e. it calls async_complete
    when done.

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 7f3efe8..7792d90 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -541,6 +541,18 @@ static void qxl_worker_start(QXLWorker *qxl_worker)
     red_dispatcher_start((RedDispatcher*)qxl_worker);
 }
 
+static void red_dispatcher_flush_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie)
+{
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                          RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC);
+
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
+    write_message(dispatcher->channel, &message);
+    send_data(dispatcher->channel, &cookie, sizeof(cookie));
+}
+
 static void red_dispatcher_stop(RedDispatcher *dispatcher)
 {
     RedWorkerMessage message = RED_WORKER_MESSAGE_STOP;
@@ -788,6 +800,12 @@ void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id,
     red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id, 1, cookie);
 }
 
+SPICE_GNUC_VISIBLE
+void spice_qxl_flush_surfaces_async(QXLInstance *instance, uint64_t cookie)
+{
+    red_dispatcher_flush_surfaces_async(instance->st->dispatcher, cookie);
+}
+
 void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t cookie)
 {
     pthread_mutex_lock(&dispatcher->async_lock);
@@ -806,6 +824,8 @@ void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t co
         break;
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
         break;
+    case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
+        break;
     default:
         red_printf("unexpected message");
     }
diff --git a/server/red_worker.c b/server/red_worker.c
index 9b5d9cd..834c1c5 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9675,18 +9675,31 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     red_cursor_reset(worker);
 }
 
-static void handle_dev_stop(RedWorker *worker)
+static void flush_all_surfaces(RedWorker *worker)
 {
     int x;
 
-    ASSERT(worker->running);
-    worker->running = FALSE;
-    red_display_clear_glz_drawables(worker->display_channel);
     for (x = 0; x < NUM_SURFACES; ++x) {
         if (worker->surfaces[x].context.canvas) {
             red_current_flush(worker, x);
         }
     }
+}
+
+static void handle_dev_flush_surfaces(RedWorker *worker)
+{
+    flush_all_qxl_commands(worker);
+    flush_all_surfaces(worker);
+    red_wait_outgoing_item((RedChannel *)worker->display_channel);
+    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+}
+
+static void handle_dev_stop(RedWorker *worker)
+{
+    ASSERT(worker->running);
+    worker->running = FALSE;
+    red_display_clear_glz_drawables(worker->display_channel);
+    flush_all_surfaces(worker);
     red_wait_outgoing_item((RedChannel *)worker->display_channel);
     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
 }
@@ -9727,6 +9740,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
+    case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
         call_async_complete = 1;
         receive_data(worker->channel, &cookie, sizeof(cookie));
         break;
@@ -9936,6 +9950,9 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         }
         break;
     }
+    case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
+        handle_dev_flush_surfaces(worker);
+        break;
     default:
         red_error("message error");
     }
diff --git a/server/red_worker.h b/server/red_worker.h
index 604437b..15d5f82 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -77,6 +77,8 @@ enum {
     RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC,
     RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC,
     RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
+    /* suspend/windows resolution change command */
+    RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC,
 };
 
 typedef uint32_t RedWorkerMessage;
diff --git a/server/spice-server.syms b/server/spice-server.syms
index 28e6025..b908d85 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -79,6 +79,7 @@ global:
     spice_qxl_destroy_primary_surface_async;
     spice_qxl_create_primary_surface_async;
     spice_qxl_destroy_surface_async;
+    spice_qxl_flush_surfaces_async;
 } SPICE_SERVER_0.8.1;
 
 SPICE_SERVER_0.10.0 {
diff --git a/server/spice.h b/server/spice.h
index 89872ea..549dd0c 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -153,6 +153,8 @@ void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t sur
 void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t surface_id,
                                 QXLDevSurfaceCreate *surface, uint64_t cookie);
 void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie);
+/* suspend and resolution change on windows drivers */
+void spice_qxl_flush_surfaces_async(QXLInstance *instance, uint64_t cookie);
 
 typedef struct QXLDrawArea {
     uint8_t *buf;
commit b26f0532c170068e91e4946592eab2fd9d6cbae5
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 6 19:31:57 2011 +0200

    server: add QXLInterface::update_area_complete callback
    
    when update_area_async is called update_area_complete will be called with
    the surfaces dirty rectangle list.

diff --git a/server/red_worker.c b/server/red_worker.c
index ec895ec..9b5d9cd 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9426,12 +9426,39 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
     red_unref_channel(channel);
 }
 
+static void surface_dirty_region_to_rects(RedSurface *surface,
+                                          QXLRect *qxl_dirty_rects,
+                                          uint32_t num_dirty_rects,
+                                          int clear_dirty_region)
+{
+    QRegion *surface_dirty_region;
+    SpiceRect *dirty_rects;
+    int i;
+
+    surface_dirty_region = &surface->draw_dirty_region;
+    dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
+    region_ret_rects(surface_dirty_region, dirty_rects, num_dirty_rects);
+    if (clear_dirty_region) {
+        region_clear(surface_dirty_region);
+    }
+    for (i = 0; i < num_dirty_rects; i++) {
+        qxl_dirty_rects[i].top    = dirty_rects[i].top;
+        qxl_dirty_rects[i].left   = dirty_rects[i].left;
+        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
+        qxl_dirty_rects[i].right  = dirty_rects[i].right;
+    }
+    free(dirty_rects);
+}
+
 static inline void handle_dev_update_async(RedWorker *worker)
 {
     QXLRect qxl_rect;
     SpiceRect rect;
     uint32_t surface_id;
     uint32_t clear_dirty_region;
+    QXLRect *qxl_dirty_rects;
+    uint32_t num_dirty_rects;
+    RedSurface *surface;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
     receive_data(worker->channel, &qxl_rect, sizeof(QXLRect));
@@ -9444,6 +9471,20 @@ static inline void handle_dev_update_async(RedWorker *worker)
 
     validate_surface(worker, surface_id);
     red_update_area(worker, &rect, surface_id);
+    if (!worker->qxl->st->qif->update_area_complete) {
+        return;
+    }
+    surface = &worker->surfaces[surface_id];
+    num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
+    if (num_dirty_rects == 0) {
+        return;
+    }
+    qxl_dirty_rects = spice_new0(QXLRect, num_dirty_rects);
+    surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
+                                  clear_dirty_region);
+    worker->qxl->st->qif->update_area_complete(worker->qxl, surface_id,
+                                          qxl_dirty_rects, num_dirty_rects);
+    free(qxl_dirty_rects);
 }
 
 static inline void handle_dev_update(RedWorker *worker)
@@ -9451,12 +9492,10 @@ static inline void handle_dev_update(RedWorker *worker)
     const QXLRect *qxl_rect;
     SpiceRect *rect = spice_new0(SpiceRect, 1);
     QXLRect *qxl_dirty_rects;
-    SpiceRect *dirty_rects;
     RedSurface *surface;
     uint32_t num_dirty_rects;
     uint32_t surface_id;
     uint32_t clear_dirty_region;
-    int i;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
     receive_data(worker->channel, &qxl_rect, sizeof(QXLRect *));
@@ -9464,7 +9503,7 @@ static inline void handle_dev_update(RedWorker *worker)
     receive_data(worker->channel, &num_dirty_rects, sizeof(uint32_t));
     receive_data(worker->channel, &clear_dirty_region, sizeof(uint32_t));
 
-    dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
+    surface = &worker->surfaces[surface_id];
     red_get_rect_ptr(rect, qxl_rect);
     flush_display_commands(worker);
 
@@ -9474,19 +9513,8 @@ static inline void handle_dev_update(RedWorker *worker)
     red_update_area(worker, rect, surface_id);
     free(rect);
 
-    surface = &worker->surfaces[surface_id];
-    region_ret_rects(&surface->draw_dirty_region, dirty_rects, num_dirty_rects);
-
-    if (clear_dirty_region) {
-        region_clear(&surface->draw_dirty_region);
-    }
-    for (i = 0; i < num_dirty_rects; i++) {
-        qxl_dirty_rects[i].top    = dirty_rects[i].top;
-        qxl_dirty_rects[i].left   = dirty_rects[i].left;
-        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
-        qxl_dirty_rects[i].right  = dirty_rects[i].right;
-    }
-    free(dirty_rects);
+    surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
+                                  clear_dirty_region);
 }
 
 static inline void handle_dev_add_memslot(RedWorker *worker)
diff --git a/server/spice.h b/server/spice.h
index c7f0a6e..89872ea 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -223,6 +223,9 @@ struct QXLInterface {
     void (*notify_update)(QXLInstance *qin, uint32_t update_id);
     int (*flush_resources)(QXLInstance *qin);
     void (*async_complete)(QXLInstance *qin, uint64_t cookie);
+    void (*update_area_complete)(QXLInstance *qin, uint32_t surface_id,
+                                 struct QXLRect *updated_rects,
+                                 uint32_t num_updated_rects);
 };
 
 struct QXLInstance {
commit f300de20d9fd7731881ab99c87226fa44a80695b
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Jul 19 10:50:30 2011 +0300

    server/red_worker: handle_dev_input: reuse write_ready introduced for async

diff --git a/server/red_worker.c b/server/red_worker.c
index f29a420..ec895ec 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9708,6 +9708,10 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE:
     case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
+    case RED_WORKER_MESSAGE_RESET_CURSOR:
+    case RED_WORKER_MESSAGE_RESET_IMAGE_CACHE:
+    case RED_WORKER_MESSAGE_STOP:
+    case RED_WORKER_MESSAGE_LOADVM_COMMANDS:
         write_ready = 1;
     default:
         break;
@@ -9740,13 +9744,9 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         break;
     case RED_WORKER_MESSAGE_RESET_CURSOR:
         red_cursor_reset(worker);
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
         break;
     case RED_WORKER_MESSAGE_RESET_IMAGE_CACHE:
         image_cache_reset(&worker->image_cache);
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
         break;
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
@@ -9781,8 +9781,6 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_STOP: {
         red_printf("stop");
         handle_dev_stop(worker);
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
         break;
     }
     case RED_WORKER_MESSAGE_START:
@@ -9908,8 +9906,6 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
             }
             count--;
         }
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
         break;
     }
     default:
commit 096f49afbf4e83ccee80f58479b3ff05bd355660
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 6 02:12:19 2011 +0200

    server: add async io support
    
    The new _ASYNC io's in qxl_dev listed at the end get six new api
    functions, and an additional callback function "async_complete". When
    the async version of a specific io is used, completion is notified by
    calling async_complete, and no READY message is written or expected by
    the dispatcher.
    
    update_area has been changed to push QXLRects to the worker thread, where
    the conversion to SpiceRect takes place.
    
    A cookie has been added to each async call to QXLWorker, and is passed back via
    async_complete.
    
    Added api:
    
    QXLWorker:
        update_area_async
        add_memslot_async
        destroy_surfaces_async
        destroy_primary_surface_async
        create_primary_surface_async
        destroy_surface_wait_async
    
    QXLInterface:
        async_complete

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index aa1990e..7f3efe8 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -43,7 +43,6 @@ static int num_active_workers = 0;
 
 //volatile
 
-typedef struct RedDispatcher RedDispatcher;
 struct RedDispatcher {
     QXLWorker base;
     QXLInstance *qxl;
@@ -55,6 +54,9 @@ struct RedDispatcher {
     int y_res;
     int use_hardware_cursor;
     RedDispatcher *next;
+    RedWorkerMessage async_message;
+    pthread_mutex_t  async_lock;
+    QXLDevSurfaceCreate *surface_create;
 };
 
 typedef struct RedWorkeState {
@@ -214,30 +216,49 @@ static void red_dispatcher_update_area(RedDispatcher *dispatcher, uint32_t surfa
                                    uint32_t num_dirty_rects, uint32_t clear_dirty_region)
 {
     RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE;
-    SpiceRect *dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
-    SpiceRect *area = spice_new0(SpiceRect, 1);
-    int i;
-
-    red_get_rect_ptr(area, qxl_area);
 
     write_message(dispatcher->channel, &message);
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
-    send_data(dispatcher->channel, &area, sizeof(SpiceRect *));
-    send_data(dispatcher->channel, &dirty_rects, sizeof(SpiceRect *));
+    send_data(dispatcher->channel, &qxl_area, sizeof(QXLRect *));
+    send_data(dispatcher->channel, &qxl_dirty_rects, sizeof(QXLRect *));
     send_data(dispatcher->channel, &num_dirty_rects, sizeof(uint32_t));
     send_data(dispatcher->channel, &clear_dirty_region, sizeof(uint32_t));
     read_message(dispatcher->channel, &message);
     ASSERT(message == RED_WORKER_MESSAGE_READY);
+}
 
-    for (i = 0; i < num_dirty_rects; i++) {
-        qxl_dirty_rects[i].top    = dirty_rects[i].top;
-        qxl_dirty_rects[i].left   = dirty_rects[i].left;
-        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
-        qxl_dirty_rects[i].right  = dirty_rects[i].right;
+static RedWorkerMessage red_dispatcher_async_start(RedDispatcher *dispatcher,
+                                                   RedWorkerMessage message)
+{
+    pthread_mutex_lock(&dispatcher->async_lock);
+    if (dispatcher->async_message != RED_WORKER_MESSAGE_NOP) {
+        red_printf("error: async clash. second async ignored");
+        pthread_mutex_unlock(&dispatcher->async_lock);
+        return RED_WORKER_MESSAGE_NOP;
     }
+    dispatcher->async_message = message;
+    pthread_mutex_unlock(&dispatcher->async_lock);
+    return message;
+}
+
+static void red_dispatcher_update_area_async(RedDispatcher *dispatcher,
+                                         uint32_t surface_id,
+                                         QXLRect *qxl_area,
+                                         uint32_t clear_dirty_region,
+                                         uint64_t cookie)
+{
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                          RED_WORKER_MESSAGE_UPDATE_ASYNC);
 
-    free(dirty_rects);
-    free(area);
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
+
+    write_message(dispatcher->channel, &message);
+    send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
+    send_data(dispatcher->channel, qxl_area, sizeof(QXLRect));
+    send_data(dispatcher->channel, &clear_dirty_region, sizeof(uint32_t));
 }
 
 static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
@@ -263,6 +284,19 @@ static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slo
     red_dispatcher_add_memslot((RedDispatcher*)qxl_worker, mem_slot);
 }
 
+static void red_dispatcher_add_memslot_async(RedDispatcher *dispatcher, QXLDevMemSlot *mem_slot, uint64_t cookie)
+{
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                          RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC);
+
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
+    write_message(dispatcher->channel, &message);
+    send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    send_data(dispatcher->channel, mem_slot, sizeof(QXLDevMemSlot));
+}
+
 static void red_dispatcher_del_memslot(RedDispatcher *dispatcher, uint32_t slot_group_id, uint32_t slot_id)
 {
     RedWorkerMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT;
@@ -291,15 +325,20 @@ static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
     red_dispatcher_destroy_surfaces((RedDispatcher*)qxl_worker);
 }
 
-static void red_dispatcher_destroy_primary(RedDispatcher *dispatcher, uint32_t surface_id)
+static void red_dispatcher_destroy_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie)
 {
-    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                      RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC);
 
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
     write_message(dispatcher->channel, &message);
-    send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
-    read_message(dispatcher->channel, &message);
-    ASSERT(message == RED_WORKER_MESSAGE_READY);
+    send_data(dispatcher->channel, &cookie, sizeof(cookie));
+}
 
+static void red_dispatcher_destroy_primary_surface_complete(RedDispatcher *dispatcher)
+{
     dispatcher->x_res = 0;
     dispatcher->y_res = 0;
     dispatcher->use_hardware_cursor = FALSE;
@@ -308,34 +347,86 @@ static void red_dispatcher_destroy_primary(RedDispatcher *dispatcher, uint32_t s
     update_client_mouse_allowed();
 }
 
-static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id)
+static void
+red_dispatcher_destroy_primary_surface(RedDispatcher *dispatcher,
+                                       uint32_t surface_id, int async, uint64_t cookie)
 {
-    red_dispatcher_destroy_primary((RedDispatcher*)qxl_worker, surface_id);
+    RedWorkerMessage message;
+
+    if (async) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
+    }
+
+    write_message(dispatcher->channel, &message);
+    if (async) {
+        send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    }
+    send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
+    if (!async) {
+        read_message(dispatcher->channel, &message);
+        ASSERT(message == RED_WORKER_MESSAGE_READY);
+        red_dispatcher_destroy_primary_surface_complete(dispatcher);
+    }
 }
 
-static void red_dispatcher_create_primary(RedDispatcher *dispatcher, uint32_t surface_id,
-                                      QXLDevSurfaceCreate *surface)
+static void qxl_worker_destroy_primary_surface(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    red_dispatcher_destroy_primary_surface((RedDispatcher*)qxl_worker, surface_id, 0, 0);
+}
+
+static void red_dispatcher_create_primary_surface_complete(RedDispatcher *dispatcher)
 {
-    RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
+    QXLDevSurfaceCreate *surface = dispatcher->surface_create;
 
     dispatcher->x_res = surface->width;
     dispatcher->y_res = surface->height;
     dispatcher->use_hardware_cursor = surface->mouse_mode;
     dispatcher->primary_active = TRUE;
 
+    update_client_mouse_allowed();
+    dispatcher->surface_create = NULL;
+}
+
+static void
+red_dispatcher_create_primary_surface(RedDispatcher *dispatcher, uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface, int async, uint64_t cookie)
+{
+    RedWorkerMessage message;
+
+    if (async) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
+    }
+    dispatcher->surface_create = surface;
+
     write_message(dispatcher->channel, &message);
+    if (async) {
+        send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    }
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
     send_data(dispatcher->channel, surface, sizeof(QXLDevSurfaceCreate));
-    read_message(dispatcher->channel, &message);
-    ASSERT(message == RED_WORKER_MESSAGE_READY);
-
-    update_client_mouse_allowed();
+    if (!async) {
+        read_message(dispatcher->channel, &message);
+        ASSERT(message == RED_WORKER_MESSAGE_READY);
+        red_dispatcher_create_primary_surface_complete(dispatcher);
+    }
 }
 
-static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id,
+static void qxl_worker_create_primary_surface(QXLWorker *qxl_worker, uint32_t surface_id,
                                       QXLDevSurfaceCreate *surface)
 {
-    red_dispatcher_create_primary((RedDispatcher*)qxl_worker, surface_id, surface);
+    red_dispatcher_create_primary_surface((RedDispatcher*)qxl_worker, surface_id, surface, 0, 0);
 }
 
 static void red_dispatcher_reset_image_cache(RedDispatcher *dispatcher)
@@ -366,19 +457,36 @@ static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
     red_dispatcher_reset_cursor((RedDispatcher*)qxl_worker);
 }
 
-static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id)
+static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id,
+                                                int async, uint64_t cookie)
 {
-    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
+    RedWorkerMessage message;
+
+    if (async ) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
+    }
 
     write_message(dispatcher->channel, &message);
+    if (async) {
+        send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    }
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
+    if (async) {
+        return;
+    }
     read_message(dispatcher->channel, &message);
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
 static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
 {
-    red_dispatcher_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id);
+    red_dispatcher_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id, 0, 0);
 }
 
 static void red_dispatcher_reset_memslots(RedDispatcher *dispatcher)
@@ -607,14 +715,14 @@ void spice_qxl_destroy_surfaces(QXLInstance *instance)
 SPICE_GNUC_VISIBLE
 void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t surface_id)
 {
-    red_dispatcher_destroy_primary(instance->st->dispatcher, surface_id);
+    red_dispatcher_destroy_primary_surface(instance->st->dispatcher, surface_id, 0, 0);
 }
 
 SPICE_GNUC_VISIBLE
 void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t surface_id,
                                 QXLDevSurfaceCreate *surface)
 {
-    red_dispatcher_create_primary(instance->st->dispatcher, surface_id, surface);
+    red_dispatcher_create_primary_surface(instance->st->dispatcher, surface_id, surface, 0, 0);
 }
 
 SPICE_GNUC_VISIBLE
@@ -632,7 +740,7 @@ void spice_qxl_reset_cursor(QXLInstance *instance)
 SPICE_GNUC_VISIBLE
 void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id)
 {
-    red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id);
+    red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id, 0, 0);
 }
 
 SPICE_GNUC_VISIBLE
@@ -641,6 +749,71 @@ void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext,
     red_dispatcher_loadvm_commands(instance->st->dispatcher, ext, count);
 }
 
+SPICE_GNUC_VISIBLE
+void spice_qxl_update_area_async(QXLInstance *instance, uint32_t surface_id, QXLRect *qxl_area,
+                                 uint32_t clear_dirty_region, uint64_t cookie)
+{
+    red_dispatcher_update_area_async(instance->st->dispatcher, surface_id, qxl_area,
+                                     clear_dirty_region, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_add_memslot_async(QXLInstance *instance, QXLDevMemSlot *slot, uint64_t cookie)
+{
+    red_dispatcher_add_memslot_async(instance->st->dispatcher, slot, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_surfaces_async(QXLInstance *instance, uint64_t cookie)
+{
+    red_dispatcher_destroy_surfaces_async(instance->st->dispatcher, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie)
+{
+    red_dispatcher_destroy_primary_surface(instance->st->dispatcher, surface_id, 1, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t surface_id,
+                                QXLDevSurfaceCreate *surface, uint64_t cookie)
+{
+    red_dispatcher_create_primary_surface(instance->st->dispatcher, surface_id, surface, 1, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie)
+{
+    red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id, 1, cookie);
+}
+
+void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t cookie)
+{
+    pthread_mutex_lock(&dispatcher->async_lock);
+    switch (dispatcher->async_message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
+        red_dispatcher_create_primary_surface_complete(dispatcher);
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
+        red_dispatcher_destroy_primary_surface_complete(dispatcher);
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
+        break;
+    default:
+        red_printf("unexpected message");
+    }
+    dispatcher->async_message = RED_WORKER_MESSAGE_NOP;
+    pthread_mutex_unlock(&dispatcher->async_lock);
+    dispatcher->qxl->st->qif->async_complete(dispatcher->qxl, cookie);
+}
+
 RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
 {
     RedDispatcher *dispatcher;
@@ -673,6 +846,8 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     init_data.num_renderers = num_renderers;
     memcpy(init_data.renderers, renderers, sizeof(init_data.renderers));
 
+    dispatcher->async_message = RED_WORKER_MESSAGE_NOP;
+    pthread_mutex_init(&dispatcher->async_lock, NULL);
     init_data.image_compression = image_compression;
     init_data.jpeg_state = jpeg_state;
     init_data.zlib_glz_state = zlib_glz_state;
@@ -689,8 +864,8 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     dispatcher->base.del_memslot = qxl_worker_del_memslot;
     dispatcher->base.reset_memslots = qxl_worker_reset_memslots;
     dispatcher->base.destroy_surfaces = qxl_worker_destroy_surfaces;
-    dispatcher->base.create_primary_surface = qxl_worker_create_primary;
-    dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary;
+    dispatcher->base.create_primary_surface = qxl_worker_create_primary_surface;
+    dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary_surface;
 
     dispatcher->base.reset_image_cache = qxl_worker_reset_image_cache;
     dispatcher->base.reset_cursor = qxl_worker_reset_cursor;
@@ -705,6 +880,7 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     init_data.num_memslots_groups = init_info.num_memslots_groups;
     init_data.internal_groupslot_id = init_info.internal_groupslot_id;
     init_data.n_surfaces = init_info.n_surfaces;
+    init_data.dispatcher = dispatcher;
 
     num_active_workers = 1;
 
@@ -745,4 +921,3 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     dispatchers = dispatcher;
     return dispatcher;
 }
-
diff --git a/server/red_dispatcher.h b/server/red_dispatcher.h
index 3f3c1ae..fa347f1 100644
--- a/server/red_dispatcher.h
+++ b/server/red_dispatcher.h
@@ -18,7 +18,6 @@
 #ifndef _H_RED_DISPATCHER
 #define _H_RED_DISPATCHER
 
-
 struct RedDispatcher *red_dispatcher_init(QXLInstance *qxl);
 
 void red_dispatcher_set_mm_time(uint32_t);
@@ -29,5 +28,7 @@ int red_dispatcher_count(void);
 int red_dispatcher_add_renderer(const char *name);
 uint32_t red_dispatcher_qxl_ram_size(void);
 int red_dispatcher_qxl_count(void);
+void red_dispatcher_async_complete(struct RedDispatcher*, uint64_t);
+
 #endif
 
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index 258a541..7737c04 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -148,7 +148,7 @@ static void red_get_point16_ptr(SpicePoint16 *red, QXLPoint16 *qxl)
     red->y = qxl->y;
 }
 
-void red_get_rect_ptr(SpiceRect *red, QXLRect *qxl)
+void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl)
 {
     red->top    = qxl->top;
     red->left   = qxl->left;
diff --git a/server/red_parse_qxl.h b/server/red_parse_qxl.h
index 5de0325..a713dcf 100644
--- a/server/red_parse_qxl.h
+++ b/server/red_parse_qxl.h
@@ -110,7 +110,7 @@ typedef struct RedCursorCmd {
     uint8_t *device_data;
 } RedCursorCmd;
 
-void red_get_rect_ptr(SpiceRect *red, QXLRect *qxl);
+void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl);
 
 void red_get_drawable(RedMemSlotInfo *slots, int group_id,
                       RedDrawable *red, QXLPHYSICAL addr, uint32_t flags);
diff --git a/server/red_worker.c b/server/red_worker.c
index 2349ac5..f29a420 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -61,6 +61,7 @@
 #include "generated_marshallers.h"
 #include "zlib_encoder.h"
 #include "red_channel.h"
+#include "red_dispatcher.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -805,6 +806,7 @@ typedef struct RedWorker {
     DisplayChannel *display_channel;
     CursorChannel *cursor_channel;
     QXLInstance *qxl;
+    RedDispatcher *dispatcher;
     int id;
     int channel;
     int running;
@@ -9424,28 +9426,53 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
     red_unref_channel(channel);
 }
 
+static inline void handle_dev_update_async(RedWorker *worker)
+{
+    QXLRect qxl_rect;
+    SpiceRect rect;
+    uint32_t surface_id;
+    uint32_t clear_dirty_region;
+
+    receive_data(worker->channel, &surface_id, sizeof(uint32_t));
+    receive_data(worker->channel, &qxl_rect, sizeof(QXLRect));
+    receive_data(worker->channel, &clear_dirty_region, sizeof(uint32_t));
+
+    red_get_rect_ptr(&rect, &qxl_rect);
+    flush_display_commands(worker);
+
+    ASSERT(worker->running);
+
+    validate_surface(worker, surface_id);
+    red_update_area(worker, &rect, surface_id);
+}
+
 static inline void handle_dev_update(RedWorker *worker)
 {
-    RedWorkerMessage message;
-    const SpiceRect *rect;
+    const QXLRect *qxl_rect;
+    SpiceRect *rect = spice_new0(SpiceRect, 1);
+    QXLRect *qxl_dirty_rects;
     SpiceRect *dirty_rects;
     RedSurface *surface;
     uint32_t num_dirty_rects;
     uint32_t surface_id;
     uint32_t clear_dirty_region;
+    int i;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
-    receive_data(worker->channel, &rect, sizeof(SpiceRect *));
-    receive_data(worker->channel, &dirty_rects, sizeof(SpiceRect *));
+    receive_data(worker->channel, &qxl_rect, sizeof(QXLRect *));
+    receive_data(worker->channel, &qxl_dirty_rects, sizeof(QXLRect *));
     receive_data(worker->channel, &num_dirty_rects, sizeof(uint32_t));
     receive_data(worker->channel, &clear_dirty_region, sizeof(uint32_t));
 
+    dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
+    red_get_rect_ptr(rect, qxl_rect);
     flush_display_commands(worker);
 
     ASSERT(worker->running);
 
     validate_surface(worker, surface_id);
     red_update_area(worker, rect, surface_id);
+    free(rect);
 
     surface = &worker->surfaces[surface_id];
     region_ret_rects(&surface->draw_dirty_region, dirty_rects, num_dirty_rects);
@@ -9453,15 +9480,17 @@ static inline void handle_dev_update(RedWorker *worker)
     if (clear_dirty_region) {
         region_clear(&surface->draw_dirty_region);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
+    for (i = 0; i < num_dirty_rects; i++) {
+        qxl_dirty_rects[i].top    = dirty_rects[i].top;
+        qxl_dirty_rects[i].left   = dirty_rects[i].left;
+        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
+        qxl_dirty_rects[i].right  = dirty_rects[i].right;
+    }
+    free(dirty_rects);
 }
 
-
 static inline void handle_dev_add_memslot(RedWorker *worker)
 {
-    RedWorkerMessage message;
     QXLDevMemSlot dev_slot;
 
     receive_data(worker->channel, &dev_slot, sizeof(QXLDevMemSlot));
@@ -9469,9 +9498,6 @@ static inline void handle_dev_add_memslot(RedWorker *worker)
     red_memslot_info_add_slot(&worker->mem_slots, dev_slot.slot_group_id, dev_slot.slot_id,
                               dev_slot.addr_delta, dev_slot.virt_start, dev_slot.virt_end,
                               dev_slot.generation);
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_del_memslot(RedWorker *worker)
@@ -9507,7 +9533,6 @@ static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
 
 static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
@@ -9519,9 +9544,6 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
     if (worker->surfaces[0].context.canvas) {
         destroy_surface_wait(worker, 0);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void red_cursor_reset(RedWorker *worker)
@@ -9549,7 +9571,6 @@ static inline void red_cursor_reset(RedWorker *worker)
 static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 {
     int i;
-    RedWorkerMessage message;
 
     flush_all_qxl_commands(worker);
     //to handle better
@@ -9572,14 +9593,10 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
     red_display_clear_glz_drawables(worker->display_channel);
 
     red_cursor_reset(worker);
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_create_primary_surface(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
     QXLDevSurfaceCreate surface;
     uint8_t *line_0;
@@ -9609,14 +9626,10 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     if (worker->cursor_channel) {
         red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
@@ -9632,22 +9645,78 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     ASSERT(!worker->surfaces[surface_id].context.canvas);
 
     red_cursor_reset(worker);
+}
 
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
+static void handle_dev_stop(RedWorker *worker)
+{
+    int x;
+
+    ASSERT(worker->running);
+    worker->running = FALSE;
+    red_display_clear_glz_drawables(worker->display_channel);
+    for (x = 0; x < NUM_SURFACES; ++x) {
+        if (worker->surfaces[x].context.canvas) {
+            red_current_flush(worker, x);
+        }
+    }
+    red_wait_outgoing_item((RedChannel *)worker->display_channel);
+    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+}
+
+static void handle_dev_start(RedWorker *worker)
+{
+    RedChannel *cursor_red_channel = &worker->cursor_channel->common.base;
+    RedChannel *display_red_channel = &worker->display_channel->common.base;
+
+    ASSERT(!worker->running);
+    if (worker->cursor_channel) {
+        cursor_red_channel->migrate = FALSE;
+    }
+    if (worker->display_channel) {
+        display_red_channel->migrate = FALSE;
+    }
+    worker->running = TRUE;
 }
 
 static void handle_dev_input(EventListener *listener, uint32_t events)
 {
     RedWorker *worker = SPICE_CONTAINEROF(listener, RedWorker, dev_listener);
     RedWorkerMessage message;
-    RedChannel *cursor_red_channel = &worker->cursor_channel->common.base;
     RedChannel *display_red_channel = &worker->display_channel->common.base;
     int ring_is_empty;
+    int call_async_complete = 0;
+    int write_ready = 0;
+    uint64_t cookie;
 
     read_message(worker->channel, &message);
 
+    /* for async messages we do the common work in the handler, and
+     * send a ready or call async_complete from here, hence the added switch. */
+    switch (message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
+        call_async_complete = 1;
+        receive_data(worker->channel, &cookie, sizeof(cookie));
+        break;
+    case RED_WORKER_MESSAGE_UPDATE:
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES:
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE:
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
+        write_ready = 1;
+    default:
+        break;
+    }
+
     switch (message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+        handle_dev_update_async(worker);
+        break;
     case RED_WORKER_MESSAGE_UPDATE:
         handle_dev_update(worker);
         break;
@@ -9679,15 +9748,19 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         message = RED_WORKER_MESSAGE_READY;
         write_message(worker->channel, &message);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
         handle_dev_destroy_surface_wait(worker);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACES:
         handle_dev_destroy_surfaces(worker);
         break;
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE:
         handle_dev_create_primary_surface(worker);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE:
         handle_dev_destroy_primary_surface(worker);
         break;
@@ -9706,33 +9779,15 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         red_disconnect_display((RedChannel *)worker->display_channel);
         break;
     case RED_WORKER_MESSAGE_STOP: {
-        int x;
-
         red_printf("stop");
-        ASSERT(worker->running);
-        worker->running = FALSE;
-        red_display_clear_glz_drawables(worker->display_channel);
-        for (x = 0; x < NUM_SURFACES; ++x) {
-            if (worker->surfaces[x].context.canvas) {
-                red_current_flush(worker, x);
-            }
-        }
-        red_wait_outgoing_item((RedChannel *)worker->display_channel);
-        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+        handle_dev_stop(worker);
         message = RED_WORKER_MESSAGE_READY;
         write_message(worker->channel, &message);
         break;
     }
     case RED_WORKER_MESSAGE_START:
         red_printf("start");
-        ASSERT(!worker->running);
-        if (worker->cursor_channel) {
-            cursor_red_channel->migrate = FALSE;
-        }
-        if (worker->display_channel) {
-            display_red_channel->migrate = FALSE;
-        }
-        worker->running = TRUE;
+        handle_dev_start(worker);
         break;
     case RED_WORKER_MESSAGE_DISPLAY_MIGRATE:
         red_printf("migrate");
@@ -9814,6 +9869,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         receive_data(worker->channel, &worker->mouse_mode, sizeof(uint32_t));
         red_printf("mouse mode %u", worker->mouse_mode);
         break;
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
     case RED_WORKER_MESSAGE_ADD_MEMSLOT:
         handle_dev_add_memslot(worker);
         break;
@@ -9859,6 +9915,13 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     default:
         red_error("message error");
     }
+    if (call_async_complete) {
+        red_dispatcher_async_complete(worker->dispatcher, cookie);
+    }
+    if (write_ready) {
+        message = RED_WORKER_MESSAGE_READY;
+        write_message(worker->channel, &message);
+    }
 }
 
 static void handle_dev_free(EventListener *ctx)
@@ -9875,6 +9938,7 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
     ASSERT(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
 
     memset(worker, 0, sizeof(RedWorker));
+    worker->dispatcher = init_data->dispatcher;
     worker->qxl = init_data->qxl;
     worker->id = init_data->id;
     worker->channel = init_data->channel;
diff --git a/server/red_worker.h b/server/red_worker.h
index b4e2ed2..604437b 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -70,6 +70,13 @@ enum {
     RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
     RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
     RED_WORKER_MESSAGE_LOADVM_COMMANDS,
+    /* async commands */
+    RED_WORKER_MESSAGE_UPDATE_ASYNC,
+    RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC,
+    RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
 };
 
 typedef uint32_t RedWorkerMessage;
@@ -83,6 +90,8 @@ enum {
     RED_RENDERER_OGL_PIXMAP,
 };
 
+typedef struct RedDispatcher RedDispatcher;
+
 typedef struct WorkerInitData {
     struct QXLInstance *qxl;
     int id;
@@ -100,6 +109,7 @@ typedef struct WorkerInitData {
     uint8_t memslot_id_bits;
     uint8_t internal_groupslot_id;
     uint32_t n_surfaces;
+    RedDispatcher *dispatcher;
 } WorkerInitData;
 
 void *red_worker_main(void *arg);
diff --git a/server/spice-server.syms b/server/spice-server.syms
index 4e120ee..28e6025 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -73,6 +73,12 @@ global:
     spice_qxl_reset_cursor;
     spice_qxl_destroy_surface_wait;
     spice_qxl_loadvm_commands;
+    spice_qxl_update_area_async;
+    spice_qxl_add_memslot_async;
+    spice_qxl_destroy_surfaces_async;
+    spice_qxl_destroy_primary_surface_async;
+    spice_qxl_create_primary_surface_async;
+    spice_qxl_destroy_surface_async;
 } SPICE_SERVER_0.8.1;
 
 SPICE_SERVER_0.10.0 {
diff --git a/server/spice.h b/server/spice.h
index 0b82bb7..c7f0a6e 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -20,6 +20,7 @@
 
 #include <stdint.h>
 #include <sys/socket.h>
+#include <spice/qxl_dev.h>
 
 #define SPICE_SERVER_VERSION 0x000900 /* release 0.9.0 */
 
@@ -143,6 +144,15 @@ void spice_qxl_reset_image_cache(QXLInstance *instance);
 void spice_qxl_reset_cursor(QXLInstance *instance);
 void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id);
 void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext, uint32_t count);
+/* async versions of commands. when complete spice calls async_complete */
+void spice_qxl_update_area_async(QXLInstance *instance, uint32_t surface_id, QXLRect *qxl_area,
+                                 uint32_t clear_dirty_region, uint64_t cookie);
+void spice_qxl_add_memslot_async(QXLInstance *instance, QXLDevMemSlot *slot, uint64_t cookie);
+void spice_qxl_destroy_surfaces_async(QXLInstance *instance, uint64_t cookie);
+void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie);
+void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t surface_id,
+                                QXLDevSurfaceCreate *surface, uint64_t cookie);
+void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie);
 
 typedef struct QXLDrawArea {
     uint8_t *buf;
@@ -212,6 +222,7 @@ struct QXLInterface {
     int (*req_cursor_notification)(QXLInstance *qin);
     void (*notify_update)(QXLInstance *qin, uint32_t update_id);
     int (*flush_resources)(QXLInstance *qin);
+    void (*async_complete)(QXLInstance *qin, uint64_t cookie);
 };
 
 struct QXLInstance {
commit 4db8f5efdda91acf3b94c6c104d48438f6f4e85d
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 14 13:12:21 2011 +0300

    bump required spice-protocol to 0.8.1 for qxl_dev async and s3 updates

diff --git a/configure.ac b/configure.ac
index 3268df6..cb0ca99 100644
--- a/configure.ac
+++ b/configure.ac
@@ -132,7 +132,7 @@ AM_CONDITIONAL(SUPPORT_CLIENT, test "x$enable_client" = "xyes")
 dnl =========================================================================
 dnl Check deps
 
-PKG_CHECK_MODULES(PROTOCOL, spice-protocol >= 0.6.0)
+PKG_CHECK_MODULES(PROTOCOL, spice-protocol >= 0.8.1)
 AC_SUBST(PROTOCOL_CFLAGS)
 
 AC_CHECK_LIBM
commit c04d60631e91ce9f61d417fb017d94d9a1e78dc1
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Jul 19 16:05:04 2011 +0300

    server: api: add spice_qxl_* calls based on QXLWorker contents
    
    For each callback in QXLWorker, for example QXLWorker::update_area, add
    a direct call named spice_qxl_update_area.
    
    This will (a) remove the pointless indirection and (b) make shared
    library versioning alot easier as we'll get new linker symbols which
    we can tag with the version they appeared in the shared library.

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 56446ab..aa1990e 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -209,11 +209,10 @@ static void update_client_mouse_allowed(void)
     }
 }
 
-static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
+static void red_dispatcher_update_area(RedDispatcher *dispatcher, uint32_t surface_id,
                                    QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
                                    uint32_t num_dirty_rects, uint32_t clear_dirty_region)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE;
     SpiceRect *dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
     SpiceRect *area = spice_new0(SpiceRect, 1);
@@ -241,9 +240,16 @@ static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
     free(area);
 }
 
-static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
+static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
+                                   QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
+                                   uint32_t num_dirty_rects, uint32_t clear_dirty_region)
+{
+    red_dispatcher_update_area((RedDispatcher*)qxl_worker, surface_id, qxl_area,
+                               qxl_dirty_rects, num_dirty_rects, clear_dirty_region);
+}
+
+static void red_dispatcher_add_memslot(RedDispatcher *dispatcher, QXLDevMemSlot *mem_slot)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT;
 
     write_message(dispatcher->channel, &message);
@@ -252,9 +258,13 @@ static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slo
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id, uint32_t slot_id)
+static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
+{
+    red_dispatcher_add_memslot((RedDispatcher*)qxl_worker, mem_slot);
+}
+
+static void red_dispatcher_del_memslot(RedDispatcher *dispatcher, uint32_t slot_group_id, uint32_t slot_id)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT;
 
     write_message(dispatcher->channel, &message);
@@ -262,9 +272,13 @@ static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id
     send_data(dispatcher->channel, &slot_id, sizeof(uint32_t));
 }
 
-static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
+static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id, uint32_t slot_id)
+{
+    red_dispatcher_del_memslot((RedDispatcher*)qxl_worker, slot_group_id, slot_id);
+}
+
+static void red_dispatcher_destroy_surfaces(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES;
 
     write_message(dispatcher->channel, &message);
@@ -272,9 +286,13 @@ static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id)
+static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
+{
+    red_dispatcher_destroy_surfaces((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_destroy_primary(RedDispatcher *dispatcher, uint32_t surface_id)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
 
     write_message(dispatcher->channel, &message);
@@ -290,10 +308,14 @@ static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_i
     update_client_mouse_allowed();
 }
 
-static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id,
+static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    red_dispatcher_destroy_primary((RedDispatcher*)qxl_worker, surface_id);
+}
+
+static void red_dispatcher_create_primary(RedDispatcher *dispatcher, uint32_t surface_id,
                                       QXLDevSurfaceCreate *surface)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
 
     dispatcher->x_res = surface->width;
@@ -310,9 +332,14 @@ static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id
     update_client_mouse_allowed();
 }
 
-static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
+static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface)
+{
+    red_dispatcher_create_primary((RedDispatcher*)qxl_worker, surface_id, surface);
+}
+
+static void red_dispatcher_reset_image_cache(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_IMAGE_CACHE;
 
     write_message(dispatcher->channel, &message);
@@ -320,9 +347,13 @@ static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
+static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
+{
+    red_dispatcher_reset_image_cache((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_reset_cursor(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_CURSOR;
 
     write_message(dispatcher->channel, &message);
@@ -330,9 +361,13 @@ static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
+static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
+{
+    red_dispatcher_reset_cursor((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
 
     write_message(dispatcher->channel, &message);
@@ -341,18 +376,25 @@ static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surf
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
+static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    red_dispatcher_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id);
+}
+
+static void red_dispatcher_reset_memslots(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_MEMSLOTS;
 
     write_message(dispatcher->channel, &message);
 }
 
-static void qxl_worker_wakeup(QXLWorker *qxl_worker)
+static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    red_dispatcher_reset_memslots((RedDispatcher*)qxl_worker);
+}
 
+static void red_dispatcher_wakeup(RedDispatcher *dispatcher)
+{
     if (!test_bit(RED_WORKER_PENDING_WAKEUP, dispatcher->pending)) {
         RedWorkerMessage message = RED_WORKER_MESSAGE_WAKEUP;
         set_bit(RED_WORKER_PENDING_WAKEUP, &dispatcher->pending);
@@ -360,9 +402,13 @@ static void qxl_worker_wakeup(QXLWorker *qxl_worker)
     }
 }
 
-static void qxl_worker_oom(QXLWorker *qxl_worker)
+static void qxl_worker_wakeup(QXLWorker *qxl_worker)
+{
+    red_dispatcher_wakeup((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_oom(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     if (!test_bit(RED_WORKER_PENDING_OOM, dispatcher->pending)) {
         RedWorkerMessage message = RED_WORKER_MESSAGE_OOM;
         set_bit(RED_WORKER_PENDING_OOM, &dispatcher->pending);
@@ -370,17 +416,25 @@ static void qxl_worker_oom(QXLWorker *qxl_worker)
     }
 }
 
-static void qxl_worker_start(QXLWorker *qxl_worker)
+static void qxl_worker_oom(QXLWorker *qxl_worker)
+{
+    red_dispatcher_oom((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_start(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_START;
 
     write_message(dispatcher->channel, &message);
 }
 
-static void qxl_worker_stop(QXLWorker *qxl_worker)
+static void qxl_worker_start(QXLWorker *qxl_worker)
+{
+    red_dispatcher_start((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_stop(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_STOP;
 
     write_message(dispatcher->channel, &message);
@@ -388,11 +442,15 @@ static void qxl_worker_stop(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
-                                       struct QXLCommandExt *ext,
-                                       uint32_t count)
+static void qxl_worker_stop(QXLWorker *qxl_worker)
+{
+    red_dispatcher_stop((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_loadvm_commands(RedDispatcher *dispatcher,
+                                           struct QXLCommandExt *ext,
+                                           uint32_t count)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_LOADVM_COMMANDS;
 
     red_printf("");
@@ -403,6 +461,13 @@ static void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
+static void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
+                                       struct QXLCommandExt *ext,
+                                       uint32_t count)
+{
+    red_dispatcher_loadvm_commands((RedDispatcher*)qxl_worker, ext, count);
+}
+
 void red_dispatcher_set_mm_time(uint32_t mm_time)
 {
     RedDispatcher *now = dispatchers;
@@ -482,6 +547,100 @@ uint32_t red_dispatcher_qxl_ram_size(void)
     return qxl_info.qxl_ram_size;
 }
 
+SPICE_GNUC_VISIBLE
+void spice_qxl_wakeup(QXLInstance *instance)
+{
+    red_dispatcher_wakeup(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_oom(QXLInstance *instance)
+{
+    red_dispatcher_oom(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_start(QXLInstance *instance)
+{
+    red_dispatcher_start(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_stop(QXLInstance *instance)
+{
+    red_dispatcher_stop(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_update_area(QXLInstance *instance, uint32_t surface_id,
+                    struct QXLRect *area, struct QXLRect *dirty_rects,
+                    uint32_t num_dirty_rects, uint32_t clear_dirty_region)
+{
+    red_dispatcher_update_area(instance->st->dispatcher, surface_id, area, dirty_rects,
+                               num_dirty_rects, clear_dirty_region);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_add_memslot(QXLInstance *instance, QXLDevMemSlot *slot)
+{
+    red_dispatcher_add_memslot(instance->st->dispatcher, slot);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_del_memslot(QXLInstance *instance, uint32_t slot_group_id, uint32_t slot_id)
+{
+    red_dispatcher_del_memslot(instance->st->dispatcher, slot_group_id, slot_id);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_reset_memslots(QXLInstance *instance)
+{
+    red_dispatcher_reset_memslots(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_surfaces(QXLInstance *instance)
+{
+    red_dispatcher_destroy_surfaces(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t surface_id)
+{
+    red_dispatcher_destroy_primary(instance->st->dispatcher, surface_id);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t surface_id,
+                                QXLDevSurfaceCreate *surface)
+{
+    red_dispatcher_create_primary(instance->st->dispatcher, surface_id, surface);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_reset_image_cache(QXLInstance *instance)
+{
+    red_dispatcher_reset_image_cache(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_reset_cursor(QXLInstance *instance)
+{
+    red_dispatcher_reset_cursor(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id)
+{
+    red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext, uint32_t count)
+{
+    red_dispatcher_loadvm_commands(instance->st->dispatcher, ext, count);
+}
+
 RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
 {
     RedDispatcher *dispatcher;
diff --git a/server/spice-server.syms b/server/spice-server.syms
index da7a483..4e120ee 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -58,6 +58,21 @@ SPICE_SERVER_0.8.2 {
 global:
     spice_server_set_sasl;
     spice_server_set_sasl_appname;
+    spice_qxl_wakeup;
+    spice_qxl_oom;
+    spice_qxl_start;
+    spice_qxl_stop;
+    spice_qxl_update_area;
+    spice_qxl_add_memslot;
+    spice_qxl_del_memslot;
+    spice_qxl_reset_memslots;
+    spice_qxl_destroy_surfaces;
+    spice_qxl_destroy_primary_surface;
+    spice_qxl_create_primary_surface;
+    spice_qxl_reset_image_cache;
+    spice_qxl_reset_cursor;
+    spice_qxl_destroy_surface_wait;
+    spice_qxl_loadvm_commands;
 } SPICE_SERVER_0.8.1;
 
 SPICE_SERVER_0.10.0 {
diff --git a/server/spice.h b/server/spice.h
index f64ff41..0b82bb7 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -104,6 +104,7 @@ struct QXLRect;
 struct QXLWorker {
     uint32_t minor_version;
     uint32_t major_version;
+    /* These calls are deprecated. Pleaes use the spice_qxl_* calls instead */
     void (*wakeup)(QXLWorker *worker);
     void (*oom)(QXLWorker *worker);
     void (*start)(QXLWorker *worker);
@@ -124,6 +125,25 @@ struct QXLWorker {
     void (*loadvm_commands)(QXLWorker *worker, struct QXLCommandExt *ext, uint32_t count);
 };
 
+void spice_qxl_wakeup(QXLInstance *instance);
+void spice_qxl_oom(QXLInstance *instance);
+void spice_qxl_start(QXLInstance *instance);
+void spice_qxl_stop(QXLInstance *instance);
+void spice_qxl_update_area(QXLInstance *instance, uint32_t surface_id,
+                   struct QXLRect *area, struct QXLRect *dirty_rects,
+                   uint32_t num_dirty_rects, uint32_t clear_dirty_region);
+void spice_qxl_add_memslot(QXLInstance *instance, QXLDevMemSlot *slot);
+void spice_qxl_del_memslot(QXLInstance *instance, uint32_t slot_group_id, uint32_t slot_id);
+void spice_qxl_reset_memslots(QXLInstance *instance);
+void spice_qxl_destroy_surfaces(QXLInstance *instance);
+void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t surface_id);
+void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t surface_id,
+                               QXLDevSurfaceCreate *surface);
+void spice_qxl_reset_image_cache(QXLInstance *instance);
+void spice_qxl_reset_cursor(QXLInstance *instance);
+void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id);
+void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext, uint32_t count);
+
 typedef struct QXLDrawArea {
     uint8_t *buf;
     uint32_t size;
commit f4ba39fe0f41e76b90fb2afe8ee08337e6981799
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 10:59:47 2011 +0300

    server: spice-server.syms: move sasl symbols to 0.8.2

diff --git a/server/spice-server.syms b/server/spice-server.syms
index 7f3c5d4..da7a483 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -54,13 +54,17 @@ global:
     spice_server_set_agent_copypaste;
 } SPICE_SERVER_0.8.0;
 
+SPICE_SERVER_0.8.2 {
+global:
+    spice_server_set_sasl;
+    spice_server_set_sasl_appname;
+} SPICE_SERVER_0.8.1;
+
 SPICE_SERVER_0.10.0 {
 global:
     spice_server_playback_set_mute;
     spice_server_playback_set_volume;
     spice_server_record_set_mute;
     spice_server_record_set_volume;
-    spice_server_set_sasl;
-    spice_server_set_sasl_appname;
-} SPICE_SERVER_0.8.1;
+} SPICE_SERVER_0.8.2;
 


More information about the Spice-commits mailing list