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. --- server/red_dispatcher.c | 33 ++++++++++++++++++++++++++++++++- server/red_worker.c | 42 ++++++++++++++++++++++++++++++------------ server/red_worker.h | 2 ++ server/spice-server.syms | 5 +++++ server/spice.h | 6 +++++- 5 files changed, 74 insertions(+), 14 deletions(-) diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c index f846a8c..a998238 100644 --- a/server/red_dispatcher.c +++ b/server/red_dispatcher.c @@ -230,7 +230,7 @@ static RedWorkerMessage red_dispatcher_async_start(RedDispatcher *dispatcher, pthread_mutex_lock(&dispatcher->async_lock); if (dispatcher->async_message != RED_WORKER_MESSAGE_NOP) { red_warn("warning: async clash. have %d, ignoring %d", - dispatcher->async_message, message); + dispatcher->async_message, message); pthread_mutex_unlock(&dispatcher->async_lock); return RED_WORKER_MESSAGE_NOP; } @@ -259,6 +259,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) @@ -768,6 +789,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); @@ -809,6 +839,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 0d67586..e74f3a4 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -30,6 +30,7 @@ #include <netinet/tcp.h> #include <setjmp.h> #include <openssl/ssl.h> +#include <inttypes.h> #include <spice/qxl_dev.h> #include "spice.h" @@ -9665,18 +9666,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_log(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); @@ -9686,20 +9692,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) @@ -9950,6 +9963,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: @@ -9958,6 +9972,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_log(2, "got cookie: %"PRIu64"", cookie); break; case RED_WORKER_MESSAGE_UPDATE: case RED_WORKER_MESSAGE_ADD_MEMSLOT: @@ -9975,8 +9990,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 e65ab19..1787f13 100644 --- a/server/red_worker.h +++ b/server/red_worker.h @@ -77,6 +77,8 @@ enum { RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC, /* suspend/windows resolution change command */ RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC, + /* 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 62cdc18..5cb63fa 100644 --- a/server/spice-server.syms +++ b/server/spice-server.syms @@ -85,3 +85,8 @@ global: 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; diff --git a/server/spice.h b/server/spice.h index ce2d149..967fc1e 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 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.6.4 _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel