diff options
Diffstat (limited to 'server/red_worker.c')
-rw-r--r-- | server/red_worker.c | 160 |
1 files changed, 112 insertions, 48 deletions
diff --git a/server/red_worker.c b/server/red_worker.c index 2349ac51..f29a4207 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -61,6 +61,7 @@ #include "generated_marshallers.h" #include "zlib_encoder.h" #include "red_channel.h" +#include "red_dispatcher.h" //#define COMPRESS_STAT //#define DUMP_BITMAP @@ -805,6 +806,7 @@ typedef struct RedWorker { DisplayChannel *display_channel; CursorChannel *cursor_channel; QXLInstance *qxl; + RedDispatcher *dispatcher; int id; int channel; int running; @@ -9424,28 +9426,53 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item) red_unref_channel(channel); } +static inline void handle_dev_update_async(RedWorker *worker) +{ + QXLRect qxl_rect; + SpiceRect rect; + uint32_t surface_id; + uint32_t clear_dirty_region; + + receive_data(worker->channel, &surface_id, sizeof(uint32_t)); + receive_data(worker->channel, &qxl_rect, sizeof(QXLRect)); + receive_data(worker->channel, &clear_dirty_region, sizeof(uint32_t)); + + red_get_rect_ptr(&rect, &qxl_rect); + flush_display_commands(worker); + + ASSERT(worker->running); + + validate_surface(worker, surface_id); + red_update_area(worker, &rect, surface_id); +} + static inline void handle_dev_update(RedWorker *worker) { - RedWorkerMessage message; - const SpiceRect *rect; + 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, &rect, sizeof(SpiceRect *)); - receive_data(worker->channel, &dirty_rects, sizeof(SpiceRect *)); + 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); ASSERT(worker->running); validate_surface(worker, surface_id); red_update_area(worker, rect, surface_id); + free(rect); surface = &worker->surfaces[surface_id]; region_ret_rects(&surface->draw_dirty_region, dirty_rects, num_dirty_rects); @@ -9453,15 +9480,17 @@ static inline void handle_dev_update(RedWorker *worker) if (clear_dirty_region) { region_clear(&surface->draw_dirty_region); } - - message = RED_WORKER_MESSAGE_READY; - write_message(worker->channel, &message); + 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); } - static inline void handle_dev_add_memslot(RedWorker *worker) { - RedWorkerMessage message; QXLDevMemSlot dev_slot; receive_data(worker->channel, &dev_slot, sizeof(QXLDevMemSlot)); @@ -9469,9 +9498,6 @@ static inline void handle_dev_add_memslot(RedWorker *worker) red_memslot_info_add_slot(&worker->mem_slots, dev_slot.slot_group_id, dev_slot.slot_id, dev_slot.addr_delta, dev_slot.virt_start, dev_slot.virt_end, dev_slot.generation); - - message = RED_WORKER_MESSAGE_READY; - write_message(worker->channel, &message); } static inline void handle_dev_del_memslot(RedWorker *worker) @@ -9507,7 +9533,6 @@ static inline void destroy_surface_wait(RedWorker *worker, int surface_id) static inline void handle_dev_destroy_surface_wait(RedWorker *worker) { - RedWorkerMessage message; uint32_t surface_id; receive_data(worker->channel, &surface_id, sizeof(uint32_t)); @@ -9519,9 +9544,6 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker) if (worker->surfaces[0].context.canvas) { destroy_surface_wait(worker, 0); } - - message = RED_WORKER_MESSAGE_READY; - write_message(worker->channel, &message); } static inline void red_cursor_reset(RedWorker *worker) @@ -9549,7 +9571,6 @@ static inline void red_cursor_reset(RedWorker *worker) static inline void handle_dev_destroy_surfaces(RedWorker *worker) { int i; - RedWorkerMessage message; flush_all_qxl_commands(worker); //to handle better @@ -9572,14 +9593,10 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker) red_display_clear_glz_drawables(worker->display_channel); red_cursor_reset(worker); - - message = RED_WORKER_MESSAGE_READY; - write_message(worker->channel, &message); } static inline void handle_dev_create_primary_surface(RedWorker *worker) { - RedWorkerMessage message; uint32_t surface_id; QXLDevSurfaceCreate surface; uint8_t *line_0; @@ -9609,14 +9626,10 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker) if (worker->cursor_channel) { red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT); } - - message = RED_WORKER_MESSAGE_READY; - write_message(worker->channel, &message); } static inline void handle_dev_destroy_primary_surface(RedWorker *worker) { - RedWorkerMessage message; uint32_t surface_id; receive_data(worker->channel, &surface_id, sizeof(uint32_t)); @@ -9632,22 +9645,78 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker) ASSERT(!worker->surfaces[surface_id].context.canvas); red_cursor_reset(worker); +} - message = RED_WORKER_MESSAGE_READY; - write_message(worker->channel, &message); +static void handle_dev_stop(RedWorker *worker) +{ + int x; + + ASSERT(worker->running); + worker->running = FALSE; + red_display_clear_glz_drawables(worker->display_channel); + for (x = 0; x < NUM_SURFACES; ++x) { + if (worker->surfaces[x].context.canvas) { + red_current_flush(worker, x); + } + } + red_wait_outgoing_item((RedChannel *)worker->display_channel); + red_wait_outgoing_item((RedChannel *)worker->cursor_channel); +} + +static void handle_dev_start(RedWorker *worker) +{ + RedChannel *cursor_red_channel = &worker->cursor_channel->common.base; + RedChannel *display_red_channel = &worker->display_channel->common.base; + + ASSERT(!worker->running); + if (worker->cursor_channel) { + cursor_red_channel->migrate = FALSE; + } + if (worker->display_channel) { + display_red_channel->migrate = FALSE; + } + worker->running = TRUE; } static void handle_dev_input(EventListener *listener, uint32_t events) { RedWorker *worker = SPICE_CONTAINEROF(listener, RedWorker, dev_listener); RedWorkerMessage message; - RedChannel *cursor_red_channel = &worker->cursor_channel->common.base; RedChannel *display_red_channel = &worker->display_channel->common.base; int ring_is_empty; + int call_async_complete = 0; + int write_ready = 0; + uint64_t cookie; read_message(worker->channel, &message); + /* for async messages we do the common work in the handler, and + * 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_ADD_MEMSLOT_ASYNC: + case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC: + case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC: + case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC: + case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC: + call_async_complete = 1; + receive_data(worker->channel, &cookie, sizeof(cookie)); + break; + case RED_WORKER_MESSAGE_UPDATE: + case RED_WORKER_MESSAGE_ADD_MEMSLOT: + case RED_WORKER_MESSAGE_DESTROY_SURFACES: + case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE: + case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE: + case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT: + write_ready = 1; + default: + break; + } + switch (message) { + case RED_WORKER_MESSAGE_UPDATE_ASYNC: + handle_dev_update_async(worker); + break; case RED_WORKER_MESSAGE_UPDATE: handle_dev_update(worker); break; @@ -9679,15 +9748,19 @@ static void handle_dev_input(EventListener *listener, uint32_t events) message = RED_WORKER_MESSAGE_READY; write_message(worker->channel, &message); break; + case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC: case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT: handle_dev_destroy_surface_wait(worker); break; + case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC: case RED_WORKER_MESSAGE_DESTROY_SURFACES: handle_dev_destroy_surfaces(worker); break; + case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC: case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE: handle_dev_create_primary_surface(worker); break; + case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC: case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE: handle_dev_destroy_primary_surface(worker); break; @@ -9706,33 +9779,15 @@ static void handle_dev_input(EventListener *listener, uint32_t events) red_disconnect_display((RedChannel *)worker->display_channel); break; case RED_WORKER_MESSAGE_STOP: { - int x; - red_printf("stop"); - ASSERT(worker->running); - worker->running = FALSE; - red_display_clear_glz_drawables(worker->display_channel); - for (x = 0; x < NUM_SURFACES; ++x) { - if (worker->surfaces[x].context.canvas) { - red_current_flush(worker, x); - } - } - red_wait_outgoing_item((RedChannel *)worker->display_channel); - red_wait_outgoing_item((RedChannel *)worker->cursor_channel); + handle_dev_stop(worker); message = RED_WORKER_MESSAGE_READY; write_message(worker->channel, &message); break; } case RED_WORKER_MESSAGE_START: red_printf("start"); - ASSERT(!worker->running); - if (worker->cursor_channel) { - cursor_red_channel->migrate = FALSE; - } - if (worker->display_channel) { - display_red_channel->migrate = FALSE; - } - worker->running = TRUE; + handle_dev_start(worker); break; case RED_WORKER_MESSAGE_DISPLAY_MIGRATE: red_printf("migrate"); @@ -9814,6 +9869,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events) receive_data(worker->channel, &worker->mouse_mode, sizeof(uint32_t)); red_printf("mouse mode %u", worker->mouse_mode); break; + case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC: case RED_WORKER_MESSAGE_ADD_MEMSLOT: handle_dev_add_memslot(worker); break; @@ -9859,6 +9915,13 @@ static void handle_dev_input(EventListener *listener, uint32_t events) default: red_error("message error"); } + if (call_async_complete) { + red_dispatcher_async_complete(worker->dispatcher, cookie); + } + if (write_ready) { + message = RED_WORKER_MESSAGE_READY; + write_message(worker->channel, &message); + } } static void handle_dev_free(EventListener *ctx) @@ -9875,6 +9938,7 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data) ASSERT(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE); memset(worker, 0, sizeof(RedWorker)); + worker->dispatcher = init_data->dispatcher; worker->qxl = init_data->qxl; worker->id = init_data->id; worker->channel = init_data->channel; |