[Spice-devel] [PATCH v3] server: add QXLInterface::surface_updated callback

Alon Levy alevy at redhat.com
Thu Jul 7 09:33:29 PDT 2011


used to move dirty rectangle notification from update_area to surface_updated.

This is RfC quality. Specifically where to call surface_updated. Currently I
only call it from stop. This should be good enough for migration, which is
the only use case I think. This means after stop qemu is guranteed to know
the dirty regions of all surfaces.
---
 server/red_dispatcher.c          |   20 +++--------
 server/red_worker.c              |   71 +++++++++++++++++++++++++------------
 server/spice.h                   |    8 ++--
 server/tests/test_display_base.c |    2 +-
 4 files changed, 58 insertions(+), 43 deletions(-)

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 3dfd4e5..996e1ed 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -210,9 +210,7 @@ static void update_client_mouse_allowed(void)
 }
 
 static void qxl_worker_update_area_helper(QXLWorker *qxl_worker, uint32_t surface_id,
-                                   QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
-                                   uint32_t num_dirty_rects, uint32_t clear_dirty_region,
-                                   int async, uint64_t cookie)
+                                   QXLRect *qxl_area, int async, uint64_t cookie)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message;
@@ -228,9 +226,6 @@ static void qxl_worker_update_area_helper(QXLWorker *qxl_worker, uint32_t surfac
     }
     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));
     if (async) {
         return;
     }
@@ -239,22 +234,17 @@ static void qxl_worker_update_area_helper(QXLWorker *qxl_worker, uint32_t surfac
 }
 
 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)
+                                   QXLRect *qxl_area)
 {
-    qxl_worker_update_area_helper(qxl_worker, surface_id, qxl_area, qxl_dirty_rects, num_dirty_rects,
-        clear_dirty_region, 0, 0);
+    qxl_worker_update_area_helper(qxl_worker, surface_id, qxl_area, 0, 0);
 }
 
 static void qxl_worker_update_area_async(QXLWorker *qxl_worker, uint32_t surface_id,
-                                   QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
-                                   uint32_t num_dirty_rects, uint32_t clear_dirty_region, uint64_t cookie)
+                                         QXLRect *qxl_area, uint64_t cookie)
 {
-    qxl_worker_update_area_helper(qxl_worker, surface_id, qxl_area, qxl_dirty_rects, num_dirty_rects,
-        clear_dirty_region, 1, cookie);
+    qxl_worker_update_area_helper(qxl_worker, surface_id, qxl_area, 1, cookie);
 }
 
-
 static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
diff --git a/server/red_worker.c b/server/red_worker.c
index cb84754..f5b5570 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9415,25 +9415,56 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
     red_unref_channel(channel);
 }
 
+static int surface_updated_available(RedWorker *worker)
+{
+    int minor = worker->qxl->st->qif->base.minor_version;
+    int major = worker->qxl->st->qif->base.major_version;
+
+    return (major > 3 || (major == 3 && minor >= 1)) &&
+            worker->qxl->st->qif->surface_updated != NULL;
+}
+
+static void notify_surface_updated(RedWorker *worker, uint32_t surface_id)
+{
+    QXLRect *qxl_dirty_rects;
+    SpiceRect* dirty_rects;
+    uint32_t num_dirty_rects;
+    QRegion *surface_dirty_region;
+    RedSurface *surface;
+    int i;
+
+    if (!surface_updated_available(worker)) {
+        return;
+    }
+
+    surface = &worker->surfaces[surface_id];
+    surface_dirty_region = &surface->draw_dirty_region;
+    num_dirty_rects = pixman_region32_n_rects((pixman_region32_t *)&surface_dirty_region);
+    dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
+    region_ret_rects(surface_dirty_region, dirty_rects, num_dirty_rects);
+    region_clear(surface_dirty_region);
+    qxl_dirty_rects = spice_new0(QXLRect, num_dirty_rects);
+    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);
+    worker->qxl->st->qif->surface_updated(worker->qxl, surface_id,
+                                          qxl_dirty_rects, num_dirty_rects);
+    free(qxl_dirty_rects);
+}
+
 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 *));
-    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);
 
@@ -9441,19 +9472,6 @@ static inline void handle_dev_update(RedWorker *worker)
 
     validate_surface(worker, surface_id);
     red_update_area(worker, rect, surface_id);
-
-    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;
-    }
 }
 
 
@@ -9636,12 +9654,19 @@ static void handle_dev_flush_surfaces(RedWorker *worker)
 
 static void handle_dev_stop(RedWorker *worker)
 {
+    int x;
+
     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);
+    for (x = 0; x < NUM_SURFACES; ++x) {
+        if (worker->surfaces[x].context.canvas) {
+            notify_surface_updated(worker, x);
+        }
+    }
 }
 
 static void handle_dev_start(RedWorker *worker)
diff --git a/server/spice.h b/server/spice.h
index 048462f..4fcc1cf 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -109,8 +109,7 @@ struct QXLWorker {
     void (*start)(QXLWorker *worker);
     void (*stop)(QXLWorker *worker);
     void (*update_area)(QXLWorker *qxl_worker, uint32_t surface_id,
-                       struct QXLRect *area, struct QXLRect *dirty_rects,
-                       uint32_t num_dirty_rects, uint32_t clear_dirty_region);
+                       struct QXLRect *area);
     void (*add_memslot)(QXLWorker *worker, QXLDevMemSlot *slot);
     void (*del_memslot)(QXLWorker *worker, uint32_t slot_group_id, uint32_t slot_id);
     void (*reset_memslots)(QXLWorker *worker);
@@ -124,8 +123,7 @@ struct QXLWorker {
     void (*loadvm_commands)(QXLWorker *worker, struct QXLCommandExt *ext, uint32_t count);
     /* async versions of commands. when complete spice calls async_complete */
     void (*update_area_async)(QXLWorker *qxl_worker, uint32_t surface_id,
-                       struct QXLRect *area, struct QXLRect *dirty_rects,
-                       uint32_t num_dirty_rects, uint32_t clear_dirty_region, uint64_t cookie);
+                       struct QXLRect *area, uint64_t cookie);
     void (*add_memslot_async)(QXLWorker *worker, QXLDevMemSlot *slot, uint64_t cookie);
     void (*destroy_surfaces_async)(QXLWorker *worker, uint64_t cookie);
     void (*destroy_primary_surface_async)(QXLWorker *worker, uint32_t surface_id, uint64_t cookie);
@@ -205,6 +203,8 @@ 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 (*surface_updated)(QXLInstance *qin, uint32_t surface_id, struct QXLRect *updated_rects,
+                       uint32_t num_updated_rects);
 };
 
 struct QXLInstance {
diff --git a/server/tests/test_display_base.c b/server/tests/test_display_base.c
index 76817d9..57c593a 100644
--- a/server/tests/test_display_base.c
+++ b/server/tests/test_display_base.c
@@ -364,7 +364,7 @@ static void produce_command()
         case SIMPLE_UPDATE: {
             QXLRect rect = {.left = 0, .right = WIDTH,
                             .top = 0, .bottom = HEIGHT};
-            qxl_worker->update_area(qxl_worker, 0, &rect, NULL, 0, 1);
+            qxl_worker->update_area(qxl_worker, 0, &rect);
             break;
         }
         case SIMPLE_COPY_BITS:
-- 
1.7.5.4



More information about the Spice-devel mailing list