[Spice-devel] [PATCH 1/2] server: spice_qxl_update_area_dirty_async

Alon Levy alevy at redhat.com
Mon Oct 24 05:09:51 PDT 2011


Bumps spice to 0.9.2, since it adds a new symbol. This will be 0.8.4
in 0.8 branch - the syms file is updated to contain 0.8.3 and 0.8.4.

Add an asynchronous version of update_area that updates the dirty
rectangles, similarily to the sync one. The existing async version
doesn't pass the dirty list at all, which is good for
QXL_IO_UPDATE_AREA, but bad for the monitor command screen_dump.

Bumping SPICE_INTERFACE_QXL_MINOR to 2 for a compile time check.

RHBZ: 747011
FDBZ: 41622
---
 configure.ac             |    2 +-
 server/red_dispatcher.c  |   34 +++++++++++++++++++++++++++++++++-
 server/red_worker.c      |   42 ++++++++++++++++++++++++++++++------------
 server/red_worker.h      |    3 ++-
 server/spice-server.syms |   12 ++++++++++--
 server/spice.h           |    8 ++++++--
 6 files changed, 82 insertions(+), 19 deletions(-)

diff --git a/configure.ac b/configure.ac
index 2afc559..c555749 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ AC_PREREQ([2.57])
 
 m4_define([SPICE_MAJOR], 0)
 m4_define([SPICE_MINOR], 9)
-m4_define([SPICE_MICRO], 1)
+m4_define([SPICE_MICRO], 2)
 
 AC_INIT(spice, [SPICE_MAJOR.SPICE_MINOR.SPICE_MICRO], [], spice)
 
diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 721c79c..6731727 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -268,7 +268,8 @@ static RedWorkerMessage red_dispatcher_async_start(RedDispatcher *dispatcher,
 {
     pthread_mutex_lock(&dispatcher->async_lock);
     if (dispatcher->async_message != RED_WORKER_MESSAGE_NOP) {
-        red_printf("error: async clash. second async ignored");
+        red_printf("warning: async clash. have %d, ignoring %d",
+                 dispatcher->async_message, message);
         pthread_mutex_unlock(&dispatcher->async_lock);
         return RED_WORKER_MESSAGE_NOP;
     }
@@ -297,6 +298,27 @@ static void red_dispatcher_update_area_async(RedDispatcher *dispatcher,
     send_data(dispatcher->channel, &clear_dirty_region, sizeof(uint32_t));
 }
 
+static void red_dispatcher_update_area_dirty_async(RedDispatcher *dispatcher,
+                                       uint32_t surface_id, struct QXLRect *qxl_area,
+                                       struct QXLRect *qxl_dirty_rects, uint32_t num_dirty_rects,
+                                       uint32_t clear_dirty_region, uint64_t cookie)
+{
+    RedWorkerMessage message = red_dispatcher_async_start(
+            dispatcher, RED_WORKER_MESSAGE_UPDATE_DIRTY_ASYNC);
+
+    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, &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));
+}
+
 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)
@@ -806,6 +828,15 @@ void spice_qxl_update_area_async(QXLInstance *instance, uint32_t surface_id, QXL
 }
 
 SPICE_GNUC_VISIBLE
+void spice_qxl_update_area_dirty_async(QXLInstance *instance, uint32_t surface_id,
+                QXLRect *qxl_area, struct QXLRect *qxl_dirty_rects, uint32_t num_dirty_rects,
+                uint32_t clear_dirty_region, uint64_t cookie)
+{
+    red_dispatcher_update_area_dirty_async(instance->st->dispatcher, surface_id, qxl_area,
+                                     qxl_dirty_rects, num_dirty_rects, 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);
@@ -847,6 +878,7 @@ void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t co
     pthread_mutex_lock(&dispatcher->async_lock);
     switch (dispatcher->async_message) {
     case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+    case RED_WORKER_MESSAGE_UPDATE_DIRTY_ASYNC:
         break;
     case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
         break;
diff --git a/server/red_worker.c b/server/red_worker.c
index 6756af9..5a77f35 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -43,6 +43,7 @@
 #include <netinet/tcp.h>
 #include <setjmp.h>
 #include <openssl/ssl.h>
+#include <inttypes.h>
 
 #include <spice/qxl_dev.h>
 #include "spice.h"
@@ -10102,18 +10103,23 @@ static void surface_dirty_region_to_rects(RedSurface *surface,
     free(dirty_rects);
 }
 
-static inline void handle_dev_update_async(RedWorker *worker)
+static inline void handle_dev_update_async(RedWorker *worker, int with_dirty)
 {
     QXLRect qxl_rect;
     SpiceRect rect;
     uint32_t surface_id;
     uint32_t clear_dirty_region;
-    QXLRect *qxl_dirty_rects;
+    QXLRect *qxl_dirty_rects = NULL;
     uint32_t num_dirty_rects;
     RedSurface *surface;
 
+    red_printf_debug(2, "");
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
     receive_data(worker->channel, &qxl_rect, sizeof(QXLRect));
+    if (with_dirty) {
+        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));
 
     red_get_rect_ptr(&rect, &qxl_rect);
@@ -10123,20 +10129,27 @@ 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) {
+    if (!worker->qxl->st->qif->update_area_complete && !with_dirty) {
         return;
     }
     surface = &worker->surfaces[surface_id];
-    num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
-    if (num_dirty_rects == 0) {
-        return;
+    if (!with_dirty) {
+        num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
+        if (num_dirty_rects != 0) {
+            qxl_dirty_rects = spice_new0(QXLRect, num_dirty_rects);
+        }
     }
-    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,
+    if (num_dirty_rects > 0) {
+        surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
+                                      clear_dirty_region);
+    }
+    if (worker->qxl->st->qif->update_area_complete) {
+        worker->qxl->st->qif->update_area_complete(worker->qxl, surface_id,
                                           qxl_dirty_rects, num_dirty_rects);
-    free(qxl_dirty_rects);
+    }
+    if (!with_dirty) {
+        free(qxl_dirty_rects);
+    }
 }
 
 static inline void handle_dev_update(RedWorker *worker)
@@ -10390,6 +10403,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
      * 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_UPDATE_DIRTY_ASYNC:
     case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
     case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
@@ -10398,6 +10412,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
         call_async_complete = 1;
         receive_data(worker->channel, &cookie, sizeof(cookie));
+        red_printf_debug(2, "got cookie: %"PRIu64"", cookie);
         break;
     case RED_WORKER_MESSAGE_UPDATE:
     case RED_WORKER_MESSAGE_ADD_MEMSLOT:
@@ -10419,8 +10434,11 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     }
 
     switch (message) {
+    case RED_WORKER_MESSAGE_UPDATE_DIRTY_ASYNC:
+        handle_dev_update_async(worker, 1);
+        break;
     case RED_WORKER_MESSAGE_UPDATE_ASYNC:
-        handle_dev_update_async(worker);
+        handle_dev_update_async(worker, 0);
         break;
     case RED_WORKER_MESSAGE_UPDATE:
         handle_dev_update(worker);
diff --git a/server/red_worker.h b/server/red_worker.h
index 26c43ad..6db1d24 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -81,9 +81,10 @@ enum {
     RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
     /* suspend/windows resolution change command */
     RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC,
-
     RED_WORKER_MESSAGE_DISPLAY_CHANNEL_CREATE,
     RED_WORKER_MESSAGE_CURSOR_CHANNEL_CREATE,
+    /* support monitor async screen dump */
+    RED_WORKER_MESSAGE_UPDATE_DIRTY_ASYNC,
 };
 
 typedef uint32_t RedWorkerMessage;
diff --git a/server/spice-server.syms b/server/spice-server.syms
index f1374bd..ec51df9 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -82,6 +82,15 @@ global:
     spice_qxl_flush_surfaces_async;
 } SPICE_SERVER_0.8.1;
 
+SPICE_SERVER_0.8.3 {
+    spice_server_migrate_connect;
+} SPICE_SERVER_0.8.2;
+
+SPICE_SERVER_0.8.4 {
+global:
+    spice_qxl_update_area_dirty_async;
+} SPICE_SERVER_0.8.3;
+
 SPICE_SERVER_0.10.0 {
 global:
     spice_server_playback_set_mute;
@@ -89,5 +98,4 @@ global:
     spice_server_record_set_mute;
     spice_server_record_set_volume;
     spice_server_get_num_clients;
-} SPICE_SERVER_0.8.2;
-
+} SPICE_SERVER_0.8.4;
diff --git a/server/spice.h b/server/spice.h
index 74f9fdb..354efd8 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -22,7 +22,7 @@
 #include <sys/socket.h>
 #include <spice/qxl_dev.h>
 
-#define SPICE_SERVER_VERSION 0x000901 /* release 0.9.1 */
+#define SPICE_SERVER_VERSION 0x000902 /* release 0.9.2 */
 
 /* interface base type */
 
@@ -90,7 +90,7 @@ struct SpiceCoreInterface {
 
 #define SPICE_INTERFACE_QXL "qxl"
 #define SPICE_INTERFACE_QXL_MAJOR 3
-#define SPICE_INTERFACE_QXL_MINOR 1
+#define SPICE_INTERFACE_QXL_MINOR 2
 typedef struct QXLInterface QXLInterface;
 typedef struct QXLInstance QXLInstance;
 typedef struct QXLState QXLState;
@@ -147,6 +147,10 @@ void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext,
 /* 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_update_area_dirty_async(QXLInstance *instance, uint32_t surface_id,
+                                       struct QXLRect *area, struct QXLRect *dirty_rects,
+                                       uint32_t num_dirty_rects, 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);
-- 
1.7.7



More information about the Spice-devel mailing list