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 <yhalp...@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 _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel