[Spice-devel] [PATCH 5/6] server/red_worker: (QXLInterface change) add update_mem for S3/S4 support
Alon Levy
alevy at redhat.com
Mon Jun 20 04:18:08 PDT 2011
Adds QXLWorker::update_mem to the public api (spice.h) functions, used by qxl
(qemu) for ACPI S3 (suspend to ram) and S4 (hibernate, suspend to disk)
support. This is a helper function, it provides functionality available
otherwise but by adding it the amount of vmexits is reduced. Specifically:
update_mem:
render all operations onto each surface
(guest will copy surfaces from pci to guest ram)
free all resources (pci may be erased and qxl *will* be reset)
(in particular) destroy all surfaces
alternative: guest can do an QXL_IO_UPDATE_AREA for each surface.
This is a vmexit per UPDATE_AREA.
this only takes care of the rendering. It can then send a destroy surface
command treating it specially in the driver (not releasing the guest side
resource). 32 commands in the ring, so an additional number of vmexits
(windows xp guest has ~40 surfaces after boot).
Cc: Yonit Halperin <yhalperi at redhat.com>
---
server/red_dispatcher.c | 12 ++++++++++
server/red_worker.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-
server/red_worker.h | 1 +
server/spice.h | 1 +
4 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 56446ab..22c69b5 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -460,6 +460,16 @@ void red_dispatcher_set_mouse_mode(uint32_t mode)
}
}
+static void qxl_worker_update_mem(QXLWorker *qxl_worker)
+{
+ RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+ RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE_MEM;
+
+ write_message(dispatcher->channel, &message);
+ read_message(dispatcher->channel, &message);
+ ASSERT(message == RED_WORKER_MESSAGE_READY);
+}
+
int red_dispatcher_count(void)
{
RedDispatcher *now = dispatchers;
@@ -538,6 +548,8 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
dispatcher->base.destroy_surface_wait = qxl_worker_destroy_surface_wait;
dispatcher->base.loadvm_commands = qxl_worker_loadvm_commands;
+ dispatcher->base.update_mem = qxl_worker_update_mem;
+
qxl->st->qif->get_init_info(qxl, &init_info);
init_data.memslot_id_bits = init_info.memslot_id_bits;
diff --git a/server/red_worker.c b/server/red_worker.c
index 38ccb90..f5a2091 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -4290,7 +4290,8 @@ 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,
+ surface->flags & QXL_SURF_FLAG_KEEP_DATA);
break;
}
default:
@@ -8485,6 +8486,9 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
}
red_create_surface_item(worker, surface_id);
+ if (data_is_valid) {
+ red_add_surface_image(worker, surface_id);
+ }
return;
}
@@ -8495,6 +8499,9 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
if (surface->context.canvas) { //no need canvas check
worker->renderer = worker->renderers[i];
red_create_surface_item(worker, surface_id);
+ if (data_is_valid) {
+ red_add_surface_image(worker, surface_id);
+ }
return;
}
}
@@ -9550,7 +9557,6 @@ static inline void destroy_all_surfaces_starting_from(RedWorker *worker, int fir
{
int i;
- red_printf("");
flush_all_qxl_commands(worker);
//to handle better
for (i = first_surface_id; i < NUM_SURFACES; ++i) {
@@ -9590,6 +9596,12 @@ static inline void destroy_all_surfaces_starting_from(RedWorker *worker, int fir
worker->cursor_trail_length = worker->cursor_trail_frequency = 0;
}
+static void destroy_all_offscreen_surfaces(RedWorker *worker)
+{
+ red_printf("");
+ destroy_all_surfaces_starting_from(worker, 1);
+}
+
/* called upon device reset */
static inline void handle_dev_destroy_surfaces(RedWorker *worker)
{
@@ -9676,6 +9688,38 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
write_message(worker->channel, &message);
}
+/*
+ * Render all surfaces
+ * then call to handle_dev_destroy_surface_wait
+ */
+static void red_worker_update_mem(RedWorker *worker)
+{
+ RedWorkerMessage message;
+ SpiceRect area = {0, 0, 0, 0};
+ RedSurface *surface;
+ int surface_id;
+ int count = 0;
+
+ red_cursor_flush(worker);
+ flush_all_qxl_commands(worker);
+ // TODO: go over worker->current_list instead of individually over surfaces currents.
+ for (surface_id = 1 ; surface_id < NUM_SURFACES ; ++surface_id) {
+ if (!worker->surfaces[surface_id].context.canvas) {
+ continue;
+ }
+ count++;
+ surface = &worker->surfaces[surface_id];
+ area.right = surface->context.width;
+ area.bottom = surface->context.height;
+ red_update_area(worker, &area, surface_id);
+ }
+ destroy_all_offscreen_surfaces(worker);
+ red_printf("updated %d surfaces (left with %d/%d/%d)", count,
+ worker->drawable_count, worker->current_size, worker->stream_count);
+ message = RED_WORKER_MESSAGE_READY;
+ write_message(worker->channel, &message);
+}
+
static void handle_dev_input(EventListener *listener, uint32_t events)
{
RedWorker *worker = SPICE_CONTAINEROF(listener, RedWorker, dev_listener);
@@ -9913,6 +9957,10 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
write_message(worker->channel, &message);
break;
}
+ case RED_WORKER_MESSAGE_UPDATE_MEM: {
+ red_worker_update_mem(worker);
+ break;
+ }
default:
red_error("message error");
}
diff --git a/server/red_worker.h b/server/red_worker.h
index b4e2ed2..7dfb433 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -70,6 +70,7 @@ enum {
RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
RED_WORKER_MESSAGE_LOADVM_COMMANDS,
+ RED_WORKER_MESSAGE_UPDATE_MEM,
};
typedef uint32_t RedWorkerMessage;
diff --git a/server/spice.h b/server/spice.h
index cbb75cc..23e7d54 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -122,6 +122,7 @@ struct QXLWorker {
void (*reset_cursor)(QXLWorker *worker);
void (*destroy_surface_wait)(QXLWorker *worker, uint32_t surface_id);
void (*loadvm_commands)(QXLWorker *worker, struct QXLCommandExt *ext, uint32_t count);
+ void (*update_mem)(QXLWorker *worker);
};
typedef struct QXLDrawArea {
--
1.7.5.2
More information about the Spice-devel
mailing list