diff options
author | Izik Eidus <ieidus@redhat.com> | 2010-01-28 04:44:43 +0200 |
---|---|---|
committer | Izik Eidus <ieidus@redhat.com> | 2010-01-28 04:46:29 +0200 |
commit | 2ba69f9f8819daaa3d166c4c1c7e03b121b88a95 (patch) | |
tree | af28f5f7a71af15769c6447ccf4b6e10e8d60644 /server | |
parent | 766c74f63cb005ba614c11a59b5da844f01cb335 (diff) | |
download | spice-2ba69f9f8819daaa3d166c4c1c7e03b121b88a95.tar.gz spice-2ba69f9f8819daaa3d166c4c1c7e03b121b88a95.tar.xz spice-2ba69f9f8819daaa3d166c4c1c7e03b121b88a95.zip |
libspice: add surface 0 support
This include alot of infestracture for off screens.
Signed-off-by: Izik Eidus <ieidus@redhat.com>
Diffstat (limited to 'server')
-rw-r--r-- | server/red_common.h | 5 | ||||
-rw-r--r-- | server/red_dispatcher.c | 111 | ||||
-rw-r--r-- | server/red_worker.c | 1593 | ||||
-rw-r--r-- | server/red_worker.h | 10 | ||||
-rw-r--r-- | server/red_yuv.h | 11 | ||||
-rw-r--r-- | server/vd_interface.h | 44 |
6 files changed, 1137 insertions, 637 deletions
diff --git a/server/red_common.h b/server/red_common.h index fafb2841..f505868c 100644 --- a/server/red_common.h +++ b/server/red_common.h @@ -48,6 +48,11 @@ abort(); \ } +#define PANIC_ON(x) if ((x)) { \ + printf("%s: panic %s\n", __FUNCTION__, #x); \ + abort(); \ +} + #define TRUE 1 #define FALSE 0 diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c index 439d5342..e35aba35 100644 --- a/server/red_dispatcher.c +++ b/server/red_dispatcher.c @@ -44,7 +44,7 @@ struct RedDispatcher { int channel; pthread_t worker_thread; uint32_t pending; - int active; + int primary_active; int x_res; int y_res; int use_hardware_cursor; @@ -179,7 +179,7 @@ static void update_client_mouse_allowed() allow_now = TRUE; RedDispatcher *now = dispatchers; while (now && allow_now) { - if (now->active) { + if (now->primary_active) { allow_now = now->use_hardware_cursor; if (num_active_workers == 1) { if (allow_now) { @@ -199,72 +199,114 @@ static void update_client_mouse_allowed() } } -static void qxl_worker_attach(QXLWorker *qxl_worker) +static void qxl_worker_update_area(QXLWorker *qxl_worker) { RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; - RedWorkeMessage message = RED_WORKER_MESSAGE_ATTACH; - QXLDevInfo info; + RedWorkeMessage message = RED_WORKER_MESSAGE_UPDATE; - dispatcher->qxl_interface->get_info(dispatcher->qxl_interface, &info); - dispatcher->x_res = info.x_res; - dispatcher->y_res = info.y_res; - dispatcher->use_hardware_cursor = info.use_hardware_cursor; - dispatcher->active = TRUE; + write_message(dispatcher->channel, &message); + read_message(dispatcher->channel, &message); + ASSERT(message == RED_WORKER_MESSAGE_READY); +} + +static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot) +{ + RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; + RedWorkeMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT; write_message(dispatcher->channel, &message); - send_data(dispatcher->channel, &info, sizeof(QXLDevInfo)); + send_data(dispatcher->channel, mem_slot, sizeof(QXLDevMemSlot)); read_message(dispatcher->channel, &message); ASSERT(message == RED_WORKER_MESSAGE_READY); +} - num_active_workers++; - update_client_mouse_allowed(); +static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id, uint32_t slot_id) +{ + RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; + RedWorkeMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT; + + write_message(dispatcher->channel, &message); + send_data(dispatcher->channel, &slot_group_id, sizeof(uint32_t)); + send_data(dispatcher->channel, &slot_id, sizeof(uint32_t)); } -static void qxl_worker_detach(QXLWorker *qxl_worker) +static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker) { RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; - RedWorkeMessage message = RED_WORKER_MESSAGE_DETACH; + RedWorkeMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES; write_message(dispatcher->channel, &message); read_message(dispatcher->channel, &message); ASSERT(message == RED_WORKER_MESSAGE_READY); +} + +static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id) +{ + RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; + RedWorkeMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE; + + write_message(dispatcher->channel, &message); + send_data(dispatcher->channel, &surface_id, sizeof(uint32_t)); + read_message(dispatcher->channel, &message); + ASSERT(message == RED_WORKER_MESSAGE_READY); dispatcher->x_res = 0; dispatcher->y_res = 0; dispatcher->use_hardware_cursor = FALSE; - dispatcher->active = FALSE; - num_active_workers--; + dispatcher->primary_active = FALSE; + update_client_mouse_allowed(); } -static void qxl_worker_update_area(QXLWorker *qxl_worker) +static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id, + QXLDevSurfaceCreate *surface) { RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; - RedWorkeMessage message = RED_WORKER_MESSAGE_UPDATE; + RedWorkeMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE; + + dispatcher->x_res = surface->width; + dispatcher->y_res = surface->height; + dispatcher->use_hardware_cursor = surface->mouse_mode; + dispatcher->primary_active = TRUE; write_message(dispatcher->channel, &message); + send_data(dispatcher->channel, &surface_id, sizeof(uint32_t)); + send_data(dispatcher->channel, surface, sizeof(QXLDevSurfaceCreate)); read_message(dispatcher->channel, &message); ASSERT(message == RED_WORKER_MESSAGE_READY); + + update_client_mouse_allowed(); } -static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot) +static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker) { RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; - RedWorkeMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT; + RedWorkeMessage message = RED_WORKER_MESSAGE_RESET_IMAGE_CACHE; write_message(dispatcher->channel, &message); - send_data(dispatcher->channel, mem_slot, sizeof(QXLDevMemSlot)); read_message(dispatcher->channel, &message); ASSERT(message == RED_WORKER_MESSAGE_READY); } -static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_id) +static void qxl_worker_reset_cursor(QXLWorker *qxl_worker) { RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; - RedWorkeMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT; + RedWorkeMessage message = RED_WORKER_MESSAGE_RESET_CURSOR; write_message(dispatcher->channel, &message); - send_data(dispatcher->channel, &slot_id, sizeof(uint32_t)); + read_message(dispatcher->channel, &message); + ASSERT(message == RED_WORKER_MESSAGE_READY); +} + +static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id) +{ + RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker; + RedWorkeMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT; + + write_message(dispatcher->channel, &message); + send_data(dispatcher->channel, &surface_id, sizeof(uint32_t)); + read_message(dispatcher->channel, &message); + ASSERT(message == RED_WORKER_MESSAGE_READY); } static void qxl_worker_reset_memslots(QXLWorker *qxl_worker) @@ -404,12 +446,12 @@ int red_dispatcher_count() uint32_t red_dispatcher_qxl_ram_size() { - QXLDevInfo qxl_info; + QXLDevInitInfo qxl_info; if (!dispatchers) { return 0; } - dispatchers->qxl_interface->get_info(dispatchers->qxl_interface, &qxl_info); - return qxl_info.ram_size; + dispatchers->qxl_interface->get_init_info(dispatchers->qxl_interface, &qxl_info); + return qxl_info.qxl_ram_size; } RedDispatcher *red_dispatcher_init(QXLInterface *qxl_interface) @@ -457,8 +499,6 @@ RedDispatcher *red_dispatcher_init(QXLInterface *qxl_interface) dispatcher->base.major_version = VD_INTERFACE_QXL_MAJOR; dispatcher->base.major_version = VD_INTERFACE_QXL_MINOR; - dispatcher->base.attach = qxl_worker_attach; - dispatcher->base.detach = qxl_worker_detach; dispatcher->base.wakeup = qxl_worker_wakeup; dispatcher->base.oom = qxl_worker_oom; dispatcher->base.save = qxl_worker_save; @@ -469,12 +509,23 @@ RedDispatcher *red_dispatcher_init(QXLInterface *qxl_interface) dispatcher->base.add_memslot = qxl_worker_add_memslot; dispatcher->base.del_memslot = qxl_worker_del_memslot; dispatcher->base.reset_memslots = qxl_worker_reset_memslots; + dispatcher->base.destroy_surfaces = qxl_worker_destroy_surfaces; + dispatcher->base.create_primary_surface = qxl_worker_create_primary; + dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary; + + dispatcher->base.reset_image_cache = qxl_worker_reset_image_cache; + dispatcher->base.reset_cursor = qxl_worker_reset_cursor; + dispatcher->base.destroy_surface_wait = qxl_worker_destroy_surface_wait; qxl_interface->get_init_info(qxl_interface, &init_info); init_data.memslot_id_bits = init_info.memslot_id_bits; init_data.memslot_gen_bits = init_info.memslot_gen_bits; init_data.num_memslots = init_info.num_memslots; + init_data.num_memslots_groups = init_info.num_memslots_groups; + init_data.internal_groupslot_id = init_info.internal_groupslot_id; + + num_active_workers = 1; sigfillset(&thread_sig_mask); sigdelset(&thread_sig_mask, SIGILL); diff --git a/server/red_worker.c b/server/red_worker.c index 575605c1..572b3224 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -216,6 +216,7 @@ typedef struct BufDescriptor { uint32_t size; uint8_t *data; uint32_t slot_id; + uint32_t group_id; } BufDescriptor; enum { @@ -286,8 +287,10 @@ enum { typedef struct CursorItem { PipeItem pipe_data; + uint32_t group_id; int refs; int type; + QXLCursorCmd *qxl_cursor; } CursorItem; typedef struct LocalCursor { @@ -509,9 +512,11 @@ typedef struct FreeList { typedef struct DisplayChannel DisplayChannel; -typedef void *(*enc_get_virt_fn_t)(void *get_virt_opaque, unsigned long addr, uint32_t add_size); +typedef void *(*enc_get_virt_fn_t)(void *get_virt_opaque, unsigned long addr, uint32_t add_size, + uint32_t group_id); typedef void (*enc_validate_virt_fn_t)(void *validate_virt_opaque, unsigned long virt, - unsigned long from_addr, uint32_t add_size); + unsigned long from_addr, uint32_t add_size, + uint32_t group_id); typedef struct { DisplayChannel *display_channel; RedCompressBuf *bufs_head; @@ -521,6 +526,7 @@ typedef struct { struct { ADDRESS next; uint32_t stride; + uint32_t group_id; void *enc_get_virt_opaque; enc_get_virt_fn_t enc_get_virt; @@ -574,6 +580,8 @@ struct RedGlzDrawable { RingItem link; // ordered by the time it was encoded QXLDrawable *qxl_drawable; Drawable *drawable; + uint32_t group_id; + uint8_t *self_bitmap; GlzDrawableInstanceItem instances_pool[MAX_GLZ_DRAWABLE_INSTANCES]; Ring instances; uint8_t instances_count; @@ -793,6 +801,8 @@ struct Drawable { int streamable; #endif BitmapGradualType copy_bitmap_graduality; + uint32_t group_id; + uint8_t *self_bitmap; }; typedef struct _Drawable _Drawable; @@ -803,6 +813,14 @@ struct _Drawable { } u; }; +typedef struct _CursorItem _CursorItem; +struct _CursorItem { + union { + CursorItem cursor_item; + _CursorItem *next; + } u; +}; + typedef struct UpgradeItem { PipeItem base; int refs; @@ -826,13 +844,10 @@ typedef void (*draw_alpha_blend_t)(void *canvas, Rect *bbox, Clip *clip, AlphaBl typedef void (*read_pixels_t)(void *canvas, uint8_t *dest, int dest_stride, const Rect *area); typedef void (*set_top_mask_t)(void *canvas, int num_rect, const Rect *rects); typedef void (*clear_top_mask_t)(void *canvas); -typedef void (*validate_area_t)(void *canvas, const DrawArea *draw_area, const Rect *area); +typedef void (*validate_area_t)(void *canvas, int32_t stride, uint8_t *line_0, const Rect *area); typedef void (*destroy_t)(void *canvas); - -typedef struct DrawContext { - void *canvas; - int top_down; +typedef struct DrawFuncs { draw_fill_t draw_fill; draw_copy_t draw_copy; draw_opaque_t draw_opaque; @@ -851,8 +866,22 @@ typedef struct DrawContext { clear_top_mask_t clear_top_mask; validate_area_t validate_area; destroy_t destroy; +} DrawFuncs; + +typedef struct DrawContext { + void *canvas; + int top_down; + uint32_t width; + uint32_t height; + int32_t stride; + uint8_t depth; + void *line_0; } DrawContext; +typedef struct Surface { + uint32_t refs; + DrawContext context; +} Surface; #ifdef STREAM_TRACE typedef struct ItemTrace { @@ -879,6 +908,7 @@ typedef struct MemSlot { } MemSlot; #define NUM_DRAWABLES 1000 +#define NUM_CURSORS 100 typedef struct RedWorker { EventListener dev_listener; @@ -887,17 +917,18 @@ typedef struct RedWorker { QXLInterface *qxl; int id; int channel; - int attached; int running; uint32_t *pending; - QXLDevInfo dev_info; int epoll; unsigned int epoll_timeout; uint32_t repoll_cmd_ring; uint32_t repoll_cursor_ring; - DrawContext draw_context; uint32_t num_renderers; uint32_t renderers[RED_MAX_RENDERERS]; + uint32_t renderer; + + DrawFuncs draw_funcs; + Surface surface; Ring current_list; Ring current; @@ -919,15 +950,22 @@ typedef struct RedWorker { _Drawable drawables[NUM_DRAWABLES]; _Drawable *free_drawables; - MemSlot *mem_slots; + _CursorItem cursor_items[NUM_CURSORS]; + _CursorItem *free_cursor_items; + + MemSlot **mem_slots; + uint32_t num_memslots_groups; uint32_t num_memslots; uint8_t mem_slot_bits; uint8_t generation_bits; uint8_t memslot_id_shift; uint8_t memslot_gen_shift; + uint8_t internal_groupslot_id; unsigned long memslot_gen_mask; unsigned long memslot_clean_virt_mask; + uint32_t preload_group_id; + uint32_t local_images_pos; LocalImage local_images[MAX_BITMAPS]; @@ -971,7 +1009,7 @@ typedef struct RedWorker { pthread_mutex_t avcodec_lock = PTHREAD_MUTEX_INITIALIZER; -static void red_draw_qxl_drawable(RedWorker *worker, QXLDrawable *drawable); +static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable); static void red_current_flush(RedWorker *worker); static void display_channel_push(RedWorker *worker); #ifdef DRAW_ALL @@ -1001,11 +1039,11 @@ static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipI static int red_display_free_some_independent_glz_drawables(DisplayChannel *channel); static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawable *drawable); static void reset_rate(StreamAgent *stream_agent); -static int _bitmap_is_gradual(RedWorker *worker, Bitmap *bitmap); +static int _bitmap_is_gradual(RedWorker *worker, Bitmap *bitmap, uint32_t group_id); static inline int _stride_is_extra(Bitmap *bitmap); #ifdef DUMP_BITMAP -static void dump_bitmap(RedWorker *worker, Bitmap *bitmap); +static void dump_bitmap(RedWorker *worker, Bitmap *bitmap, uint32_t group_id); #endif #ifdef COMPRESS_STAT @@ -1068,18 +1106,41 @@ static inline unsigned long __get_clean_virt(RedWorker *worker, unsigned long ad return addr & worker->memslot_clean_virt_mask; } -static inline unsigned long get_virt_delta(RedWorker *worker, unsigned long addr) +static inline void print_memslots(RedWorker *worker) +{ + int i; + int x; + + for (i = 0; i < worker->num_memslots_groups; ++i) { + for (x = 0; x < worker->num_memslots; ++x) { + if (!worker->mem_slots[i][x].virt_start_addr && + !worker->mem_slots[i][x].virt_end_addr) { + continue; + } + printf("id %d, group %d, virt start %lx, virt end %lx, generation %u, delta %lx\n", + x, i, worker->mem_slots[i][x].virt_start_addr, + worker->mem_slots[i][x].virt_end_addr, worker->mem_slots[i][x].generation, + worker->mem_slots[i][x].address_delta); + } + } +} + +static inline unsigned long get_virt_delta(RedWorker *worker, unsigned long addr, int group_id) { MemSlot *slot; int slot_id; int generation; + if (group_id > worker->num_memslots_groups) { + PANIC("group_id %d too big", group_id); + } + slot_id = get_memslot_id(worker, addr); if (slot_id > worker->num_memslots) { PANIC("slod_id %d too big", slot_id); } - slot = &worker->mem_slots[slot_id]; + slot = &worker->mem_slots[group_id][slot_id]; generation = get_generation(worker, addr); if (generation != slot->generation) { @@ -1090,21 +1151,25 @@ static inline unsigned long get_virt_delta(RedWorker *worker, unsigned long addr } static inline void validate_virt(RedWorker *worker, unsigned long virt, int slot_id, - uint32_t add_size) + uint32_t add_size, uint32_t group_id) { MemSlot *slot; - slot = &worker->mem_slots[slot_id]; + slot = &worker->mem_slots[group_id][slot_id]; if ((virt + add_size) < virt) { PANIC("virtual address overlap"); } if (virt < slot->virt_start_addr || (virt + add_size) > slot->virt_end_addr) { - PANIC("virtual address out of range 0x%lx 0x%lx", virt, slot->address_delta); + print_memslots(worker); + PANIC("virtual address out of range 0x%lx 0x%lx %d %d 0x%lx 0x%lx 0x%lx", virt, + slot->address_delta, slot_id, group_id, slot->virt_start_addr, slot->virt_end_addr, + virt + add_size); } } -static inline unsigned long get_virt(RedWorker *worker, unsigned long addr, uint32_t add_size) +static inline unsigned long get_virt(RedWorker *worker, unsigned long addr, uint32_t add_size, + int group_id) { int slot_id; int generation; @@ -1112,36 +1177,56 @@ static inline unsigned long get_virt(RedWorker *worker, unsigned long addr, uint MemSlot *slot; + if (group_id > worker->num_memslots_groups) { + PANIC("group_id too big"); + } + slot_id = get_memslot_id(worker, addr); if (slot_id > worker->num_memslots) { PANIC("slot_id too big"); } - slot = &worker->mem_slots[slot_id]; + slot = &worker->mem_slots[group_id][slot_id]; generation = get_generation(worker, addr); if (generation != slot->generation) { - PANIC("address generation is not valid"); + print_memslots(worker); + PANIC("address generation is not valid, group_id %d, slot_id %d, gen %d, slot_gen %d\n", + group_id, slot_id, generation, slot->generation); } h_virt = __get_clean_virt(worker, addr); h_virt += slot->address_delta; - validate_virt(worker, h_virt, slot_id, add_size); + validate_virt(worker, h_virt, slot_id, add_size, group_id); return h_virt; } -static void *cb_get_virt(void *opaque, unsigned long addr, uint32_t add_size) +static void *cb_get_virt(void *opaque, unsigned long addr, uint32_t add_size, uint32_t group_id) { - return (void *)get_virt((RedWorker *)opaque, addr, add_size); + return (void *)get_virt((RedWorker *)opaque, addr, add_size, group_id); } static void cb_validate_virt(void *opaque, unsigned long virt, unsigned long from_addr, - uint32_t add_size) + uint32_t add_size, uint32_t group_id) { int slot_id = get_memslot_id((RedWorker *)opaque, from_addr); - validate_virt((RedWorker *)opaque, virt, slot_id, add_size); + validate_virt((RedWorker *)opaque, virt, slot_id, add_size, group_id); +} + +static void *cb_get_virt_preload_group(void *opaque, unsigned long addr, uint32_t add_size) +{ + return (void *)get_virt((RedWorker *)opaque, addr, add_size, + ((RedWorker *)opaque)->preload_group_id); +} + +static void cb_validate_virt_preload_group(void *opaque, unsigned long virt, + unsigned long from_addr, uint32_t add_size) +{ + int slot_id = get_memslot_id((RedWorker *)opaque, from_addr); + validate_virt((RedWorker *)opaque, virt, slot_id, add_size, + ((RedWorker *)opaque)->preload_group_id); } char *draw_type_to_str(UINT8 type) @@ -1445,15 +1530,42 @@ static void drawables_init(RedWorker *worker) } } -static inline void free_qxl_drawable(RedWorker *worker, QXLDrawable *drawable) + +static void red_reset_stream_trace(RedWorker *worker); + +static inline void __red_destroy_surface(RedWorker *worker) { - if (drawable->bitmap_offset) { - PHYSICAL *addr = (PHYSICAL *)((uint8_t *)drawable + drawable->bitmap_offset); - if (*addr) { - free((uint8_t *)*addr); - } + Surface *surface = &worker->surface; + + if (!--worker->surface.refs) { +#ifdef STREAM_TRACE + red_reset_stream_trace(worker); +#endif + worker->draw_funcs.destroy(surface->context.canvas); + surface->context.canvas = NULL; + } +} + +static inline void red_destroy_surface(RedWorker *worker) +{ + Surface *surface = &worker->surface; + + PANIC_ON(!surface->context.canvas); + __red_destroy_surface(worker); +} + +static inline void free_qxl_drawable(RedWorker *worker, QXLDrawable *drawable, uint32_t group_id, + uint8_t *self_bitmap) +{ + QXLReleaseInfoExt release_info_ext; + red_destroy_surface(worker); + + if (self_bitmap) { + free(self_bitmap); } - worker->qxl->release_resource(worker->qxl, &drawable->release_info); + release_info_ext.group_id = group_id; + release_info_ext.info = &drawable->release_info; + worker->qxl->release_resource(worker->qxl, release_info_ext); } static inline void release_drawable(RedWorker *worker, Drawable *item) @@ -1472,7 +1584,7 @@ static inline void release_drawable(RedWorker *worker, Drawable *item) if (item->red_glz_drawable) { item->red_glz_drawable->drawable = NULL; } else { // no refernce to the qxl drawable left - free_qxl_drawable(worker, item->qxl_drawable); + free_qxl_drawable(worker, item->qxl_drawable, item->group_id, item->self_bitmap); } free_drawable(worker, item); } @@ -2006,7 +2118,8 @@ static inline void __current_add_drawable(RedWorker *worker, Drawable *drawable, #ifdef USE_EXCLUDE_RGN -static int is_equal_path(RedWorker *worker, ADDRESS p1, ADDRESS p2) +static int is_equal_path(RedWorker *worker, ADDRESS p1, ADDRESS p2, uint32_t group_id1, + uint32_t group_id2) { QXLPath *path1; QXLPath *path2; @@ -2020,8 +2133,8 @@ static int is_equal_path(RedWorker *worker, ADDRESS p1, ADDRESS p2) ASSERT(p1 && p2); - path1 = (QXLPath *)get_virt(worker, p1, sizeof(QXLPath)); - path2 = (QXLPath *)get_virt(worker, p2, sizeof(QXLPath)); + path1 = (QXLPath *)get_virt(worker, p1, sizeof(QXLPath), group_id1); + path2 = (QXLPath *)get_virt(worker, p2, sizeof(QXLPath), group_id2); if ((size = path1->data_size) != path2->data_size) { return FALSE; @@ -2047,7 +2160,8 @@ static int is_equal_path(RedWorker *worker, ADDRESS p1, ADDRESS p2) } if ((size1 -= now) == 0) { ASSERT(chunk1->next_chunk) - chunk1 = (QXLDataChunk *)get_virt(worker, chunk1->next_chunk, sizeof(QXLDataChunk)); + chunk1 = (QXLDataChunk *)get_virt(worker, chunk1->next_chunk, sizeof(QXLDataChunk), + group_id1); size1 = chunk1->data_size; data1 = chunk1->data; } else { @@ -2056,7 +2170,8 @@ static int is_equal_path(RedWorker *worker, ADDRESS p1, ADDRESS p2) if ((size2 -= now) == 0) { ASSERT(chunk2->next_chunk) - chunk2 = (QXLDataChunk *)get_virt(worker, chunk2->next_chunk, sizeof(QXLDataChunk)); + chunk2 = (QXLDataChunk *)get_virt(worker, chunk2->next_chunk, sizeof(QXLDataChunk), + group_id2); size2 = chunk2->data_size; data2 = chunk2->data; } else { @@ -2087,34 +2202,37 @@ static inline int rect_is_equal(const Rect *r1, const Rect *r2) } // partial imp -static int is_same_geometry(RedWorker *worker, QXLDrawable *d1, QXLDrawable *d2) +static int is_same_geometry(RedWorker *worker, Drawable *d1, Drawable *d2) { - if (d1->type != d2->type) { + if (d1->qxl_drawable->type != d2->qxl_drawable->type) { return FALSE; } - switch (d1->type) { + switch (d1->qxl_drawable->type) { case QXL_DRAW_STROKE: - return is_equal_line_attr(&d1->u.stroke.attr, &d2->u.stroke.attr) && - is_equal_path(worker, d1->u.stroke.path, d2->u.stroke.path); + return is_equal_line_attr(&d1->qxl_drawable->u.stroke.attr, + &d2->qxl_drawable->u.stroke.attr) && + is_equal_path(worker, d1->qxl_drawable->u.stroke.path, + d2->qxl_drawable->u.stroke.path, d1->group_id, + d2->group_id); case QXL_DRAW_FILL: - return rect_is_equal(&d1->bbox, &d2->bbox); + return rect_is_equal(&d1->qxl_drawable->bbox, &d2->qxl_drawable->bbox); default: return FALSE; } } -static int is_same_drawable(RedWorker *worker, QXLDrawable *d1, QXLDrawable *d2) +static int is_same_drawable(RedWorker *worker, Drawable *d1, Drawable *d2) { if (!is_same_geometry(worker, d1, d2)) { return FALSE; } - switch (d1->type) { + switch (d1->qxl_drawable->type) { case QXL_DRAW_STROKE: - return is_equal_brush(&d1->u.stroke.brush, &d2->u.stroke.brush); + return is_equal_brush(&d1->qxl_drawable->u.stroke.brush, &d2->qxl_drawable->u.stroke.brush); case QXL_DRAW_FILL: - return is_equal_brush(&d1->u.fill.brush, &d2->u.fill.brush); + return is_equal_brush(&d1->qxl_drawable->u.fill.brush, &d2->qxl_drawable->u.fill.brush); default: return FALSE; } @@ -2575,7 +2693,7 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable) stream->frame_buf = frame_buf; stream->frame_buf_end = frame_buf + pict_size; QXLImage *qxl_image = (QXLImage *)get_virt(worker, drawable->qxl_drawable->u.copy.src_bitmap, - sizeof(QXLImage)); + sizeof(QXLImage), drawable->group_id); stream->top_down = !!(qxl_image->bitmap.flags & BITMAP_TOP_DOWN); drawable->stream = stream; @@ -2677,7 +2795,7 @@ static inline int __red_is_next_stream_frame(RedWorker *worker, if (stream) { QXLImage *qxl_image = (QXLImage *)get_virt(worker, qxl_drawable->u.copy.src_bitmap, - sizeof(QXLImage)); + sizeof(QXLImage), candidate->group_id); if (stream->top_down != !!(qxl_image->bitmap.flags & BITMAP_TOP_DOWN)) { return FALSE; } @@ -2731,7 +2849,8 @@ static inline int red_is_next_stream_frame(RedWorker *worker, Drawable *candidat return FALSE; } - qxl_image = (QXLImage *)get_virt(worker, qxl_drawable->u.copy.src_bitmap, sizeof(QXLImage)); + qxl_image = (QXLImage *)get_virt(worker, qxl_drawable->u.copy.src_bitmap, sizeof(QXLImage), + candidate->group_id); if (qxl_image->descriptor.type != IMAGE_TYPE_BITMAP) { return FALSE; @@ -2822,13 +2941,13 @@ static inline void red_update_copy_graduality(RedWorker* worker, Drawable *drawa } qxl_image = (QXLImage *)get_virt(worker, drawable->qxl_drawable->u.copy.src_bitmap, - sizeof(QXLImage)); + sizeof(QXLImage), drawable->group_id); if (!BITMAP_FMT_IS_RGB[qxl_image->bitmap.format] || _stride_is_extra(&qxl_image->bitmap) || (qxl_image->bitmap.flags & QXL_BITMAP_UNSTABLE)) { drawable->copy_bitmap_graduality = BITMAP_GRADUAL_NOT_AVAIL; } else { - if (_bitmap_is_gradual(worker, &qxl_image->bitmap)) { + if (_bitmap_is_gradual(worker, &qxl_image->bitmap, drawable->group_id)) { drawable->copy_bitmap_graduality = BITMAP_GRADUAL_TRUE; } else { drawable->copy_bitmap_graduality = BITMAP_GRADUAL_FALSE; @@ -2927,8 +3046,6 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI DrawItem *other_draw_item; Drawable *drawable; Drawable *other_drawable; - QXLDrawable *qxl_drawable; - QXLDrawable *other_qxl_drawable; if (other->type != TREE_ITEM_TYPE_DRAWABLE) { return FALSE; @@ -2942,9 +3059,6 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI drawable = CONTAINEROF(item, Drawable, tree_item); other_drawable = CONTAINEROF(other_draw_item, Drawable, tree_item); - qxl_drawable = drawable->qxl_drawable; - other_qxl_drawable = other_drawable->qxl_drawable; - if (item->effect == QXL_EFFECT_OPAQUE) { int add_after = !!other_drawable->stream; red_stream_maintenance(worker, drawable, other_drawable); @@ -2960,7 +3074,7 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI switch (item->effect) { case QXL_EFFECT_REVERT_ON_DUP: - if (is_same_drawable(worker, qxl_drawable, other_qxl_drawable)) { + if (is_same_drawable(worker, drawable, other_drawable)) { if (!ring_item_is_linked(&other_drawable->pipe_item.link)) { red_pipe_add_drawable(worker, drawable); } @@ -2969,7 +3083,7 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI } break; case QXL_EFFECT_OPAQUE_BRUSH: - if (is_same_geometry(worker, qxl_drawable, other_qxl_drawable)) { + if (is_same_geometry(worker, drawable, other_drawable)) { __current_add_drawable(worker, drawable, &other->siblings_link); remove_drawable(worker, other_drawable); red_pipe_add_drawable(worker, drawable); @@ -2977,7 +3091,7 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI } break; case QXL_EFFECT_NOP_ON_DUP: - if (is_same_drawable(worker, qxl_drawable, other_qxl_drawable)) { + if (is_same_drawable(worker, drawable, other_drawable)) { return TRUE; } break; @@ -3268,16 +3382,17 @@ static inline int red_current_add(RedWorker *worker, Drawable *drawable) #endif -static void add_clip_rects(RedWorker *worker, QRegion *rgn, PHYSICAL data) +static void add_clip_rects(RedWorker *worker, QRegion *rgn, PHYSICAL data, uint32_t group_id) { while (data) { QXLDataChunk *chunk; Rect *now; Rect *end; uint32_t data_size; - chunk = (QXLDataChunk *)get_virt(worker, data, sizeof(QXLDataChunk)); + chunk = (QXLDataChunk *)get_virt(worker, data, sizeof(QXLDataChunk), group_id); data_size = chunk->data_size; - validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, data), data_size); + validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, data), data_size, + group_id); now = (Rect *)chunk->data; end = now + data_size / sizeof(Rect); @@ -3386,7 +3501,8 @@ static inline void red_update_streamable(RedWorker *worker, Drawable *drawable, return; } - qxl_image = (QXLImage *)get_virt(worker, qxl_drawable->u.copy.src_bitmap, sizeof(QXLImage)); + qxl_image = (QXLImage *)get_virt(worker, qxl_drawable->u.copy.src_bitmap, sizeof(QXLImage), + drawable->group_id); if (qxl_image->descriptor.type != IMAGE_TYPE_BITMAP) { return; } @@ -3450,24 +3566,23 @@ static void red_get_area(RedWorker *worker, const Rect *area, uint8_t *dest, int red_update_area(worker, area); } - worker->draw_context.read_pixels(worker->draw_context.canvas, dest, dest_stride, area); + worker->draw_funcs.read_pixels(worker->surface.context.canvas, dest, dest_stride, area); } -static inline int red_handle_self_bitmap(RedWorker *worker, QXLDrawable *drawable) +static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable) { QXLImage *image; int32_t width; int32_t height; uint8_t *dest; int dest_stride; - PHYSICAL *addr; - if (!drawable->bitmap_offset) { + if (!drawable->qxl_drawable->self_bitmap) { return TRUE; } - width = drawable->bbox.right - drawable->bbox.left; - height = drawable->bbox.bottom - drawable->bbox.top; + width = drawable->qxl_drawable->bbox.right - drawable->qxl_drawable->bbox.left; + height = drawable->qxl_drawable->bbox.bottom - drawable->qxl_drawable->bbox.top; dest_stride = width * sizeof(uint32_t); if (!(image = malloc(sizeof(QXLImage) + height * dest_stride))) { @@ -3480,7 +3595,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, QXLDrawable *drawabl image->descriptor.flags = 0; QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique); - image->bitmap.flags = QXL_BITMAP_DIRECT | (worker->draw_context.top_down ? + image->bitmap.flags = QXL_BITMAP_DIRECT | (worker->surface.context.top_down ? QXL_BITMAP_TOP_DOWN : 0); image->bitmap.format = BITMAP_FMT_32BIT; image->bitmap.stride = dest_stride; @@ -3489,11 +3604,9 @@ static inline int red_handle_self_bitmap(RedWorker *worker, QXLDrawable *drawabl image->bitmap.data = (PHYSICAL)dest; image->bitmap.palette = 0; - red_get_area(worker, &drawable->bitmap_area, dest, dest_stride, TRUE); + red_get_area(worker, &drawable->qxl_drawable->self_bitmap_area, dest, dest_stride, TRUE); - addr = (PHYSICAL *)((uint8_t *)drawable + drawable->bitmap_offset); - ASSERT(*addr == 0); - *addr = (PHYSICAL)image; + drawable->self_bitmap = (uint8_t *)image; return TRUE; } @@ -3515,8 +3628,8 @@ static void free_one_drawable(RedWorker *worker, int force_glz_free) container_cleanup(worker, container); } -static Drawable *get_drawable(RedWorker *worker, uint8_t effect, QXLDrawable *qxl_drawable) -{ +static Drawable *get_drawable(RedWorker *worker, uint8_t effect, QXLDrawable *qxl_drawable, + uint32_t group_id) { Drawable *drawable; struct timespec time; @@ -3540,15 +3653,21 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, QXLDrawable *qx drawable->tree_item.effect = effect; red_pipe_item_init(&drawable->pipe_item, PIPE_ITEM_TYPE_DRAW); drawable->qxl_drawable = qxl_drawable; + drawable->group_id = group_id; return drawable; } -static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable) +static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable, uint32_t group_id) { - Drawable *item = get_drawable(worker, drawable->effect, drawable); + Drawable *item = get_drawable(worker, drawable->effect, drawable, group_id); ASSERT(item); + PANIC_ON(!worker->surface.context.canvas); + ASSERT(worker->surface.refs != 0); + + worker->surface.refs++; + region_add(&item->tree_item.base.rgn, &drawable->bbox); #ifdef PIPE_DEBUG printf("TEST: DRAWABLE: id %u type %s effect %u bbox %u %u %u %u\n", @@ -3562,7 +3681,7 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable QRegion rgn; region_init(&rgn); - add_clip_rects(worker, &rgn, drawable->clip.data + OFFSETOF(QXLClipRects, chunk)); + add_clip_rects(worker, &rgn, drawable->clip.data + OFFSETOF(QXLClipRects, chunk), group_id); region_and(&item->tree_item.base.rgn, &rgn); region_destroy(&rgn); } else if (drawable->clip.type == CLIP_TYPE_PATH) { @@ -3577,7 +3696,7 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable return; } - if (!red_handle_self_bitmap(worker, drawable)) { + if (!red_handle_self_bitmap(worker, item)) { release_drawable(worker, item); return; } @@ -3589,21 +3708,22 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable } red_pipe_add_drawable(worker, item); #ifdef DRAW_ALL - red_draw_qxl_drawable(worker, drawable); + red_draw_qxl_drawable(worker, item); #endif } release_drawable(worker, item); } -static void localize_path(RedWorker *worker, PHYSICAL *in_path) +static void localize_path(RedWorker *worker, PHYSICAL *in_path, uint32_t group_id) { QXLPath *path; uint8_t *data; uint32_t data_size; QXLDataChunk *chunk; + int memslot_id = get_memslot_id(worker, *in_path); ASSERT(in_path && *in_path); - path = (QXLPath *)get_virt(worker, *in_path, sizeof(QXLPath)); + path = (QXLPath *)get_virt(worker, *in_path, sizeof(QXLPath), group_id); data = malloc(sizeof(UINT32) + path->data_size); ASSERT(data); *in_path = (PHYSICAL)data; @@ -3612,12 +3732,11 @@ static void localize_path(RedWorker *worker, PHYSICAL *in_path) chunk = &path->chunk; do { data_size = chunk->data_size; - validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, *in_path), - data_size); + validate_virt(worker, (unsigned long)chunk->data, memslot_id, data_size, group_id); memcpy(data, chunk->data, data_size); data += data_size; chunk = chunk->next_chunk ? (QXLDataChunk *)get_virt(worker, chunk->next_chunk, - sizeof(QXLDataChunk)) : NULL; + sizeof(QXLDataChunk), group_id) : NULL; } while (chunk); } @@ -3628,13 +3747,14 @@ static void unlocalize_path(PHYSICAL *path) *path = 0; } -static void localize_str(RedWorker *worker, PHYSICAL *in_str) +static void localize_str(RedWorker *worker, PHYSICAL *in_str, uint32_t group_id) { - QXLString *qxl_str = (QXLString *)get_virt(worker, *in_str, sizeof(QXLString)); + QXLString *qxl_str = (QXLString *)get_virt(worker, *in_str, sizeof(QXLString), group_id); QXLDataChunk *chunk; String *str; uint8_t *dest; uint32_t data_size; + int memslot_id = get_memslot_id(worker, *in_str); ASSERT(in_str); str = malloc(sizeof(UINT32) + qxl_str->data_size); @@ -3645,15 +3765,18 @@ static void localize_str(RedWorker *worker, PHYSICAL *in_str) dest = str->data; chunk = &qxl_str->chunk; for (;;) { + PHYSICAL next_chunk; + data_size = chunk->data_size; - validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, *in_str), - data_size); + validate_virt(worker, (unsigned long)chunk->data, memslot_id, data_size, group_id); memcpy(dest, chunk->data, data_size); if (!chunk->next_chunk) { return; } dest += data_size; - chunk = (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk)); + next_chunk = chunk->next_chunk; + memslot_id = get_memslot_id(worker, next_chunk); + chunk = (QXLDataChunk *)get_virt(worker, next_chunk, sizeof(QXLDataChunk), group_id); } } @@ -3664,7 +3787,7 @@ static void unlocalize_str(PHYSICAL *str) *str = 0; } -static void localize_clip(RedWorker *worker, Clip *clip) +static void localize_clip(RedWorker *worker, Clip *clip, uint32_t group_id) { switch (clip->type) { case CLIP_TYPE_NONE: @@ -3672,9 +3795,10 @@ static void localize_clip(RedWorker *worker, Clip *clip) case CLIP_TYPE_RECTS: { QXLClipRects *clip_rects; QXLDataChunk *chunk; + int memslot_id = get_memslot_id(worker, clip->data); uint8_t *data; uint32_t data_size; - clip_rects = (QXLClipRects *)get_virt(worker, clip->data, sizeof(QXLClipRects)); + clip_rects = (QXLClipRects *)get_virt(worker, clip->data, sizeof(QXLClipRects), group_id); chunk = &clip_rects->chunk; ASSERT(clip->data); data = malloc(sizeof(UINT32) + clip_rects->num_rects * sizeof(Rect)); @@ -3684,17 +3808,17 @@ static void localize_clip(RedWorker *worker, Clip *clip) data += sizeof(UINT32); do { data_size = chunk->data_size; - validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, clip->data), - data_size); + validate_virt(worker, (unsigned long)chunk->data, memslot_id, data_size, group_id); memcpy(data, chunk->data, data_size); data += data_size; chunk = chunk->next_chunk ? (QXLDataChunk *)get_virt(worker, chunk->next_chunk, - sizeof(QXLDataChunk)) : NULL; + sizeof(QXLDataChunk), group_id) : + NULL; } while (chunk); break; } case CLIP_TYPE_PATH: - localize_path(worker, &clip->data); + localize_path(worker, &clip->data, group_id); break; default: red_printf("invalid clip type"); @@ -3854,13 +3978,13 @@ static void image_cache_eaging(ImageCache *cache) #endif } -static void localize_bitmap(RedWorker *worker, PHYSICAL *in_bitmap) +static void localize_bitmap(RedWorker *worker, PHYSICAL *in_bitmap, uint32_t group_id) { QXLImage *image; QXLImage *local_image; ASSERT(in_bitmap && *in_bitmap); - image = (QXLImage *)get_virt(worker, *in_bitmap, sizeof(QXLImage)); + image = (QXLImage *)get_virt(worker, *in_bitmap, sizeof(QXLImage), group_id); local_image = (QXLImage *)alloc_local_image(worker); *local_image = *image; *in_bitmap = (PHYSICAL)local_image; @@ -3888,7 +4012,8 @@ static void localize_bitmap(RedWorker *worker, PHYSICAL *in_bitmap) case IMAGE_TYPE_BITMAP: if (image->bitmap.flags & QXL_BITMAP_DIRECT) { local_image->bitmap.data = (PHYSICAL)get_virt(worker, image->bitmap.data, - image->bitmap.stride * image->bitmap.y); + image->bitmap.stride * image->bitmap.y, + group_id); } else { PHYSICAL src_data; int size = image->bitmap.y * image->bitmap.stride; @@ -3903,10 +4028,10 @@ static void localize_bitmap(RedWorker *worker, PHYSICAL *in_bitmap) int cp_size; ASSERT(src_data); - chunk = (QXLDataChunk *)get_virt(worker, src_data, sizeof(QXLDataChunk)); + chunk = (QXLDataChunk *)get_virt(worker, src_data, sizeof(QXLDataChunk), group_id); data_size = chunk->data_size; validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, src_data), - data_size); + data_size, group_id); cp_size = MIN(data_size, size); memcpy(data, chunk->data, cp_size); data += cp_size; @@ -3922,12 +4047,14 @@ static void localize_bitmap(RedWorker *worker, PHYSICAL *in_bitmap) Palette *shadow_palette; int slot_id = get_memslot_id(worker, local_image->bitmap.palette); - tmp_palette = (Palette *)get_virt(worker, local_image->bitmap.palette, sizeof(Palette)); + tmp_palette = (Palette *)get_virt(worker, local_image->bitmap.palette, + sizeof(Palette), group_id); num_ents = tmp_palette->num_ents; ents = tmp_palette->ents; - validate_virt(worker, (unsigned long)ents, slot_id, (num_ents * sizeof(uint32_t))); + validate_virt(worker, (unsigned long)ents, slot_id, (num_ents * sizeof(uint32_t)), + group_id); shadow_palette = (Palette *)malloc(sizeof(Palette) + num_ents * sizeof(uint32_t) + sizeof(PHYSICAL)); @@ -3973,10 +4100,10 @@ static void unlocalize_bitmap(PHYSICAL *bitmap) } } -static void localize_brush(RedWorker *worker, Brush *brush) +static void localize_brush(RedWorker *worker, Brush *brush, uint32_t group_id) { if (brush->type == BRUSH_TYPE_PATTERN) { - localize_bitmap(worker, &brush->u.pattern.pat); + localize_bitmap(worker, &brush->u.pattern.pat, group_id); } } @@ -3987,10 +4114,10 @@ static void unlocalize_brush(Brush *brush) } } -static void localize_mask(RedWorker *worker, QMask *mask) +static void localize_mask(RedWorker *worker, QMask *mask, uint32_t group_id) { if (mask->bitmap) { - localize_bitmap(worker, &mask->bitmap); + localize_bitmap(worker, &mask->bitmap, group_id); } } @@ -4001,14 +4128,15 @@ static void unlocalize_mask(QMask *mask) } } -static void localize_attr(RedWorker *worker, LineAttr *attr) +static void localize_attr(RedWorker *worker, LineAttr *attr, uint32_t group_id) { if (attr->style_nseg) { uint8_t *buf; uint8_t *data; ASSERT(attr->style); - buf = (uint8_t *)get_virt(worker, attr->style, attr->style_nseg * sizeof(uint32_t)); + buf = (uint8_t *)get_virt(worker, attr->style, attr->style_nseg * sizeof(uint32_t), + group_id); data = malloc(attr->style_nseg * sizeof(uint32_t)); ASSERT(data); memcpy(data, buf, attr->style_nseg * sizeof(uint32_t)); @@ -4024,129 +4152,133 @@ static void unlocalize_attr(LineAttr *attr) } } -static void red_draw_qxl_drawable(RedWorker *worker, QXLDrawable *drawable) +static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable) { - Clip clip = drawable->clip; + Clip clip = drawable->qxl_drawable->clip; worker->local_images_pos = 0; image_cache_eaging(&worker->image_cache); - localize_clip(worker, &clip); - switch (drawable->type) { + worker->preload_group_id = drawable->group_id; + + localize_clip(worker, &clip, drawable->group_id); + switch (drawable->qxl_drawable->type) { case QXL_DRAW_FILL: { - Fill fill = drawable->u.fill; - localize_brush(worker, &fill.brush); - localize_mask(worker, &fill.mask); - worker->draw_context.draw_fill(worker->draw_context.canvas, &drawable->bbox, &clip, &fill); - unlocalize_mask(&fill.mask); + Fill fill = drawable->qxl_drawable->u.fill; + localize_brush(worker, &fill.brush, drawable->group_id); + localize_mask(worker, &fill.mask, drawable->group_id); + worker->draw_funcs.draw_fill(worker->surface.context.canvas, &drawable->qxl_drawable->bbox, + &clip, &fill); unlocalize_mask(&fill.mask); unlocalize_brush(&fill.brush); break; } case QXL_DRAW_OPAQUE: { - Opaque opaque = drawable->u.opaque; - localize_brush(worker, &opaque.brush); - localize_bitmap(worker, &opaque.src_bitmap); - localize_mask(worker, &opaque.mask); - worker->draw_context.draw_opaque(worker->draw_context.canvas, &drawable->bbox, &clip, - &opaque); + Opaque opaque = drawable->qxl_drawable->u.opaque; + localize_brush(worker, &opaque.brush, drawable->group_id); + localize_bitmap(worker, &opaque.src_bitmap, drawable->group_id); + localize_mask(worker, &opaque.mask, drawable->group_id); + worker->draw_funcs.draw_opaque(worker->surface.context.canvas, + &drawable->qxl_drawable->bbox, &clip, &opaque); unlocalize_mask(&opaque.mask); unlocalize_bitmap(&opaque.src_bitmap); unlocalize_brush(&opaque.brush); break; } case QXL_DRAW_COPY: { - Copy copy = drawable->u.copy; - localize_bitmap(worker, ©.src_bitmap); - localize_mask(worker, ©.mask); - worker->draw_context.draw_copy(worker->draw_context.canvas, &drawable->bbox, &clip, ©); + Copy copy = drawable->qxl_drawable->u.copy; + localize_bitmap(worker, ©.src_bitmap, drawable->group_id); + localize_mask(worker, ©.mask, drawable->group_id); + worker->draw_funcs.draw_copy(worker->surface.context.canvas, &drawable->qxl_drawable->bbox, + &clip, ©); unlocalize_mask(©.mask); unlocalize_bitmap(©.src_bitmap); break; } case QXL_DRAW_TRANSPARENT: { - Transparent transparent = drawable->u.transparent; - localize_bitmap(worker, &transparent.src_bitmap); - worker->draw_context.draw_transparent(worker->draw_context.canvas, &drawable->bbox, &clip, - &transparent); + Transparent transparent = drawable->qxl_drawable->u.transparent; + localize_bitmap(worker, &transparent.src_bitmap, drawable->group_id); + worker->draw_funcs.draw_transparent(worker->surface.context.canvas, + &drawable->qxl_drawable->bbox, &clip, &transparent); unlocalize_bitmap(&transparent.src_bitmap); break; } case QXL_DRAW_ALPHA_BLEND: { - AlphaBlnd alpha_blend = drawable->u.alpha_blend; - localize_bitmap(worker, &alpha_blend.src_bitmap); - worker->draw_context.draw_alpha_blend(worker->draw_context.canvas, &drawable->bbox, &clip, - &alpha_blend); + AlphaBlnd alpha_blend = drawable->qxl_drawable->u.alpha_blend; + localize_bitmap(worker, &alpha_blend.src_bitmap, drawable->group_id); + worker->draw_funcs.draw_alpha_blend(worker->surface.context.canvas, + &drawable->qxl_drawable->bbox, &clip, &alpha_blend); unlocalize_bitmap(&alpha_blend.src_bitmap); break; } case QXL_COPY_BITS: { - worker->draw_context.copy_bits(worker->draw_context.canvas, &drawable->bbox, &clip, - &drawable->u.copy_bits.src_pos); + worker->draw_funcs.copy_bits(worker->surface.context.canvas, &drawable->qxl_drawable->bbox, + &clip, &drawable->qxl_drawable->u.copy_bits.src_pos); break; } case QXL_DRAW_BLEND: { - Blend blend = drawable->u.blend; - localize_bitmap(worker, &blend.src_bitmap); - localize_mask(worker, &blend.mask); - worker->draw_context.draw_blend(worker->draw_context.canvas, &drawable->bbox, &clip, - &blend); + Blend blend = drawable->qxl_drawable->u.blend; + localize_bitmap(worker, &blend.src_bitmap, drawable->group_id); + localize_mask(worker, &blend.mask, drawable->group_id); + worker->draw_funcs.draw_blend(worker->surface.context.canvas, &drawable->qxl_drawable->bbox, + &clip, &blend); unlocalize_mask(&blend.mask); unlocalize_bitmap(&blend.src_bitmap); break; } case QXL_DRAW_BLACKNESS: { - Blackness blackness = drawable->u.blackness; - localize_mask(worker, &blackness.mask); - worker->draw_context.draw_blackness(worker->draw_context.canvas, &drawable->bbox, &clip, - &blackness); + Blackness blackness = drawable->qxl_drawable->u.blackness; + localize_mask(worker, &blackness.mask, drawable->group_id); + worker->draw_funcs.draw_blackness(worker->surface.context.canvas, + &drawable->qxl_drawable->bbox, &clip, &blackness); unlocalize_mask(&blackness.mask); break; } case QXL_DRAW_WHITENESS: { - Whiteness whiteness = drawable->u.whiteness; - localize_mask(worker, &whiteness.mask); - worker->draw_context.draw_whiteness(worker->draw_context.canvas, &drawable->bbox, &clip, - &whiteness); + Whiteness whiteness = drawable->qxl_drawable->u.whiteness; + localize_mask(worker, &whiteness.mask, drawable->group_id); + worker->draw_funcs.draw_whiteness(worker->surface.context.canvas, + &drawable->qxl_drawable->bbox, &clip, &whiteness); unlocalize_mask(&whiteness.mask); break; } case QXL_DRAW_INVERS: { - Invers invers = drawable->u.invers; - localize_mask(worker, &invers.mask); - worker->draw_context.draw_invers(worker->draw_context.canvas, &drawable->bbox, &clip, - &invers); + Invers invers = drawable->qxl_drawable->u.invers; + localize_mask(worker, &invers.mask, drawable->group_id); + worker->draw_funcs.draw_invers(worker->surface.context.canvas, + &drawable->qxl_drawable->bbox, &clip, &invers); unlocalize_mask(&invers.mask); break; } case QXL_DRAW_ROP3: { - Rop3 rop3 = drawable->u.rop3; - localize_brush(worker, &rop3.brush); - localize_bitmap(worker, &rop3.src_bitmap); - localize_mask(worker, &rop3.mask); - worker->draw_context.draw_rop3(worker->draw_context.canvas, &drawable->bbox, &clip, &rop3); - unlocalize_mask(&rop3.mask); + Rop3 rop3 = drawable->qxl_drawable->u.rop3; + localize_brush(worker, &rop3.brush, drawable->group_id); + localize_bitmap(worker, &rop3.src_bitmap, drawable->group_id); + localize_mask(worker, &rop3.mask, drawable->group_id); + worker->draw_funcs.draw_rop3(worker->surface.context.canvas, &drawable->qxl_drawable->bbox, + &clip, &rop3); unlocalize_mask(&rop3.mask); unlocalize_bitmap(&rop3.src_bitmap); unlocalize_brush(&rop3.brush); break; } case QXL_DRAW_STROKE: { - Stroke stroke = drawable->u.stroke; - localize_brush(worker, &stroke.brush); - localize_path(worker, &stroke.path); - localize_attr(worker, &stroke.attr); - worker->draw_context.draw_stroke(worker->draw_context.canvas, &drawable->bbox, &clip, - &stroke); + Stroke stroke = drawable->qxl_drawable->u.stroke; + localize_brush(worker, &stroke.brush, drawable->group_id); + localize_path(worker, &stroke.path, drawable->group_id); + localize_attr(worker, &stroke.attr, drawable->group_id); + worker->draw_funcs.draw_stroke(worker->surface.context.canvas, + &drawable->qxl_drawable->bbox, &clip, &stroke); unlocalize_attr(&stroke.attr); unlocalize_path(&stroke.path); unlocalize_brush(&stroke.brush); break; } case QXL_DRAW_TEXT: { - Text text = drawable->u.text; - localize_brush(worker, &text.fore_brush); - localize_brush(worker, &text.back_brush); - localize_str(worker, &text.str); - worker->draw_context.draw_text(worker->draw_context.canvas, &drawable->bbox, &clip, &text); + Text text = drawable->qxl_drawable->u.text; + localize_brush(worker, &text.fore_brush, drawable->group_id); + localize_brush(worker, &text.back_brush, drawable->group_id); + localize_str(worker, &text.str, drawable->group_id); + worker->draw_funcs.draw_text(worker->surface.context.canvas, &drawable->qxl_drawable->bbox, + &clip, &text); unlocalize_str(&text.str); unlocalize_brush(&text.back_brush); unlocalize_brush(&text.fore_brush); @@ -4164,13 +4296,13 @@ static void red_draw_drawable(RedWorker *worker, Drawable *drawable) { #ifdef UPDATE_AREA_BY_TREE //todo: add need top mask flag - worker->draw_context.set_top_mask(worker->draw_context.canvas, - drawable->tree_item.base.rgn.num_rects, - drawable->tree_item.base.rgn.rects); + worker->draw_funcs.set_top_mask(worker->surface.context.canvas, + drawable->tree_item.base.rgn.num_rects, + drawable->tree_item.base.rgn.rects); #endif - red_draw_qxl_drawable(worker, drawable->qxl_drawable); + red_draw_qxl_drawable(worker, drawable); #ifdef UPDATE_AREA_BY_TREE - worker->draw_context.clear_top_mask(worker->draw_context.canvas); + worker->draw_funcs.clear_top_mask(worker->surface.context.canvas); #endif } @@ -4231,8 +4363,8 @@ static void red_update_area(RedWorker *worker, const Rect *area) QRegion rgn; if (!(ring_item = ring_get_head(ring))) { - worker->draw_context.validate_area(worker->draw_context.canvas, &worker->dev_info.draw_area, - area); + worker->draw_context.validate_area(worker->draw_context.canvas, + &worker->dev_info.surface0_area, area); return; } @@ -4252,8 +4384,8 @@ static void red_update_area(RedWorker *worker, const Rect *area) current_remove_drawable(worker, drawable); container_cleanup(worker, container); } - worker->draw_context.validate_area(worker->draw_context.canvas, &worker->dev_info.draw_area, - area); + worker->draw_funcs.validate_area(worker->surface.context.canvas, worker->surface.context.stride, + worker->surface.context.line_0, area); } #else @@ -4278,8 +4410,9 @@ static void red_update_area(RedWorker *worker, const Rect *area) region_destroy(&rgn); if (!last) { - worker->draw_context.validate_area(worker->draw_context.canvas, &worker->dev_info.draw_area, - area); + worker->draw_funcs.validate_area(worker->surface.context.canvas, + worker->surface.context.stride, + worker->surface.context.line_0, area); return; } @@ -4293,25 +4426,32 @@ static void red_update_area(RedWorker *worker, const Rect *area) current_remove_drawable(worker, now); container_cleanup(worker, container); } while (now != last); - worker->draw_context.validate_area(worker->draw_context.canvas, &worker->dev_info.draw_area, - area); + worker->draw_funcs.validate_area(worker->surface.context.canvas, worker->surface.context.stride, + worker->surface.context.line_0, area); } #endif #endif +static inline void free_cursor_item(RedWorker *worker, CursorItem *item); + static void red_release_cursor(RedWorker *worker, CursorItem *cursor) { if (!--cursor->refs) { + QXLReleaseInfoExt release_info_ext; QXLCursorCmd *cursor_cmd; if (cursor->type == CURSOR_TYPE_LOCAL) { free(cursor); return; } - cursor_cmd = CONTAINEROF(cursor, QXLCursorCmd, device_data); - worker->qxl->release_resource(worker->qxl, &cursor_cmd->release_info); + + cursor_cmd = cursor->qxl_cursor; + release_info_ext.group_id = cursor->group_id; + release_info_ext.info = &cursor_cmd->release_info; + worker->qxl->release_resource(worker->qxl, release_info_ext); + free_cursor_item(worker, cursor); } } @@ -4324,14 +4464,52 @@ static void red_set_cursor(RedWorker *worker, CursorItem *cursor) worker->cursor = cursor; } -void qxl_process_cursor(RedWorker *worker, QXLCursorCmd *cursor_cmd) +static inline CursorItem *alloc_cursor_item(RedWorker *worker) { - CursorItem *item = (CursorItem *)cursor_cmd->device_data; - int cursor_show = FALSE; + CursorItem *cursor; + if (!worker->free_cursor_items) { + return NULL; + } + cursor = &worker->free_cursor_items->u.cursor_item; + worker->free_cursor_items = worker->free_cursor_items->u.next; + return cursor; +} - red_pipe_item_init(&item->pipe_data, PIPE_ITEM_TYPE_CURSOR); - item->refs = 1; - item->type = CURSOR_TYPE_INVALID; +static inline void free_cursor_item(RedWorker *worker, CursorItem *item) +{ + ((_CursorItem *)item)->u.next = worker->free_cursor_items; + worker->free_cursor_items = (_CursorItem *)item; +} + +static void cursor_items_init(RedWorker *worker) +{ + int i; + + worker->free_cursor_items = NULL; + for (i = 0; i < NUM_CURSORS; i++) { + free_cursor_item(worker, &worker->cursor_items[i].u.cursor_item); + } +} + +static CursorItem *get_cursor_item(RedWorker *worker, QXLCursorCmd *cmd, uint32_t group_id) +{ + CursorItem *cursor_item; + + PANIC_ON(!(cursor_item = alloc_cursor_item(worker))); + + cursor_item->refs = 1; + red_pipe_item_init(&cursor_item->pipe_data, PIPE_ITEM_TYPE_CURSOR); + cursor_item->type = CURSOR_TYPE_INVALID; + cursor_item->group_id = group_id; + cursor_item->qxl_cursor = cmd; + + return cursor_item; +} + +void qxl_process_cursor(RedWorker *worker, QXLCursorCmd *cursor_cmd, uint32_t group_id) +{ + CursorItem *item = get_cursor_item(worker, cursor_cmd, group_id); + int cursor_show = FALSE; switch (cursor_cmd->type) { case QXL_CURSOR_SET: @@ -4374,11 +4552,11 @@ static inline uint64_t red_now() static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size) { - QXLCommand cmd; + QXLCommandExt ext_cmd; int n = 0; while (!worker->cursor_channel || worker->cursor_channel->base.pipe_size <= max_pipe_size) { - if (!worker->qxl->get_cursor_command(worker->qxl, &cmd)) { + if (!worker->qxl->get_cursor_command(worker->qxl, &ext_cmd)) { if (worker->repoll_cursor_ring < CMD_RING_POLL_RETRIES) { worker->repoll_cursor_ring++; worker->epoll_timeout = MIN(worker->epoll_timeout, CMD_RING_POLL_TIMEOUT); @@ -4392,11 +4570,12 @@ static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size) continue; } worker->repoll_cursor_ring = 0; - switch (cmd.type) { + switch (ext_cmd.cmd.type) { case QXL_CMD_CURSOR: { - QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)get_virt(worker, cmd.data, - sizeof(QXLCursorCmd)); - qxl_process_cursor(worker, cursor_cmd); + QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)get_virt(worker, ext_cmd.cmd.data, + sizeof(QXLCursorCmd), + ext_cmd.group_id); + qxl_process_cursor(worker, cursor_cmd, ext_cmd.group_id); break; } default: @@ -4409,12 +4588,12 @@ static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size) static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size) { - QXLCommand cmd; + QXLCommandExt ext_cmd; int n = 0; uint64_t start = red_now(); while (!worker->display_channel || worker->display_channel->base.pipe_size <= max_pipe_size) { - if (!worker->qxl->get_command(worker->qxl, &cmd)) { + if (!worker->qxl->get_command(worker->qxl, &ext_cmd)) { if (worker->repoll_cmd_ring < CMD_RING_POLL_RETRIES) { worker->repoll_cmd_ring++; worker->epoll_timeout = MIN(worker->epoll_timeout, CMD_RING_POLL_TIMEOUT); @@ -4429,30 +4608,33 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size) } stat_inc_counter(worker->command_counter, 1); worker->repoll_cmd_ring = 0; - switch (cmd.type) { + switch (ext_cmd.cmd.type) { case QXL_CMD_DRAW: { - QXLDrawable *drawable = (QXLDrawable *)get_virt(worker, cmd.data, sizeof(QXLDrawable)); - red_process_drawable(worker, drawable); + QXLDrawable *drawable = (QXLDrawable *)get_virt(worker, ext_cmd.cmd.data, + sizeof(QXLDrawable), ext_cmd.group_id); + red_process_drawable(worker, drawable, ext_cmd.group_id); break; } case QXL_CMD_UPDATE: { - QXLUpdateCmd *draw_cmd = (QXLUpdateCmd *)get_virt(worker, cmd.data, - sizeof(QXLUpdateCmd)); + QXLReleaseInfoExt release_info_ext; + QXLUpdateCmd *draw_cmd = (QXLUpdateCmd *)get_virt(worker, ext_cmd.cmd.data, + sizeof(QXLUpdateCmd), + ext_cmd.group_id); red_update_area(worker, &draw_cmd->area); worker->qxl->notify_update(worker->qxl, draw_cmd->update_id); - worker->qxl->release_resource(worker->qxl, &draw_cmd->release_info); - break; - } - case QXL_CMD_CURSOR: { - QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)get_virt(worker, cmd.data, - sizeof(QXLCursorCmd)); - qxl_process_cursor(worker, cursor_cmd); + release_info_ext.group_id = ext_cmd.group_id; + release_info_ext.info = &draw_cmd->release_info; + worker->qxl->release_resource(worker->qxl, release_info_ext); break; } case QXL_CMD_MESSAGE: { - QXLMessage *message = (QXLMessage *)get_virt(worker, cmd.data, sizeof(QXLMessage)); + QXLReleaseInfoExt release_info_ext; + QXLMessage *message = (QXLMessage *)get_virt(worker, ext_cmd.cmd.data, + sizeof(QXLMessage), ext_cmd.group_id); red_printf("MESSAGE: %s", message->data); - worker->qxl->release_resource(worker->qxl, &message->release_info); + release_info_ext.group_id = ext_cmd.group_id; + release_info_ext.info = &message->release_info; + worker->qxl->release_resource(worker->qxl, release_info_ext); break; } default: @@ -4504,11 +4686,13 @@ static void red_add_screen_image(RedWorker *worker) int stride; Rect area; - if (!worker->display_channel) { + if (!worker->display_channel || !worker->surface.context.canvas) { return; } - stride = worker->dev_info.x_res << 2; - if (!(item = (ImageItem *)malloc(sizeof(ImageItem) + worker->dev_info.y_res * stride))) { + + stride = worker->surface.context.width << 2; + if (!(item = (ImageItem *)malloc(sizeof(ImageItem) + + worker->surface.context.height * stride))) { //warn return; } @@ -4517,22 +4701,22 @@ static void red_add_screen_image(RedWorker *worker) item->refs = 1; item->pos.x = item->pos.y = 0; - item->width = worker->dev_info.x_res; - item->height = worker->dev_info.y_res; + item->width = worker->surface.context.width; + item->height = worker->surface.context.height; item->stride = stride; - item->top_down = worker->draw_context.top_down; + item->top_down = worker->surface.context.top_down; area.top = area.left = 0; - area.right = worker->dev_info.x_res; - area.bottom = worker->dev_info.y_res; - worker->draw_context.read_pixels(worker->draw_context.canvas, item->data, stride, &area); + area.right = worker->surface.context.width; + area.bottom = worker->surface.context.height; + worker->draw_funcs.read_pixels(worker->surface.context.canvas, item->data, stride, &area); red_pipe_add_image_item(worker, item); release_image_item(item); display_channel_push(worker); } static void inline __add_buf(RedChannel *channel, uint32_t type, void *data, uint32_t size, - uint32_t slot_id) + uint32_t slot_id, uint32_t group_id) { int pos = channel->send_data.n_bufs++; ASSERT(pos < MAX_SEND_BUFS); @@ -4540,65 +4724,70 @@ static void inline __add_buf(RedChannel *channel, uint32_t type, void *data, uin channel->send_data.bufs[pos].size = size; channel->send_data.bufs[pos].data = data; channel->send_data.bufs[pos].slot_id = slot_id; + channel->send_data.bufs[pos].group_id = group_id; } static void add_buf(RedChannel *channel, uint32_t type, void *data, uint32_t size, - uint32_t slot_id) + uint32_t slot_id, uint32_t group_id) { - __add_buf(channel, type, data, size, slot_id); + __add_buf(channel, type, data, size, slot_id, group_id); channel->send_data.header.size += size; } -static void fill_path(DisplayChannel *display_channel, PHYSICAL *in_path) +static void fill_path(DisplayChannel *display_channel, PHYSICAL *in_path, uint32_t group_id) { RedWorker *worker; RedChannel *channel = &display_channel->base; + int memslot_id; worker = channel->worker; ASSERT(in_path && *in_path); - QXLPath *path = (QXLPath *)get_virt(worker, *in_path, sizeof(QXLPath)); + memslot_id = get_memslot_id(worker, *in_path); + QXLPath *path = (QXLPath *)get_virt(worker, *in_path, sizeof(QXLPath), group_id); *in_path = channel->send_data.header.size; - add_buf(channel, BUF_TYPE_RAW, &path->data_size, sizeof(UINT32), 0); - add_buf(channel, BUF_TYPE_CHUNK, &path->chunk, path->data_size, - get_memslot_id(worker, *in_path)); + add_buf(channel, BUF_TYPE_RAW, &path->data_size, sizeof(UINT32), 0, 0); + add_buf(channel, BUF_TYPE_CHUNK, &path->chunk, path->data_size, memslot_id, group_id); } -static void fill_str(DisplayChannel *display_channel, PHYSICAL *in_str) +static void fill_str(DisplayChannel *display_channel, PHYSICAL *in_str, uint32_t group_id) { RedWorker *worker; RedChannel *channel = &display_channel->base; + int memslot_id; worker = channel->worker; ASSERT(in_str && *in_str); - QXLString *str = (QXLString *)get_virt(worker, *in_str, sizeof(QXLString)); + memslot_id = get_memslot_id(worker, *in_str); + QXLString *str = (QXLString *)get_virt(worker, *in_str, sizeof(QXLString), group_id); *in_str = channel->send_data.header.size; - add_buf(channel, BUF_TYPE_RAW, &str->length, sizeof(UINT32), 0); - add_buf(channel, BUF_TYPE_CHUNK, &str->chunk, str->data_size, get_memslot_id(worker, *in_str)); + add_buf(channel, BUF_TYPE_RAW, &str->length, sizeof(UINT32), 0, 0); + add_buf(channel, BUF_TYPE_CHUNK, &str->chunk, str->data_size, memslot_id, group_id); } -static inline void fill_rects_clip(RedChannel *channel, PHYSICAL *in_clip) +static inline void fill_rects_clip(RedChannel *channel, PHYSICAL *in_clip, uint32_t group_id) { RedWorker *worker = channel->worker; QXLClipRects *clip; + int memslot_id = get_memslot_id(worker, *in_clip); ASSERT(in_clip && *in_clip); - clip = (QXLClipRects *)get_virt(worker, *in_clip, sizeof(QXLClipRects)); + clip = (QXLClipRects *)get_virt(worker, *in_clip, sizeof(QXLClipRects), group_id); *in_clip = channel->send_data.header.size; - add_buf(channel, BUF_TYPE_RAW, &clip->num_rects, sizeof(UINT32), 0); - add_buf(channel, BUF_TYPE_CHUNK, &clip->chunk, clip->num_rects * sizeof(Rect), - get_memslot_id(worker, *in_clip)); + add_buf(channel, BUF_TYPE_RAW, &clip->num_rects, sizeof(UINT32), 0, 0); + add_buf(channel, BUF_TYPE_CHUNK, &clip->chunk, clip->num_rects * sizeof(Rect), memslot_id, + group_id); } -static void fill_base(DisplayChannel *display_channel, RedDrawBase *base, QXLDrawable *drawable, +static void fill_base(DisplayChannel *display_channel, RedDrawBase *base, Drawable *drawable, uint32_t size) { RedChannel *channel = &display_channel->base; - add_buf(channel, BUF_TYPE_RAW, base, size, 0); - base->box = drawable->bbox; - base->clip = drawable->clip; + add_buf(channel, BUF_TYPE_RAW, base, size, 0, 0); + base->box = drawable->qxl_drawable->bbox; + base->clip = drawable->qxl_drawable->clip; if (base->clip.type == CLIP_TYPE_RECTS) { - fill_rects_clip(channel, &base->clip.data); + fill_rects_clip(channel, &base->clip.data, drawable->group_id); } else if (base->clip.type == CLIP_TYPE_PATH) { - fill_path(display_channel, &base->clip.data); + fill_path(display_channel, &base->clip.data, drawable->group_id); } } @@ -4609,7 +4798,8 @@ static inline RedImage *alloc_image(DisplayChannel *display_channel) } /* io_palette is relative address of the palette*/ -static inline void fill_palette(DisplayChannel *display_channel, ADDRESS *io_palette, UINT8 *flags) +static inline void fill_palette(DisplayChannel *display_channel, ADDRESS *io_palette, UINT8 *flags, + uint32_t group_id) { RedChannel *channel = &display_channel->base; RedWorker *worker = channel->worker; @@ -4618,7 +4808,7 @@ static inline void fill_palette(DisplayChannel *display_channel, ADDRESS *io_pal if (!(*io_palette)) { return; } - palette = (Palette *)get_virt(worker, *io_palette, sizeof(Palette)); + palette = (Palette *)get_virt(worker, *io_palette, sizeof(Palette), group_id); if (palette->unique) { if (red_palette_cache_find(display_channel, palette->unique)) { *flags |= BITMAP_PAL_FROM_CACHE; @@ -4631,7 +4821,7 @@ static inline void fill_palette(DisplayChannel *display_channel, ADDRESS *io_pal } *io_palette = channel->send_data.header.size; add_buf(channel, BUF_TYPE_RAW, palette, - sizeof(Palette) + palette->num_ents * sizeof(UINT32), 0); + sizeof(Palette) + palette->num_ents * sizeof(UINT32), 0, 0); } static inline RedCompressBuf *red_display_alloc_compress_buf(DisplayChannel *display_channel) @@ -4705,6 +4895,8 @@ static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannel *channel, Dra ret->display_channel = channel; ret->qxl_drawable = drawable->qxl_drawable; ret->drawable = drawable; + ret->group_id = drawable->group_id; + ret->self_bitmap = drawable->self_bitmap; ret->instances_count = 0; ring_init(&ret->instances); @@ -4768,7 +4960,8 @@ static void red_display_free_glz_drawable_instance(DisplayChannel *channel, if (drawable) { drawable->red_glz_drawable = NULL; } else { // no reference to the qxl drawable left - free_qxl_drawable(channel->base.worker, glz_drawable->qxl_drawable); + free_qxl_drawable(channel->base.worker, glz_drawable->qxl_drawable, + glz_drawable->group_id, glz_drawable->self_bitmap); } if (ring_item_is_linked(&glz_drawable->link)) { @@ -5021,7 +5214,7 @@ static inline int encoder_usr_more_lines(EncoderData *enc_data, uint8_t **lines) QXLDataChunk *chunk = (QXLDataChunk *)enc_data->u.lines_data.enc_get_virt( enc_data->u.lines_data.enc_get_virt_opaque, enc_data->u.lines_data.next, - sizeof(QXLDataChunk)); + sizeof(QXLDataChunk), enc_data->u.lines_data.group_id); data_size = chunk->data_size; data = chunk->data; @@ -5032,7 +5225,7 @@ static inline int encoder_usr_more_lines(EncoderData *enc_data, uint8_t **lines) enc_data->u.lines_data.enc_validate_virt(enc_data->u.lines_data.enc_validate_virt_opaque, (unsigned long)data, enc_data->u.lines_data.next, - data_size); + data_size, enc_data->u.lines_data.group_id); enc_data->u.lines_data.next = chunk->next_chunk; *lines = data; @@ -5070,7 +5263,7 @@ static int quic_usr_more_lines_revers(QuicUsrContext *usr, uint8_t **lines) QXLDataChunk *chunk = (QXLDataChunk *)quic_data->u.lines_data.enc_get_virt( quic_data->u.lines_data.enc_get_virt_opaque, quic_data->u.lines_data.next, - sizeof(QXLDataChunk)); + sizeof(QXLDataChunk), quic_data->u.lines_data.group_id); data_size = chunk->data_size; data = chunk->data; @@ -5081,7 +5274,8 @@ static int quic_usr_more_lines_revers(QuicUsrContext *usr, uint8_t **lines) quic_data->u.lines_data.enc_validate_virt(quic_data->u.lines_data.enc_validate_virt_opaque, (unsigned long)data, - quic_data->u.lines_data.next, data_size); + quic_data->u.lines_data.next, data_size, + quic_data->u.lines_data.group_id); quic_data->u.lines_data.next = chunk->prev_chunk; *lines = data + data_size - quic_data->u.lines_data.stride; @@ -5231,7 +5425,7 @@ typedef uint16_t rgb16_pixel_t; #define GRADUAL_SCORE_RGB16_TH 0 // assumes that stride doesn't overflow -static int _bitmap_is_gradual(RedWorker *worker, Bitmap *bitmap) +static int _bitmap_is_gradual(RedWorker *worker, Bitmap *bitmap, uint32_t group_id) { double score = 0.0; int num_samples = 0; @@ -5245,20 +5439,20 @@ static int _bitmap_is_gradual(RedWorker *worker, Bitmap *bitmap) switch (bitmap->format) { case BITMAP_FMT_16BIT: { uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, x * y * - sizeof(rgb16_pixel_t)); + sizeof(rgb16_pixel_t), group_id); compute_lines_gradual_score_rgb16((rgb16_pixel_t*)lines, x, y, &score, &num_samples); break; } case BITMAP_FMT_24BIT: { uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, x * y * - sizeof(rgb24_pixel_t)); + sizeof(rgb24_pixel_t), group_id); compute_lines_gradual_score_rgb24((rgb24_pixel_t*)lines, x, y, &score, &num_samples); break; } case BITMAP_FMT_32BIT: case BITMAP_FMT_RGBA: { uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, x * y * - sizeof(rgb32_pixel_t)); + sizeof(rgb32_pixel_t), group_id); compute_lines_gradual_score_rgb32((rgb32_pixel_t*)lines, x, y, &score, &num_samples); break; } @@ -5274,21 +5468,22 @@ static int _bitmap_is_gradual(RedWorker *worker, Bitmap *bitmap) ADDRESS relative_address = bitmap->data; while (relative_address) { - chunk = (QXLDataChunk *)get_virt(worker, relative_address, sizeof(QXLDataChunk)); + chunk = (QXLDataChunk *)get_virt(worker, relative_address, sizeof(QXLDataChunk), + group_id); num_lines = chunk->data_size / bitmap->stride; x = bitmap->x; switch (bitmap->format) { case BITMAP_FMT_16BIT: validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, relative_address), - sizeof(rgb16_pixel_t) * x * num_lines); + sizeof(rgb16_pixel_t) * x * num_lines, group_id); compute_lines_gradual_score_rgb16((rgb16_pixel_t*)chunk->data, x, num_lines, &chunk_score, &chunk_num_samples); break; case BITMAP_FMT_24BIT: validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, relative_address), - sizeof(rgb24_pixel_t) * x * num_lines); + sizeof(rgb24_pixel_t) * x * num_lines, group_id); compute_lines_gradual_score_rgb24((rgb24_pixel_t*)chunk->data, x, num_lines, &chunk_score, &chunk_num_samples); break; @@ -5296,7 +5491,7 @@ static int _bitmap_is_gradual(RedWorker *worker, Bitmap *bitmap) case BITMAP_FMT_RGBA: validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, relative_address), - sizeof(rgb32_pixel_t) * x * num_lines); + sizeof(rgb32_pixel_t) * x * num_lines, group_id); compute_lines_gradual_score_rgb32((rgb32_pixel_t*)chunk->data, x, num_lines, &chunk_score, &chunk_num_samples); break; @@ -5400,7 +5595,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel, if ((src->flags & QXL_BITMAP_DIRECT)) { glz_data->usr.more_lines = glz_usr_no_more_lines; - lines = (uint8_t*)get_virt(worker, src->data, src->stride * src->y); + lines = (uint8_t*)get_virt(worker, src->data, src->stride * src->y, drawable->group_id); num_lines = src->y; } else { glz_data->data.u.lines_data.enc_get_virt = cb_get_virt; @@ -5409,6 +5604,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel, glz_data->data.u.lines_data.enc_validate_virt_opaque = worker; glz_data->data.u.lines_data.stride = src->stride; glz_data->data.u.lines_data.next = src->data; + glz_data->data.u.lines_data.group_id = drawable->group_id; glz_data->usr.more_lines = glz_usr_more_lines; lines = NULL; num_lines = 0; @@ -5437,7 +5633,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel, static inline int red_lz_compress_image(DisplayChannel *display_channel, RedImage *dest, Bitmap *src, - compress_send_data_t* o_comp_data) + compress_send_data_t* o_comp_data, uint32_t group_id) { RedWorker *worker = display_channel->base.worker; LzData *lz_data = &worker->lz_data; @@ -5471,8 +5667,8 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel, if ((src->flags & QXL_BITMAP_DIRECT)) { lz_data->usr.more_lines = lz_usr_no_more_lines; size = lz_encode(lz, type, src->x, src->y, (src->flags & QXL_BITMAP_TOP_DOWN), - (uint8_t*)get_virt(worker, src->data, src->stride * src->y), src->y, - src->stride, (uint8_t*)lz_data->data.bufs_head->buf, + (uint8_t*)get_virt(worker, src->data, src->stride * src->y, group_id), + src->y, src->stride, (uint8_t*)lz_data->data.bufs_head->buf, sizeof(lz_data->data.bufs_head->buf)); } else { lz_data->data.u.lines_data.enc_get_virt = cb_get_virt; @@ -5481,6 +5677,7 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel, lz_data->data.u.lines_data.enc_validate_virt_opaque = worker; lz_data->data.u.lines_data.stride = src->stride; lz_data->data.u.lines_data.next = src->data; + lz_data->data.u.lines_data.group_id = group_id; lz_data->usr.more_lines = lz_usr_more_lines; size = lz_encode(lz, type, src->x, src->y, (src->flags & QXL_BITMAP_TOP_DOWN), @@ -5521,7 +5718,8 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel, } static inline int red_quic_compress_image(DisplayChannel *display_channel, RedImage *dest, - Bitmap *src, compress_send_data_t* o_comp_data) + Bitmap *src, compress_send_data_t* o_comp_data, + uint32_t group_id) { RedWorker *worker = display_channel->base.worker; QuicData *quic_data = &worker->quic_data; @@ -5574,11 +5772,11 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, RedIm uint8_t *data; if (!(src->flags & QXL_BITMAP_TOP_DOWN)) { - data = (uint8_t*)get_virt(worker, src->data, src->stride * src->y) + + data = (uint8_t*)get_virt(worker, src->data, src->stride * src->y, group_id) + src->stride * (src->y - 1); stride = -src->stride; } else { - data = (uint8_t*)get_virt(worker, src->data, src->stride * src->y); + data = (uint8_t*)get_virt(worker, src->data, src->stride * src->y, group_id); stride = src->stride; } @@ -5619,20 +5817,26 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, RedIm quic_data->data.u.lines_data.enc_validate_virt = cb_validate_virt; quic_data->data.u.lines_data.enc_validate_virt_opaque = worker; quic_data->data.u.lines_data.stride = src->stride; + quic_data->data.u.lines_data.group_id = group_id; if ((src->flags & QXL_BITMAP_TOP_DOWN)) { quic_data->data.u.lines_data.next = src->data; quic_data->usr.more_lines = quic_usr_more_lines; stride = src->stride; } else { - QXLDataChunk *chunk = (QXLDataChunk *)get_virt(worker, src->data, sizeof(QXLDataChunk)); + ADDRESS prev_addr = src->data; + QXLDataChunk *chunk = (QXLDataChunk *)get_virt(worker, src->data, + sizeof(QXLDataChunk), group_id); while (chunk->next_chunk) { - chunk = (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk)); + prev_addr = chunk->next_chunk; + chunk = (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk), + group_id); ASSERT(chunk->prev_chunk); } - quic_data->data.u.lines_data.next = (ADDRESS)chunk - + quic_data->data.u.lines_data.next = (ADDRESS)prev_addr - get_virt_delta(worker, - get_memslot_id(worker, src->data)); + get_memslot_id(worker, src->data), + group_id); quic_data->usr.more_lines = quic_usr_more_lines_revers; stride = -src->stride; } @@ -5699,7 +5903,8 @@ static inline int red_compress_image(DisplayChannel *display_channel, } else { if (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_INVALID) { quic_compress = BITMAP_FMT_IS_RGB[src->format] && - _bitmap_is_gradual(display_channel->base.worker, src); + _bitmap_is_gradual(display_channel->base.worker, src, + drawable->group_id); } else { quic_compress = (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_TRUE); } @@ -5714,7 +5919,7 @@ static inline int red_compress_image(DisplayChannel *display_channel, #ifdef COMPRESS_DEBUG red_printf("QUIC compress"); #endif - return red_quic_compress_image(display_channel, dest, src, o_comp_data); + return red_quic_compress_image(display_channel, dest, src, o_comp_data, drawable->group_id); } else { int glz; int ret; @@ -5743,7 +5948,8 @@ static inline int red_compress_image(DisplayChannel *display_channel, } if (!glz) { - ret = red_lz_compress_image(display_channel, dest, src, o_comp_data); + ret = red_lz_compress_image(display_channel, dest, src, o_comp_data, + drawable->group_id); #ifdef COMPRESS_DEBUG red_printf("LZ LOCAL compress"); #endif @@ -5784,12 +5990,13 @@ static void fill_bits(DisplayChannel *display_channel, PHYSICAL *in_bitmap, Draw RedImage *image; QXLImage *qxl_image; uint8_t *data; + int memslot_id; compress_send_data_t comp_send_data; ASSERT(*in_bitmap); image = alloc_image(display_channel); - qxl_image = (QXLImage *)get_virt(worker, *in_bitmap, sizeof(QXLImage)); + qxl_image = (QXLImage *)get_virt(worker, *in_bitmap, sizeof(QXLImage), drawable->group_id); image->descriptor.id = qxl_image->descriptor.id; image->descriptor.type = qxl_image->descriptor.type; @@ -5797,12 +6004,13 @@ static void fill_bits(DisplayChannel *display_channel, PHYSICAL *in_bitmap, Draw image->descriptor.width = qxl_image->descriptor.width; image->descriptor.height = qxl_image->descriptor.height; + memslot_id = get_memslot_id(worker, *in_bitmap); *in_bitmap = channel->send_data.header.size; if ((qxl_image->descriptor.flags & QXL_IMAGE_CACHE)) { if (pixmap_cache_hit(display_channel->pixmap_cache, image->descriptor.id, display_channel)) { image->descriptor.type = IMAGE_TYPE_FROM_CACHE; - add_buf(channel, BUF_TYPE_RAW, image, sizeof(ImageDescriptor), 0); + add_buf(channel, BUF_TYPE_RAW, image, sizeof(ImageDescriptor), 0, 0); stat_inc_counter(display_channel->cache_hits_counter, 1); return; } @@ -5811,7 +6019,7 @@ static void fill_bits(DisplayChannel *display_channel, PHYSICAL *in_bitmap, Draw switch (qxl_image->descriptor.type) { case IMAGE_TYPE_BITMAP: #ifdef DUMP_BITMAP - dump_bitmap(display_channel->base.worker, &qxl_image->bitmap); + dump_bitmap(display_channel->base.worker, &qxl_image->bitmap, drawable->group_id); #endif /* Images must be added to the cache only after they are compressed in order to prevent starvation in the client between pixmap_cache and @@ -5830,36 +6038,38 @@ static void fill_bits(DisplayChannel *display_channel, PHYSICAL *in_bitmap, Draw image_data = image->bitmap.data; image->bitmap.flags = image->bitmap.flags & BITMAP_TOP_DOWN; - add_buf(channel, BUF_TYPE_RAW, image, sizeof(BitmapImage), 0); - fill_palette(display_channel, &(image->bitmap.palette), &(image->bitmap.flags)); + add_buf(channel, BUF_TYPE_RAW, image, sizeof(BitmapImage), 0, 0); + fill_palette(display_channel, &(image->bitmap.palette), &(image->bitmap.flags), + drawable->group_id); image->bitmap.data = channel->send_data.header.size; if (qxl_image->bitmap.flags & QXL_BITMAP_DIRECT) { - data = (uint8_t *)get_virt(worker, image_data, stride * y); - add_buf(channel, BUF_TYPE_RAW, data, y * stride, 0); + data = (uint8_t *)get_virt(worker, image_data, stride * y, drawable->group_id); + add_buf(channel, BUF_TYPE_RAW, data, y * stride, 0, 0); } else { - data = (uint8_t *)get_virt(worker, image_data, sizeof(QXLDataChunk)); - add_buf(channel, BUF_TYPE_CHUNK, data, y * stride, - get_memslot_id(worker, image_data)); + data = (uint8_t *)get_virt(worker, image_data, sizeof(QXLDataChunk), + drawable->group_id); + add_buf(channel, BUF_TYPE_CHUNK, data, y * stride, memslot_id, drawable->group_id); } } else { red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image); add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, image, comp_send_data.raw_size, - 0); + 0, 0); add_buf((RedChannel *)display_channel, BUF_TYPE_COMPRESS_BUF, - comp_send_data.comp_buf, comp_send_data.comp_buf_size, 0); + comp_send_data.comp_buf, comp_send_data.comp_buf_size, 0, 0); if (comp_send_data.plt_ptr != NULL) { - fill_palette(display_channel, comp_send_data.plt_ptr, comp_send_data.flags_ptr); + fill_palette(display_channel, comp_send_data.plt_ptr, comp_send_data.flags_ptr, + drawable->group_id); } } break; case IMAGE_TYPE_QUIC: red_display_add_image_to_pixmap_cache(display_channel, qxl_image, image); image->quic = qxl_image->quic; - add_buf(channel, BUF_TYPE_RAW, image, sizeof(QUICImage), 0); + add_buf(channel, BUF_TYPE_RAW, image, sizeof(QUICImage), 0, 0); add_buf(channel, BUF_TYPE_CHUNK, qxl_image->quic.data, qxl_image->quic.data_size, - get_memslot_id(worker, *in_bitmap)); + memslot_id, drawable->group_id); break; default: red_error("invalid image type %u", image->descriptor.type); @@ -5887,15 +6097,15 @@ static void fill_mask(DisplayChannel *display_channel, QMask *mask, Drawable *dr } } -static void fill_attr(DisplayChannel *display_channel, LineAttr *attr) +static void fill_attr(DisplayChannel *display_channel, LineAttr *attr, uint32_t group_id) { if (attr->style_nseg) { RedChannel *channel = &display_channel->base; uint8_t *buf = (uint8_t *)get_virt(channel->worker, attr->style, - attr->style_nseg * sizeof(uint32_t)); + attr->style_nseg * sizeof(uint32_t), group_id); ASSERT(attr->style); attr->style = channel->send_data.header.size; - add_buf(channel, BUF_TYPE_RAW, buf, attr->style_nseg * sizeof(uint32_t), 0); + add_buf(channel, BUF_TYPE_RAW, buf, attr->style_nseg * sizeof(uint32_t), 0, 0); } } @@ -5912,9 +6122,9 @@ static void fill_cursor(CursorChannel *cursor_channel, RedCursor *red_cursor, Cu QXLCursorCmd *cursor_cmd; QXLCursor *qxl_cursor; - cursor_cmd = CONTAINEROF(cursor, QXLCursorCmd, device_data); + cursor_cmd = cursor->qxl_cursor; qxl_cursor = (QXLCursor *)get_virt(channel->worker, cursor_cmd->u.set.shape, - sizeof(QXLCursor)); + sizeof(QXLCursor), cursor->group_id); red_cursor->flags = 0; red_cursor->header = qxl_cursor->header; @@ -5930,14 +6140,15 @@ static void fill_cursor(CursorChannel *cursor_channel, RedCursor *red_cursor, Cu if (qxl_cursor->data_size) { add_buf(channel, BUF_TYPE_CHUNK, &qxl_cursor->chunk, qxl_cursor->data_size, - get_memslot_id(channel->worker, cursor_cmd->u.set.shape)); + get_memslot_id(channel->worker, cursor_cmd->u.set.shape), cursor->group_id); } } else { LocalCursor *local_cursor; ASSERT(cursor->type == CURSOR_TYPE_LOCAL); local_cursor = (LocalCursor *)cursor; *red_cursor = local_cursor->red_cursor; - add_buf(channel, BUF_TYPE_RAW, local_cursor->red_cursor.data, local_cursor->data_size, 0); + add_buf(channel, BUF_TYPE_RAW, local_cursor->red_cursor.data, local_cursor->data_size, 0, + 0); } } @@ -5971,7 +6182,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp switch (drawable->type) { case QXL_DRAW_FILL: channel->send_data.header.type = RED_DISPLAY_DRAW_FILL; - fill_base(display_channel, &display_channel->send_data.u.fill.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.fill.base, item, sizeof(RedFill)); display_channel->send_data.u.fill.data = drawable->u.fill; fill_brush(display_channel, &display_channel->send_data.u.fill.data.brush, item); @@ -5979,7 +6190,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp break; case QXL_DRAW_OPAQUE: channel->send_data.header.type = RED_DISPLAY_DRAW_OPAQUE; - fill_base(display_channel, &display_channel->send_data.u.opaque.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.opaque.base, item, sizeof(RedOpaque)); display_channel->send_data.u.opaque.data = drawable->u.opaque; fill_bits(display_channel, &display_channel->send_data.u.opaque.data.src_bitmap, item); @@ -5988,35 +6199,34 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp break; case QXL_DRAW_COPY: channel->send_data.header.type = RED_DISPLAY_DRAW_COPY; - fill_base(display_channel, &display_channel->send_data.u.copy.base, drawable, - sizeof(RedCopy)); + fill_base(display_channel, &display_channel->send_data.u.copy.base, item, sizeof(RedCopy)); display_channel->send_data.u.copy.data = drawable->u.copy; fill_bits(display_channel, &display_channel->send_data.u.copy.data.src_bitmap, item); fill_mask(display_channel, &display_channel->send_data.u.copy.data.mask, item); break; case QXL_DRAW_TRANSPARENT: channel->send_data.header.type = RED_DISPLAY_DRAW_TRANSPARENT; - fill_base(display_channel, &display_channel->send_data.u.transparent.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.transparent.base, item, sizeof(RedTransparent)); display_channel->send_data.u.transparent.data = drawable->u.transparent; fill_bits(display_channel, &display_channel->send_data.u.transparent.data.src_bitmap, item); break; case QXL_DRAW_ALPHA_BLEND: channel->send_data.header.type = RED_DISPLAY_DRAW_ALPHA_BLEND; - fill_base(display_channel, &display_channel->send_data.u.alpha_blend.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.alpha_blend.base, item, sizeof(RedAlphaBlend)); display_channel->send_data.u.alpha_blend.data = drawable->u.alpha_blend; fill_bits(display_channel, &display_channel->send_data.u.alpha_blend.data.src_bitmap, item); break; case QXL_COPY_BITS: channel->send_data.header.type = RED_DISPLAY_COPY_BITS; - fill_base(display_channel, &display_channel->send_data.u.copy_bits.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.copy_bits.base, item, sizeof(RedCopyBits)); display_channel->send_data.u.copy_bits.src_pos = drawable->u.copy_bits.src_pos; break; case QXL_DRAW_BLEND: channel->send_data.header.type = RED_DISPLAY_DRAW_BLEND; - fill_base(display_channel, &display_channel->send_data.u.blend.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.blend.base, item, sizeof(RedBlend)); display_channel->send_data.u.blend.data = drawable->u.blend; fill_bits(display_channel, &display_channel->send_data.u.blend.data.src_bitmap, item); @@ -6024,28 +6234,28 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp break; case QXL_DRAW_BLACKNESS: channel->send_data.header.type = RED_DISPLAY_DRAW_BLACKNESS; - fill_base(display_channel, &display_channel->send_data.u.blackness.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.blackness.base, item, sizeof(RedBlackness)); display_channel->send_data.u.blackness.data = drawable->u.blackness; fill_mask(display_channel, &display_channel->send_data.u.blackness.data.mask, item); break; case QXL_DRAW_WHITENESS: channel->send_data.header.type = RED_DISPLAY_DRAW_WHITENESS; - fill_base(display_channel, &display_channel->send_data.u.whiteness.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.whiteness.base, item, sizeof(RedWhiteness)); display_channel->send_data.u.whiteness.data = drawable->u.whiteness; fill_mask(display_channel, &display_channel->send_data.u.whiteness.data.mask, item); break; case QXL_DRAW_INVERS: channel->send_data.header.type = RED_DISPLAY_DRAW_INVERS; - fill_base(display_channel, &display_channel->send_data.u.invers.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.invers.base, item, sizeof(RedInvers)); display_channel->send_data.u.invers.data = drawable->u.invers; fill_mask(display_channel, &display_channel->send_data.u.invers.data.mask, item); break; case QXL_DRAW_ROP3: channel->send_data.header.type = RED_DISPLAY_DRAW_ROP3; - fill_base(display_channel, &display_channel->send_data.u.rop3.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.rop3.base, item, sizeof(RedRop3)); display_channel->send_data.u.rop3.data = drawable->u.rop3; fill_bits(display_channel, &display_channel->send_data.u.rop3.data.src_bitmap, item); @@ -6054,21 +6264,20 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp break; case QXL_DRAW_STROKE: channel->send_data.header.type = RED_DISPLAY_DRAW_STROKE; - fill_base(display_channel, &display_channel->send_data.u.stroke.base, drawable, + fill_base(display_channel, &display_channel->send_data.u.stroke.base, item, sizeof(RedStroke)); display_channel->send_data.u.stroke.data = drawable->u.stroke; - fill_path(display_channel, &display_channel->send_data.u.stroke.data.path); - fill_attr(display_channel, &display_channel->send_data.u.stroke.data.attr); + fill_path(display_channel, &display_channel->send_data.u.stroke.data.path, item->group_id); + fill_attr(display_channel, &display_channel->send_data.u.stroke.data.attr, item->group_id); fill_brush(display_channel, &display_channel->send_data.u.stroke.data.brush, item); break; case QXL_DRAW_TEXT: channel->send_data.header.type = RED_DISPLAY_DRAW_TEXT; - fill_base(display_channel, &display_channel->send_data.u.text.base, drawable, - sizeof(RedText)); + fill_base(display_channel, &display_channel->send_data.u.text.base, item, sizeof(RedText)); display_channel->send_data.u.text.data = drawable->u.text; fill_brush(display_channel, &display_channel->send_data.u.text.data.fore_brush, item); fill_brush(display_channel, &display_channel->send_data.u.text.data.back_brush, item); - fill_str(display_channel, &display_channel->send_data.u.text.data.str); + fill_str(display_channel, &display_channel->send_data.u.text.data.str, item->group_id); break; default: red_error("invalid type"); @@ -6133,14 +6342,16 @@ static inline uint32_t __fill_iovec(RedWorker *worker, BufDescriptor *buf, int s data_size -= skip_now; if (data_size) { - validate_virt(worker, (unsigned long)chunk->data, buf->slot_id, data_size); + validate_virt(worker, (unsigned long)chunk->data, buf->slot_id, data_size, + buf->group_id); size += data_size; vec[*vec_index].iov_base = chunk->data + skip_now; vec[*vec_index].iov_len = data_size; (*vec_index)++; } chunk = chunk->next_chunk ? - (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk)) : + (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk), + buf->group_id) : NULL; } while (chunk && *vec_index < MAX_SEND_VEC); break; @@ -6277,29 +6488,31 @@ static inline void display_begin_send_massage(DisplayChannel *channel, void *ite if (sync_count) { sub_list->size = 2; add_buf((RedChannel*)channel, BUF_TYPE_RAW, sub_list, - sizeof(*sub_list) + 2 * sizeof(sub_list->sub_messages[0]), 0); + sizeof(*sub_list) + 2 * sizeof(sub_list->sub_messages[0]), 0, 0); sub_list->sub_messages[0] = channel->base.send_data.header.size; sub_header[0].type = RED_WAIT_FOR_CHANNELS; sub_header[0].size = sizeof(free_list->wait.header) + sync_count * sizeof(free_list->wait.buf[0]); - add_buf((RedChannel*)channel, BUF_TYPE_RAW, sub_header, sizeof(*sub_header), 0); + add_buf((RedChannel*)channel, BUF_TYPE_RAW, sub_header, sizeof(*sub_header), 0, 0); free_list->wait.header.wait_count = sync_count; add_buf((RedChannel*)channel, BUF_TYPE_RAW, &free_list->wait.header, - sub_header[0].size, 0); + sub_header[0].size, 0, 0); sub_list->sub_messages[1] = channel->base.send_data.header.size; sub_index = 1; } else { sub_list->size = 1; add_buf((RedChannel*)channel, BUF_TYPE_RAW, sub_list, - sizeof(*sub_list) + sizeof(sub_list->sub_messages[0]), 0); + sizeof(*sub_list) + sizeof(sub_list->sub_messages[0]), 0, 0); sub_list->sub_messages[0] = channel->base.send_data.header.size; sub_index = 0; } sub_header[sub_index].type = RED_DISPLAY_INVAL_LIST; sub_header[sub_index].size = sizeof(*free_list->res) + free_list->res->count * sizeof(free_list->res->resorces[0]); - add_buf((RedChannel*)channel, BUF_TYPE_RAW, &sub_header[sub_index], sizeof(*sub_header), 0); - add_buf((RedChannel*)channel, BUF_TYPE_RAW, free_list->res, sub_header[sub_index].size, 0); + add_buf((RedChannel*)channel, BUF_TYPE_RAW, &sub_header[sub_index], sizeof(*sub_header), 0, + 0); + add_buf((RedChannel*)channel, BUF_TYPE_RAW, free_list->res, sub_header[sub_index].size, 0, + 0); } red_begin_send_massage((RedChannel *)channel, item); } @@ -6322,14 +6535,16 @@ static inline void red_unref_channel(RedChannel *channel) } static inline uint8_t *red_get_image_line(RedWorker *worker, QXLDataChunk **chunk, int *offset, - int stride, long phys_delta, int memslot_id) + int stride, long phys_delta, int memslot_id, + uint32_t group_id) { uint8_t *ret; uint32_t data_size; - validate_virt(worker, (unsigned long)*chunk, memslot_id, sizeof(QXLDataChunk)); + validate_virt(worker, (unsigned long)*chunk, memslot_id, sizeof(QXLDataChunk), + group_id); data_size = (*chunk)->data_size; - validate_virt(worker, (unsigned long)(*chunk)->data, memslot_id, data_size); + validate_virt(worker, (unsigned long)(*chunk)->data, memslot_id, data_size, group_id); if (data_size == *offset) { if ((*chunk)->next_chunk == 0) { @@ -6383,7 +6598,7 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable channel = &display_channel->base; worker = channel->worker; qxl_image = (QXLImage *)get_virt(worker, drawable->qxl_drawable->u.copy.src_bitmap, - sizeof(QXLImage)); + sizeof(QXLImage), drawable->group_id); if (qxl_image->descriptor.type != IMAGE_TYPE_BITMAP || (qxl_image->bitmap.flags & QXL_BITMAP_DIRECT)) { @@ -6403,27 +6618,27 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable case BITMAP_FMT_32BIT: if (!red_rgb_to_yuv420_32bpp(worker, &drawable->qxl_drawable->u.copy.src_area, &qxl_image->bitmap, stream->av_frame, - get_virt_delta(worker, data), + get_virt_delta(worker, data, drawable->group_id), get_memslot_id(worker, data), - stream - worker->streams_buf, stream)) { + stream - worker->streams_buf, stream, drawable->group_id)) { return FALSE; } break; case BITMAP_FMT_16BIT: if (!red_rgb_to_yuv420_16bpp(worker, &drawable->qxl_drawable->u.copy.src_area, &qxl_image->bitmap, stream->av_frame, - get_virt_delta(worker, data), + get_virt_delta(worker, data, drawable->group_id), get_memslot_id(worker, data), - stream - worker->streams_buf, stream)) { + stream - worker->streams_buf, stream, drawable->group_id)) { return FALSE; } break; case BITMAP_FMT_24BIT: if (!red_rgb_to_yuv420_24bpp(worker, &drawable->qxl_drawable->u.copy.src_area, &qxl_image->bitmap, stream->av_frame, - get_virt_delta(worker, data), + get_virt_delta(worker, data, drawable->group_id), get_memslot_id(worker, data), - stream - worker->streams_buf, stream)) { + stream - worker->streams_buf, stream, drawable->group_id)) { return FALSE; } break; @@ -6496,9 +6711,9 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable #endif channel->send_data.header.type = RED_DISPLAY_STREAM_DATA; RedStreamData* stream_data = &display_channel->send_data.u.stream_data; - add_buf(channel, BUF_TYPE_RAW, stream_data, sizeof(RedStreamData), 0); + add_buf(channel, BUF_TYPE_RAW, stream_data, sizeof(RedStreamData), 0, 0); add_buf(channel, BUF_TYPE_RAW, display_channel->send_data.stream_outbuf, - n + FF_INPUT_BUFFER_PADDING_SIZE, 0); + n + FF_INPUT_BUFFER_PADDING_SIZE, 0, 0); stream_data->id = stream - worker->streams_buf; stream_data->multi_media_time = drawable->qxl_drawable->mm_time; @@ -6529,13 +6744,18 @@ static void red_send_mode(DisplayChannel *display_channel) ASSERT(display_channel); worker = display_channel->base.worker; + + if (!worker->surface.context.canvas) { + return; + } + channel = &display_channel->base; channel->send_data.header.type = RED_DISPLAY_MODE; - display_channel->send_data.u.mode.x_res = worker->dev_info.x_res; - display_channel->send_data.u.mode.y_res = worker->dev_info.y_res; - display_channel->send_data.u.mode.bits = worker->dev_info.bits; + display_channel->send_data.u.mode.x_res = worker->surface.context.width; + display_channel->send_data.u.mode.y_res = worker->surface.context.height; + display_channel->send_data.u.mode.bits = worker->surface.context.depth; - add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.mode, sizeof(RedMode), 0); + add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.mode, sizeof(RedMode), 0, 0); display_begin_send_massage(display_channel, NULL); } @@ -6548,7 +6768,7 @@ static void red_send_set_ack(RedChannel *channel) channel->send_data.u.ack.window = channel->client_ack_window; channel->messages_window = 0; - add_buf(channel, BUF_TYPE_RAW, &channel->send_data.u.ack, sizeof(RedSetAck), 0); + add_buf(channel, BUF_TYPE_RAW, &channel->send_data.u.ack, sizeof(RedSetAck), 0, 0); red_begin_send_massage(channel, NULL); } @@ -6571,7 +6791,7 @@ static inline void __red_send_inval(RedChannel *channel, CacheItem *cach_item, { channel->send_data.header.type = cach_item->inval_type; inval_one->id = *(uint64_t *)&cach_item->id; - add_buf(channel, BUF_TYPE_RAW, inval_one, sizeof(*inval_one), 0); + add_buf(channel, BUF_TYPE_RAW, inval_one, sizeof(*inval_one), 0, 0); } static void red_send_inval(RedChannel *channel, CacheItem *cach_item, RedInvalOne *inval_one) @@ -6593,7 +6813,7 @@ static void display_channel_send_migrate(DisplayChannel *display_channel) display_channel->send_data.u.migrate.flags = RED_MIGRATE_NEED_FLUSH | RED_MIGRATE_NEED_DATA_TRANSFER; add_buf((RedChannel*)display_channel, BUF_TYPE_RAW, &display_channel->send_data.u.migrate, - sizeof(display_channel->send_data.u.migrate), 0); + sizeof(display_channel->send_data.u.migrate), 0, 0); display_channel->expect_migrate_mark = TRUE; display_begin_send_massage(display_channel, NULL); } @@ -6625,7 +6845,7 @@ static void display_channel_send_migrate_data(DisplayChannel *display_channel) &display_channel->glz_data.usr); add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, &display_channel->send_data.u.migrate_data, - sizeof(display_channel->send_data.u.migrate_data), 0); + sizeof(display_channel->send_data.u.migrate_data), 0, 0); display_begin_send_massage(display_channel, NULL); } @@ -6652,7 +6872,7 @@ static void display_channel_pixmap_sync(DisplayChannel *display_channel) pthread_mutex_unlock(&pixmap_cache->lock); add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, wait, - sizeof(*wait) + sizeof(wait->wait_list[0]), 0); + sizeof(*wait) + sizeof(wait->wait_list[0]), 0, 0); display_begin_send_massage(display_channel, NULL); } @@ -6664,7 +6884,7 @@ static void display_channel_reset_cache(DisplayChannel *display_channel) pixmap_cache_reset(display_channel->pixmap_cache, display_channel, wait); add_buf((RedChannel *)display_channel, BUF_TYPE_RAW, wait, - sizeof(*wait) + wait->wait_count * sizeof(wait->wait_list[0]), 0); + sizeof(*wait) + wait->wait_count * sizeof(wait->wait_list[0]), 0, 0); display_begin_send_massage(display_channel, NULL); } @@ -6699,7 +6919,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item) channel->send_data.header.type = RED_DISPLAY_DRAW_COPY; - add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.copy, sizeof(RedCopy), 0); + add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.copy, sizeof(RedCopy), 0, 0); display_channel->send_data.u.copy.base.box.left = item->pos.x; display_channel->send_data.u.copy.base.box.top = item->pos.y; display_channel->send_data.u.copy.base.box.right = item->pos.x + bitmap.x; @@ -6717,17 +6937,18 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item) compress_send_data_t comp_send_data; - if (red_quic_compress_image(display_channel, red_image, &bitmap, &comp_send_data)) { - add_buf(channel, BUF_TYPE_RAW, red_image, comp_send_data.raw_size, 0); + if (red_quic_compress_image(display_channel, red_image, &bitmap, &comp_send_data, + worker->internal_groupslot_id)) { + add_buf(channel, BUF_TYPE_RAW, red_image, comp_send_data.raw_size, 0, 0); add_buf(channel, BUF_TYPE_COMPRESS_BUF, comp_send_data.comp_buf, - comp_send_data.comp_buf_size, 0); + comp_send_data.comp_buf_size, 0, 0); } else { red_image->descriptor.type = IMAGE_TYPE_BITMAP; red_image->bitmap = bitmap; red_image->bitmap.flags &= ~QXL_BITMAP_DIRECT; - add_buf(channel, BUF_TYPE_RAW, red_image, sizeof(BitmapImage), 0); + add_buf(channel, BUF_TYPE_RAW, red_image, sizeof(BitmapImage), 0, 0); red_image->bitmap.data = channel->send_data.header.size; - add_buf(channel, BUF_TYPE_RAW, item->data, bitmap.y * bitmap.stride, 0); + add_buf(channel, BUF_TYPE_RAW, item->data, bitmap.y * bitmap.stride, 0, 0); } display_begin_send_massage(display_channel, &item->link); } @@ -6748,12 +6969,12 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte ASSERT(qxl_drawable->u.copy.rop_decriptor == ROPD_OP_PUT); ASSERT(qxl_drawable->u.copy.mask.bitmap == 0); - add_buf(channel, BUF_TYPE_RAW, copy, sizeof(RedCopy), 0); + add_buf(channel, BUF_TYPE_RAW, copy, sizeof(RedCopy), 0, 0); copy->base.box = qxl_drawable->bbox; copy->base.clip.type = CLIP_TYPE_RECTS; copy->base.clip.data = channel->send_data.header.size; - add_buf(channel, BUF_TYPE_RAW, &item->region.num_rects, sizeof(uint32_t), 0); - add_buf(channel, BUF_TYPE_RAW, item->region.rects, sizeof(Rect) * item->region.num_rects, 0); + add_buf(channel, BUF_TYPE_RAW, &item->region.num_rects, sizeof(uint32_t), 0, 0); + add_buf(channel, BUF_TYPE_RAW, item->region.rects, sizeof(Rect) * item->region.num_rects, 0, 0); copy->data = qxl_drawable->u.copy; fill_bits(display_channel, ©->data.src_bitmap, item->drawable); @@ -6779,12 +7000,12 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea stream_create->stream_height = ALIGN(stream_create->src_height, 2); stream_create->dest = stream->dest_area; - add_buf(channel, BUF_TYPE_RAW, stream_create, sizeof(*stream_create), 0); + add_buf(channel, BUF_TYPE_RAW, stream_create, sizeof(*stream_create), 0, 0); if (stream->current) { QXLDrawable *qxl_drawable = stream->current->qxl_drawable; stream_create->clip = qxl_drawable->clip; if (qxl_drawable->clip.type == CLIP_TYPE_RECTS) { - fill_rects_clip(channel, &stream_create->clip.data); + fill_rects_clip(channel, &stream_create->clip.data, stream->current->group_id); } else { ASSERT(qxl_drawable->clip.type == CLIP_TYPE_NONE); } @@ -6794,7 +7015,7 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea stream_create->clip.data = channel->send_data.header.size; display_channel->send_data.u.stream_create.num_rects = 0; add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.stream_create.num_rects, - sizeof(uint32_t), 0); + sizeof(uint32_t), 0, 0); display_begin_send_massage(display_channel, NULL); } } @@ -6811,16 +7032,16 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel, channel->send_data.header.type = RED_DISPLAY_STREAM_CLIP; RedStreamClip *stream_clip = &display_channel->send_data.u.stream_clip; - add_buf(channel, BUF_TYPE_RAW, stream_clip, sizeof(*stream_clip), 0); + add_buf(channel, BUF_TYPE_RAW, stream_clip, sizeof(*stream_clip), 0, 0); stream_clip->id = agent - display_channel->stream_agents; if ((stream_clip->clip.type = item->clip_type) == CLIP_TYPE_NONE) { stream_clip->clip.data = 0; } else { ASSERT(stream_clip->clip.type == CLIP_TYPE_RECTS); stream_clip->clip.data = channel->send_data.header.size; - add_buf(channel, BUF_TYPE_RAW, &item->region.num_rects, sizeof(uint32_t), 0); + add_buf(channel, BUF_TYPE_RAW, &item->region.num_rects, sizeof(uint32_t), 0, 0); add_buf(channel, BUF_TYPE_RAW, item->region.rects, - item->region.num_rects * sizeof(Rect), 0); + item->region.num_rects * sizeof(Rect), 0, 0); } display_begin_send_massage(display_channel, item); } @@ -6831,7 +7052,7 @@ static void red_display_send_stream_end(DisplayChannel *display_channel, StreamA channel->send_data.header.type = RED_DISPLAY_STREAM_DESTROY; display_channel->send_data.u.stream_destroy.id = agent - display_channel->stream_agents; add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.stream_destroy, - sizeof(RedStreamDestroy), 0); + sizeof(RedStreamDestroy), 0, 0); display_begin_send_massage(display_channel, NULL); } @@ -6854,7 +7075,7 @@ static void red_send_cursor_init(CursorChannel *channel) channel->send_data.u.cursor_init.trail_length = worker->cursor_trail_length; channel->send_data.u.cursor_init.trail_frequency = worker->cursor_trail_frequency; add_buf(&channel->base, BUF_TYPE_RAW, &channel->send_data.u.cursor_init, sizeof(RedCursorInit), - 0); + 0, 0); fill_cursor(channel, &channel->send_data.u.cursor_init.cursor, worker->cursor); @@ -6872,7 +7093,7 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu cursor_channel->send_data.u.cursor_set.postition = cursor->position; cursor_channel->send_data.u.cursor_set.visible = channel->worker->cursor_visible; add_buf(channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.cursor_set, - sizeof(RedCursorSet), 0); + sizeof(RedCursorSet), 0, 0); fill_cursor(cursor_channel, &cursor_channel->send_data.u.cursor_set.cursor, &cursor->base); red_begin_send_massage(channel, cursor); @@ -6885,7 +7106,7 @@ static void cursor_channel_send_migrate(CursorChannel *cursor_channel) cursor_channel->base.send_data.header.type = RED_MIGRATE; cursor_channel->send_data.u.migrate.flags = 0; add_buf((RedChannel*)cursor_channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.migrate, - sizeof(cursor_channel->send_data.u.migrate), 0); + sizeof(cursor_channel->send_data.u.migrate), 0, 0); red_begin_send_massage((RedChannel*)cursor_channel, NULL); } @@ -6898,20 +7119,20 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor) channel = &cursor_channel->base; - cmd = CONTAINEROF(cursor, QXLCursorCmd, device_data); + cmd = cursor->qxl_cursor; switch (cmd->type) { case QXL_CURSOR_MOVE: channel->send_data.header.type = RED_CURSOR_MOVE; cursor_channel->send_data.u.cursor_move.postition = cmd->u.position; add_buf(channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.cursor_move, - sizeof(RedCursorMove), 0); + sizeof(RedCursorMove), 0, 0); break; case QXL_CURSOR_SET: channel->send_data.header.type = RED_CURSOR_SET; cursor_channel->send_data.u.cursor_set.postition = cmd->u.set.position; cursor_channel->send_data.u.cursor_set.visible = channel->worker->cursor_visible; add_buf(channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.cursor_set, - sizeof(RedCursorSet), 0); + sizeof(RedCursorSet), 0, 0); fill_cursor(cursor_channel, &cursor_channel->send_data.u.cursor_set.cursor, cursor); break; case QXL_CURSOR_HIDE: @@ -6922,7 +7143,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor) cursor_channel->send_data.u.cursor_trail.length = cmd->u.trail.length; cursor_channel->send_data.u.cursor_trail.frequency = cmd->u.trail.frequency; add_buf(channel, BUF_TYPE_RAW, &cursor_channel->send_data.u.cursor_trail, - sizeof(RedCursorTrail), 0); + sizeof(RedCursorTrail), 0, 0); break; default: red_error("bad cursor command %d", cmd->type); @@ -7221,47 +7442,41 @@ static void destroy_cairo_canvas(CairoCanvas *canvas) cairo_destroy(cairo); } -static void validate_area_nop(void *canvas, const DrawArea *draw_area, const Rect *area) +static void validate_area_nop(void *canvas, int32_t stride, uint8_t *line_0, const Rect *area) { } -static void init_cairo_draw_context(RedWorker *worker, CairoCanvas *canvas) +static void init_cairo_draw_funcs(RedWorker *worker) { - worker->draw_context.canvas = canvas; - worker->draw_context.top_down = TRUE; - worker->draw_context.draw_fill = (draw_fill_t)canvas_draw_fill; - worker->draw_context.draw_copy = (draw_copy_t)canvas_draw_copy; - worker->draw_context.draw_opaque = (draw_opaque_t)canvas_draw_opaque; - worker->draw_context.copy_bits = (copy_bits_t)canvas_copy_bits; - worker->draw_context.draw_text = (draw_text_t)canvas_draw_text; - worker->draw_context.draw_stroke = (draw_stroke_t)canvas_draw_stroke; - worker->draw_context.draw_rop3 = (draw_rop3_t)canvas_draw_rop3; - worker->draw_context.draw_blend = (draw_blend_t)canvas_draw_blend; - worker->draw_context.draw_blackness = (draw_blackness_t)canvas_draw_blackness; - worker->draw_context.draw_whiteness = (draw_whiteness_t)canvas_draw_whiteness; - worker->draw_context.draw_invers = (draw_invers_t)canvas_draw_invers; - worker->draw_context.draw_transparent = (draw_transparent_t)canvas_draw_transparent; - worker->draw_context.draw_alpha_blend = (draw_alpha_blend_t)canvas_draw_alpha_blend; - worker->draw_context.read_pixels = (read_pixels_t)canvas_read_bits; + worker->draw_funcs.draw_fill = (draw_fill_t)canvas_draw_fill; + worker->draw_funcs.draw_copy = (draw_copy_t)canvas_draw_copy; + worker->draw_funcs.draw_opaque = (draw_opaque_t)canvas_draw_opaque; + worker->draw_funcs.copy_bits = (copy_bits_t)canvas_copy_bits; + worker->draw_funcs.draw_text = (draw_text_t)canvas_draw_text; + worker->draw_funcs.draw_stroke = (draw_stroke_t)canvas_draw_stroke; + worker->draw_funcs.draw_rop3 = (draw_rop3_t)canvas_draw_rop3; + worker->draw_funcs.draw_blend = (draw_blend_t)canvas_draw_blend; + worker->draw_funcs.draw_blackness = (draw_blackness_t)canvas_draw_blackness; + worker->draw_funcs.draw_whiteness = (draw_whiteness_t)canvas_draw_whiteness; + worker->draw_funcs.draw_invers = (draw_invers_t)canvas_draw_invers; + worker->draw_funcs.draw_transparent = (draw_transparent_t)canvas_draw_transparent; + worker->draw_funcs.draw_alpha_blend = (draw_alpha_blend_t)canvas_draw_alpha_blend; + worker->draw_funcs.read_pixels = (read_pixels_t)canvas_read_bits; - worker->draw_context.set_top_mask = (set_top_mask_t)canvas_group_start; - worker->draw_context.clear_top_mask = (clear_top_mask_t)canvas_group_end; - worker->draw_context.validate_area = validate_area_nop; - worker->draw_context.destroy = (destroy_t)destroy_cairo_canvas; + worker->draw_funcs.set_top_mask = (set_top_mask_t)canvas_group_start; + worker->draw_funcs.clear_top_mask = (clear_top_mask_t)canvas_group_end; + worker->draw_funcs.validate_area = validate_area_nop; + worker->draw_funcs.destroy = (destroy_t)destroy_cairo_canvas; } -static int create_cairo_context(RedWorker *worker) +static CairoCanvas *create_cairo_context(RedWorker *worker, uint32_t width, uint32_t height, + int32_t stride, uint8_t depth, void *line_0) { cairo_surface_t *cairo_surface; - CairoCanvas *canvas; cairo_t *cairo; - cairo_surface = cairo_image_surface_create_for_data(worker->dev_info.draw_area.line_0, - CAIRO_FORMAT_RGB24, - worker->dev_info.draw_area.width, - worker->dev_info.draw_area.heigth, - worker->dev_info.draw_area.stride); - + cairo_surface = cairo_image_surface_create_for_data(line_0, CAIRO_FORMAT_RGB24, width, height, + stride); if (cairo_surface_status(cairo_surface) != CAIRO_STATUS_SUCCESS) { red_error("create cairo surface failed, %s", cairo_status_to_string(cairo_surface_status(cairo_surface))); @@ -7273,14 +7488,9 @@ static int create_cairo_context(RedWorker *worker) cairo_status_to_string(cairo_status(cairo))); } - if (!(canvas = canvas_create(cairo, worker->dev_info.bits, &worker->image_cache, - image_cache_put, image_cache_get, worker, cb_get_virt, - worker, cb_validate_virt))) { - red_error("create cairo canvas failed"); - } - init_cairo_draw_context(worker, canvas); - red_printf("using cairo canvas"); - return TRUE; + return canvas_create(cairo, depth, &worker->image_cache, image_cache_put, image_cache_get, + worker, cb_get_virt_preload_group, worker, + cb_validate_virt_preload_group); } static void destroy_gl_canvas(GLCanvas *canvas) @@ -7297,7 +7507,7 @@ static void destroy_gl_canvas(GLCanvas *canvas) oglctx_destroy(ctx); } -static void gl_validate_area(GLCanvas *canvas, DrawArea *draw_area, const Rect *area) +static void gl_validate_area(GLCanvas *canvas, int32_t stride, uint8_t *line_0, const Rect *area) { int h; @@ -7305,121 +7515,217 @@ static void gl_validate_area(GLCanvas *canvas, DrawArea *draw_area, const Rect * return; } - ASSERT(draw_area->stride < 0); - uint8_t *dest = draw_area->line_0 + (area->top * draw_area->stride) + - area->left * sizeof(uint32_t); - dest += (h - 1) * draw_area->stride; - gl_canvas_read_pixels(canvas, dest, -draw_area->stride, area); + ASSERT(stride < 0); + uint8_t *dest = line_0 + (area->top * stride) + area->left * sizeof(uint32_t); + dest += (h - 1) * stride; + gl_canvas_read_pixels(canvas, dest, -stride, area); } -static void init_ogl_draw_context(RedWorker *worker, GLCanvas *canvas) +static void init_ogl_draw_funcs(RedWorker *worker) { - worker->draw_context.canvas = canvas; - worker->draw_context.top_down = FALSE; - worker->draw_context.draw_fill = (draw_fill_t)gl_canvas_draw_fill; - worker->draw_context.draw_copy = (draw_copy_t)gl_canvas_draw_copy; - worker->draw_context.draw_opaque = (draw_opaque_t)gl_canvas_draw_opaque; - worker->draw_context.copy_bits = (copy_bits_t)gl_canvas_copy_pixels; - worker->draw_context.draw_text = (draw_text_t)gl_canvas_draw_text; - worker->draw_context.draw_stroke = (draw_stroke_t)gl_canvas_draw_stroke; - worker->draw_context.draw_rop3 = (draw_rop3_t)gl_canvas_draw_rop3; - worker->draw_context.draw_blend = (draw_blend_t)gl_canvas_draw_blend; - worker->draw_context.draw_blackness = (draw_blackness_t)gl_canvas_draw_blackness; - worker->draw_context.draw_whiteness = (draw_whiteness_t)gl_canvas_draw_whiteness; - worker->draw_context.draw_invers = (draw_invers_t)gl_canvas_draw_invers; - worker->draw_context.draw_transparent = (draw_transparent_t)gl_canvas_draw_transparent; - worker->draw_context.draw_alpha_blend = (draw_alpha_blend_t)gl_canvas_draw_alpha_blend; - worker->draw_context.read_pixels = (read_pixels_t)gl_canvas_read_pixels; + worker->draw_funcs.draw_fill = (draw_fill_t)gl_canvas_draw_fill; + worker->draw_funcs.draw_copy = (draw_copy_t)gl_canvas_draw_copy; + worker->draw_funcs.draw_opaque = (draw_opaque_t)gl_canvas_draw_opaque; + worker->draw_funcs.copy_bits = (copy_bits_t)gl_canvas_copy_pixels; + worker->draw_funcs.draw_text = (draw_text_t)gl_canvas_draw_text; + worker->draw_funcs.draw_stroke = (draw_stroke_t)gl_canvas_draw_stroke; + worker->draw_funcs.draw_rop3 = (draw_rop3_t)gl_canvas_draw_rop3; + worker->draw_funcs.draw_blend = (draw_blend_t)gl_canvas_draw_blend; + worker->draw_funcs.draw_blackness = (draw_blackness_t)gl_canvas_draw_blackness; + worker->draw_funcs.draw_whiteness = (draw_whiteness_t)gl_canvas_draw_whiteness; + worker->draw_funcs.draw_invers = (draw_invers_t)gl_canvas_draw_invers; + worker->draw_funcs.draw_transparent = (draw_transparent_t)gl_canvas_draw_transparent; + worker->draw_funcs.draw_alpha_blend = (draw_alpha_blend_t)gl_canvas_draw_alpha_blend; + worker->draw_funcs.read_pixels = (read_pixels_t)gl_canvas_read_pixels; - worker->draw_context.set_top_mask = (set_top_mask_t)gl_canvas_set_top_mask; - worker->draw_context.clear_top_mask = (clear_top_mask_t)gl_canvas_clear_top_mask; - worker->draw_context.validate_area = (validate_area_t)gl_validate_area; - worker->draw_context.destroy = (destroy_t)destroy_gl_canvas; + worker->draw_funcs.set_top_mask = (set_top_mask_t)gl_canvas_set_top_mask; + worker->draw_funcs.clear_top_mask = (clear_top_mask_t)gl_canvas_clear_top_mask; + worker->draw_funcs.validate_area = (validate_area_t)gl_validate_area; + worker->draw_funcs.destroy = (destroy_t)destroy_gl_canvas; } -static int create_ogl_context_common(RedWorker *worker, OGLCtx *ctx) +static GLCanvas *create_ogl_context_common(RedWorker *worker, OGLCtx *ctx, uint32_t width, + uint32_t height, int32_t stride, uint8_t depth) { GLCanvas *canvas; - int width; - int height; - - width = worker->dev_info.x_res; - height = worker->dev_info.y_res; oglctx_make_current(ctx); - if (!(canvas = gl_canvas_create(ctx, width, height, worker->dev_info.bits, &worker->image_cache, - image_cache_put, image_cache_get, worker, cb_get_virt, - worker, cb_validate_virt))) { - return FALSE; + if (!(canvas = gl_canvas_create(ctx, width, height, depth, &worker->image_cache, + image_cache_put, image_cache_get, worker, + cb_get_virt_preload_group, + worker, cb_validate_virt_preload_group))) { + return NULL; } - init_ogl_draw_context(worker, canvas); gl_canvas_clear(canvas); - red_printf("using ogl %s canvas", oglctx_type_str(ctx)); - return TRUE; + + return canvas; } -static int create_ogl_pbuf_context(RedWorker *worker) +static GLCanvas *create_ogl_pbuf_context(RedWorker *worker, uint32_t width, uint32_t height, + int32_t stride, uint8_t depth) { OGLCtx *ctx; + GLCanvas *canvas; - if (!(ctx = pbuf_create(worker->dev_info.x_res, worker->dev_info.y_res))) { - return FALSE; + if (!(ctx = pbuf_create(width, height))) { + return NULL; } - if (!create_ogl_context_common(worker, ctx)) { + if (!(canvas = create_ogl_context_common(worker, ctx, width, height, stride, depth))) { oglctx_destroy(ctx); - return FALSE; + return NULL; } - return TRUE; + return canvas; } -static int create_ogl_pixmap_context(RedWorker *worker) -{ +static GLCanvas *create_ogl_pixmap_context(RedWorker *worker, uint32_t width, uint32_t height, + int32_t stride, uint8_t depth) { OGLCtx *ctx; + GLCanvas *canvas; - if (!(ctx = pixmap_create(worker->dev_info.x_res, worker->dev_info.y_res))) { - return FALSE; + if (!(ctx = pixmap_create(width, height))) { + return NULL; } - if (!create_ogl_context_common(worker, ctx)) { + if (!(canvas = create_ogl_context_common(worker, ctx, width, height, stride, depth))) { oglctx_destroy(ctx); - return FALSE; + return NULL; } - return TRUE; + return canvas; } -static void red_create_draw_context(RedWorker *worker) +static inline void surface_init_draw_funcs(RedWorker *worker, uint32_t renderer) { - int i; + switch (renderer) { + case RED_RENDERER_CAIRO: + init_cairo_draw_funcs(worker); + red_printf("using cairo canvas"); + return; + case RED_RENDERER_OGL_PBUF: + init_ogl_draw_funcs(worker); + red_printf("using opengl pbuff canvas"); + return; + case RED_RENDERER_OGL_PIXMAP: + init_ogl_draw_funcs(worker); + red_printf("using opengl pixmap canvas"); + return; + default: + red_error("invalid renderer type"); + }; +} + +static inline void *create_canvas_for_surface(RedWorker *worker, Surface *surface, + uint32_t renderer, uint32_t width, uint32_t height, + int32_t stride, uint8_t depth, void *line_0) +{ + void *canvas; + + switch (renderer) { + case RED_RENDERER_CAIRO: + canvas = create_cairo_context(worker, width, height, stride, depth, line_0); + surface->context.top_down = TRUE; + return canvas; + case RED_RENDERER_OGL_PBUF: + canvas = create_ogl_pbuf_context(worker, width, height, stride, depth); + surface->context.top_down = FALSE; + return canvas; + case RED_RENDERER_OGL_PIXMAP: + canvas = create_ogl_pixmap_context(worker, width, height, stride, depth); + surface->context.top_down = FALSE; + return canvas; + default: + red_error("invalid renderer type"); + }; +} + +static inline void red_create_surface(RedWorker *worker, uint32_t width, uint32_t height, + int32_t stride, uint8_t depth, void *line_0) +{ + uint32_t i; + Surface *surface = &worker->surface; + + if (stride >= 0) { + PANIC("Untested path stride >= 0"); + } + PANIC_ON(surface->context.canvas); + + surface->context.width = width; + surface->context.height = height; + surface->context.depth = depth; + surface->context.stride = stride; + surface->context.line_0 = line_0; + surface->refs = 1; + + if (worker->renderer != RED_RENDERER_INVALID) { + surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderer, + width, height, stride, + surface->context.depth, line_0); + if (!surface->context.canvas) { + PANIC("drawing canvas creating failed - can`t create same type canvas"); + } + return; + } - worker->draw_context.destroy(worker->draw_context.canvas); - worker->draw_context.canvas = NULL; for (i = 0; i < worker->num_renderers; i++) { - switch (worker->renderers[i]) { - case RED_RENDERER_CAIRO: - if (create_cairo_context(worker)) { - return; - } + surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderers[i], + width, height, stride, + surface->context.depth, line_0); + if (surface->context.canvas) { + worker->renderer = worker->renderers[i]; + surface_init_draw_funcs(worker, worker->renderers[i]); + return; + } + } + + PANIC("unable to create drawing canvas"); +} + +static void red_wait_outgoiong_item(RedChannel *channel); + +static inline void flush_display_commands(RedWorker *worker) +{ + for (;;) { + uint64_t end_time; + + while (red_process_commands(worker, MAX_PIPE_SIZE)) { + display_channel_push(worker); + } + + if (!worker->qxl->has_command(worker->qxl)) { break; - case RED_RENDERER_OGL_PBUF: - if (create_ogl_pbuf_context(worker)) { - return; + } + end_time = red_now() + DISPLAY_CLIENT_TIMEOUT * 10; + int sleep_count = 0; + for (;;) { + display_channel_push(worker); + if (!worker->display_channel || + worker->display_channel->base.pipe_size <= MAX_PIPE_SIZE) { + break; } - break; - case RED_RENDERER_OGL_PIXMAP: - if (create_ogl_pixmap_context(worker)) { - return; + RedChannel *channel = (RedChannel *)worker->display_channel; + red_ref_channel(channel); + red_receive(channel); + red_send_data(channel, NULL); + if (red_now() >= end_time) { + red_printf("update timout"); + red_disconnect_display((RedChannel *)worker->display_channel); + } else { + sleep_count++; + usleep(DISPLAY_CLIENT_RETRY_INTERVAL); } - break; - default: - red_error("invalid renderer type"); + red_unref_channel(channel); } } - red_error("create renderer failed"); - memset(worker->dev_info.draw_area.buf, 0, worker->dev_info.draw_area.size); +} + +static inline void red_flush_surface_pipe(RedWorker *worker) +{ + if (worker->display_channel) { + display_channel_push(worker); + } } static void push_new_mode(RedWorker *worker) @@ -7480,7 +7786,7 @@ static void on_new_display_channel(RedWorker *worker) return; } display_channel->base.messages_window = 0; - if (worker->attached) { + if (worker->surface.context.canvas) { red_current_flush(worker); push_new_mode(worker); red_add_screen_image(worker); @@ -8098,7 +8404,7 @@ static void on_new_cursor_channel(RedWorker *worker) channel->base.messages_window = 0; red_pipe_add_type(&channel->base, PIPE_ITEM_TYPE_SET_ACK); - if (worker->attached && !channel->base.migrate) { + if (worker->surface.context.canvas && !channel->base.migrate) { red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_CURSOR_INIT); } } @@ -8208,9 +8514,10 @@ static void red_cursor_flush(RedWorker *worker) ASSERT(worker->cursor->type == CURSOR_TYPE_DEV); - cursor_cmd = CONTAINEROF(worker->cursor, QXLCursorCmd, device_data); + cursor_cmd = worker->cursor->qxl_cursor; ASSERT(cursor_cmd->type == QXL_CURSOR_SET); - qxl_cursor = (QXLCursor *)get_virt(worker, cursor_cmd->u.set.shape, sizeof(QXLCursor)); + qxl_cursor = (QXLCursor *)get_virt(worker, cursor_cmd->u.set.shape, sizeof(QXLCursor), + worker->cursor->group_id); local = _new_local_cursor(&qxl_cursor->header, qxl_cursor->data_size, worker->cursor_position); @@ -8226,7 +8533,8 @@ static void red_cursor_flush(RedWorker *worker) data_size -= chunk->data_size; dest += chunk->data_size; chunk = chunk->next_chunk ? - (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk)) : NULL; + (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk), + worker->internal_groupslot_id) : NULL; } red_set_cursor(worker, &local->base); red_release_cursor(worker, &local->base); @@ -8293,39 +8601,10 @@ static inline void handle_dev_update(RedWorker *worker) { RedWorkeMessage message; - ASSERT(worker->attached && worker->running); - for (;;) { - uint64_t end_time; + ASSERT(worker->surface.context.canvas && worker->running); - while (red_process_commands(worker, MAX_PIPE_SIZE)) { - display_channel_push(worker); - } + flush_display_commands(worker); - if (!worker->qxl->has_command(worker->qxl)) { - break; - } - end_time = red_now() + DISPLAY_CLIENT_TIMEOUT; - int sleep_count = 0; - for (;;) { - display_channel_push(worker); - if (!worker->display_channel || - worker->display_channel->base.pipe_size <= MAX_PIPE_SIZE) { - break; - } - RedChannel *channel = (RedChannel *)worker->display_channel; - red_ref_channel(channel); - red_receive(channel); - red_send_data(channel, NULL); - if (red_now() >= end_time) { - red_printf("update timout"); - red_disconnect_display((RedChannel *)worker->display_channel); - } else { - sleep_count++; - usleep(DISPLAY_CLIENT_RETRY_INTERVAL); - } - red_unref_channel(channel); - } - } red_update_area(worker, worker->qxl->get_update_area(worker->qxl)); message = RED_WORKER_MESSAGE_READY; write_message(worker->channel, &message); @@ -8339,12 +8618,13 @@ static inline void handle_dev_add_memslot(RedWorker *worker) receive_data(worker->channel, &dev_slot, sizeof(QXLDevMemSlot)); + ASSERT(worker->num_memslots_groups > dev_slot.slot_group_id); ASSERT(worker->num_memslots > dev_slot.slot_id); - - worker->mem_slots[dev_slot.slot_id].address_delta = dev_slot.addr_delta; - worker->mem_slots[dev_slot.slot_id].virt_start_addr = dev_slot.virt_start; - worker->mem_slots[dev_slot.slot_id].virt_end_addr = dev_slot.virt_end; - worker->mem_slots[dev_slot.slot_id].generation = dev_slot.generation; + worker->mem_slots[dev_slot.slot_group_id][dev_slot.slot_id].address_delta = dev_slot.addr_delta; + worker->mem_slots[dev_slot.slot_group_id][dev_slot.slot_id].virt_start_addr = + dev_slot.virt_start; + worker->mem_slots[dev_slot.slot_group_id][dev_slot.slot_id].virt_end_addr = dev_slot.virt_end; + worker->mem_slots[dev_slot.slot_group_id][dev_slot.slot_id].generation = dev_slot.generation; message = RED_WORKER_MESSAGE_READY; write_message(worker->channel, &message); @@ -8353,23 +8633,172 @@ static inline void handle_dev_add_memslot(RedWorker *worker) static inline void handle_dev_del_memslot(RedWorker *worker) { uint32_t slot_id; + uint32_t slot_group_id; + receive_data(worker->channel, &slot_group_id, sizeof(uint32_t)); receive_data(worker->channel, &slot_id, sizeof(uint32_t)); + ASSERT(worker->num_memslots_groups > slot_group_id); ASSERT(worker->num_memslots > slot_id); - worker->mem_slots[slot_id].virt_start_addr = 0; - worker->mem_slots[slot_id].virt_end_addr = 0; + worker->mem_slots[slot_group_id][slot_id].virt_start_addr = 0; + worker->mem_slots[slot_group_id][slot_id].virt_end_addr = 0; +} + +static inline void destroy_surface_wait(RedWorker *worker) +{ + flush_display_commands(worker); + red_flush_surface_pipe(worker); + red_display_clear_glz_drawables(worker->display_channel); + red_current_clear(worker); + red_wait_outgoiong_item((RedChannel *)worker->display_channel); + if (worker->display_channel) { + ASSERT(!worker->display_channel->base.send_data.item); + } +} + +static inline void handle_dev_destroy_surface_wait(RedWorker *worker) +{ + RedWorkeMessage message; + uint32_t surface_id; + + receive_data(worker->channel, &surface_id, sizeof(uint32_t)); + + ASSERT(surface_id == 0); + + if (worker->surface.context.canvas) { + destroy_surface_wait(worker); + } + + message = RED_WORKER_MESSAGE_READY; + write_message(worker->channel, &message); +} + +static inline void handle_dev_destroy_surfaces(RedWorker *worker) +{ + RedWorkeMessage message; + + destroy_surface_wait(worker); + __red_destroy_surface(worker); + ASSERT(ring_is_empty(&worker->streams)); + + red_wait_outgoiong_item((RedChannel *)worker->cursor_channel); + if (worker->cursor_channel) { + red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE); + if (!worker->cursor_channel->base.migrate) { + red_pipe_add_verb(&worker->cursor_channel->base, RED_CURSOR_RESET); + } + ASSERT(!worker->cursor_channel->base.send_data.item); + } + + if (worker->display_channel) { + red_pipe_add_type(&worker->display_channel->base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE); + red_pipe_add_verb(&worker->display_channel->base, RED_DISPLAY_STREAM_DESTROY_ALL); + if (!worker->display_channel->base.migrate) { + red_pipe_add_verb(&worker->display_channel->base, RED_DISPLAY_RESET); + } + } + + ASSERT(!worker->surface.context.canvas); + + worker->cursor_visible = TRUE; + worker->cursor_position.x = worker->cursor_position.y = 0; + worker->cursor_trail_length = worker->cursor_trail_frequency = 0; + + message = RED_WORKER_MESSAGE_READY; + write_message(worker->channel, &message); +} + +static inline void handle_dev_create_primary_surface(RedWorker *worker) +{ + RedWorkeMessage message; + uint32_t surface_id; + QXLDevSurfaceCreate surface; + uint8_t *line_0; + + receive_data(worker->channel, &surface_id, sizeof(uint32_t)); + receive_data(worker->channel, &surface, sizeof(QXLDevSurfaceCreate)); + + PANIC_ON(surface_id != 0); + PANIC_ON(surface.height == 0); + PANIC_ON(((uint64_t)abs(surface.stride) * (uint64_t)surface.height) != + abs(surface.stride) * surface.height); + + line_0 = (uint8_t*)get_virt(worker, surface.mem, surface.height * abs(surface.stride), + surface.group_id); + if (surface.stride < 0) { + line_0 -= (int32_t)(surface.stride * (surface.height -1)); + } + + red_create_surface(worker, surface.width, surface.height, surface.stride, surface.depth, + line_0); + + if (worker->display_channel) { + red_pipe_add_type(&worker->display_channel->base, PIPE_ITEM_TYPE_MODE); + red_pipe_add_verb(&worker->display_channel->base, RED_DISPLAY_MARK); + display_channel_push(worker); + } + + if (worker->cursor_channel) { + red_pipe_add_type(&worker->cursor_channel->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) +{ + RedWorkeMessage message; + uint32_t surface_id; + + receive_data(worker->channel, &surface_id, sizeof(uint32_t)); + + PANIC_ON(surface_id != 0); + + if (worker->cursor) { + red_release_cursor(worker, worker->cursor); + worker->cursor = NULL; + } + + red_wait_outgoiong_item((RedChannel *)worker->cursor_channel); + if (worker->cursor_channel) { + red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE); + if (!worker->cursor_channel->base.migrate) { + red_pipe_add_verb(&worker->cursor_channel->base, RED_CURSOR_RESET); + } + ASSERT(!worker->cursor_channel->base.send_data.item); + } + + + destroy_surface_wait(worker); + red_destroy_surface(worker); + ASSERT(ring_is_empty(&worker->streams)); + + ASSERT(!worker->surface.context.canvas); + + worker->cursor_visible = TRUE; + worker->cursor_position.x = worker->cursor_position.y = 0; + worker->cursor_trail_length = worker->cursor_trail_frequency = 0; + + message = RED_WORKER_MESSAGE_READY; + write_message(worker->channel, &message); } static void inline red_create_mem_slots(RedWorker *worker) { + uint32_t i; + ASSERT(worker->num_memslots > 0); - worker->mem_slots = (MemSlot *)malloc(sizeof(MemSlot) * worker->num_memslots); - if (!worker->mem_slots) { - PANIC("malloc failed"); + ASSERT(worker->num_memslots_groups > 0); + worker->mem_slots = (MemSlot **)malloc(sizeof(MemSlot *) * worker->num_memslots_groups); + PANIC_ON(!worker->mem_slots); + + for (i = 0; i < worker->num_memslots_groups; ++i) { + worker->mem_slots[i] = malloc(sizeof(MemSlot) * worker->num_memslots); + PANIC_ON(!worker->mem_slots[i]); + memset(worker->mem_slots[i], 0, sizeof(MemSlot) * worker->num_memslots); } - memset(worker->mem_slots, 0, sizeof(MemSlot) * worker->num_memslots); worker->memslot_id_shift = 64 - worker->mem_slot_bits; worker->memslot_gen_shift = 64 - (worker->mem_slot_bits + worker->generation_bits); @@ -8394,7 +8823,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events) stat_inc_counter(worker->wakeup_counter, 1); break; case RED_WORKER_MESSAGE_OOM: - ASSERT(worker->attached && worker->running); + ASSERT(worker->running); while (red_process_commands(worker, MAX_PIPE_SIZE)) { display_channel_push(worker); } @@ -8405,32 +8834,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events) } clear_bit(RED_WORKER_PENDING_OOM, worker->pending); break; - case RED_WORKER_MESSAGE_ATTACH: - ASSERT(!worker->attached); - red_printf("attach"); - receive_data(worker->channel, &worker->dev_info, sizeof(QXLDevInfo)); - worker->attached = TRUE; - worker->repoll_cmd_ring = worker->repoll_cursor_ring = 0; - red_create_draw_context(worker); - ASSERT(ring_is_empty(&worker->current)); - if (worker->display_channel && !worker->display_channel->base.migrate) { - red_pipe_add_type(&worker->display_channel->base, PIPE_ITEM_TYPE_MODE); - red_pipe_add_verb(&worker->display_channel->base, RED_DISPLAY_MARK); - display_channel_push(worker); - } - if (worker->cursor_channel && !worker->cursor_channel->base.migrate) { - red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_CURSOR_INIT); - } - message = RED_WORKER_MESSAGE_READY; - write_message(worker->channel, &message); - break; - case RED_WORKER_MESSAGE_DETACH: - red_printf("detach"); - red_display_clear_glz_drawables(worker->display_channel); - red_current_clear(worker); -#ifdef STREAM_TRACE - red_reset_stream_trace(worker); -#endif + case RED_WORKER_MESSAGE_RESET_CURSOR: if (worker->cursor) { red_release_cursor(worker, worker->cursor); worker->cursor = NULL; @@ -8443,28 +8847,32 @@ static void handle_dev_input(EventListener *listener, uint32_t events) red_pipe_add_verb(&worker->cursor_channel->base, RED_CURSOR_RESET); } ASSERT(!worker->cursor_channel->base.send_data.item); - } - red_wait_outgoiong_item((RedChannel *)worker->display_channel); - ASSERT(ring_is_empty(&worker->streams)); - if (worker->display_channel) { - red_pipe_add_type(&worker->display_channel->base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE); - red_pipe_add_verb(&worker->display_channel->base, RED_DISPLAY_STREAM_DESTROY_ALL); - if (!worker->display_channel->base.migrate) { - red_pipe_add_verb(&worker->display_channel->base, RED_DISPLAY_RESET); - } - ASSERT(!worker->display_channel->base.send_data.item); + worker->cursor_visible = TRUE; + worker->cursor_position.x = worker->cursor_position.y = 0; + worker->cursor_trail_length = worker->cursor_trail_frequency = 0; } - worker->attached = FALSE; - worker->cursor_visible = TRUE; - worker->cursor_position.x = worker->cursor_position.y = 0; - worker->cursor_trail_length = worker->cursor_trail_frequency = 0; - + message = RED_WORKER_MESSAGE_READY; + write_message(worker->channel, &message); + break; + case RED_WORKER_MESSAGE_RESET_IMAGE_CACHE: image_cache_reset(&worker->image_cache); message = RED_WORKER_MESSAGE_READY; write_message(worker->channel, &message); break; + case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT: + handle_dev_destroy_surface_wait(worker); + break; + case RED_WORKER_MESSAGE_DESTROY_SURFACES: + handle_dev_destroy_surfaces(worker); + break; + case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE: + handle_dev_create_primary_surface(worker); + break; + case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE: + handle_dev_destroy_primary_surface(worker); + break; case RED_WORKER_MESSAGE_DISPLAY_CONNECT: { RedsStreamContext *peer; int migrate; @@ -8600,18 +9008,18 @@ static void handle_dev_input(EventListener *listener, uint32_t events) case RED_WORKER_MESSAGE_DEL_MEMSLOT: handle_dev_del_memslot(worker); break; - case RED_WORKER_MESSAGE_RESET_MEMSLOTS: - memset(worker->mem_slots, 0, sizeof(MemSlot) * worker->num_memslots); + case RED_WORKER_MESSAGE_RESET_MEMSLOTS: { + uint32_t i; + for (i = 0; i < worker->num_memslots_groups; ++i) { + memset(worker->mem_slots[i], 0, sizeof(MemSlot) * worker->num_memslots); + } break; + } default: red_error("message error"); } } -static void default_draw_context_destroy(void *canvas) -{ -} - static void red_init(RedWorker *worker, WorkerInitData *init_data) { struct epoll_event event; @@ -8628,10 +9036,10 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data) worker->dev_listener.refs = 1; worker->dev_listener.action = handle_dev_input; worker->cursor_visible = TRUE; - worker->draw_context.destroy = default_draw_context_destroy; ASSERT(init_data->num_renderers > 0); worker->num_renderers = init_data->num_renderers; memcpy(worker->renderers, init_data->renderers, sizeof(worker->renderers)); + worker->renderer = RED_RENDERER_INVALID; worker->mouse_mode = RED_MOUSE_MODE_SERVER; worker->image_compression = init_data->image_compression; worker->streaming_video = init_data->streaming_video; @@ -8639,6 +9047,7 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data) ring_init(&worker->current); image_cache_init(&worker->image_cache); drawables_init(worker); + cursor_items_init(worker); red_init_streams(worker); stat_init(&worker->add_stat, add_stat_name); stat_init(&worker->exclude_stat, exclude_stat_name); @@ -8662,9 +9071,11 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data) red_error("add channel failed, %s", strerror(errno)); } + worker->num_memslots_groups = init_data->num_memslots_groups; worker->num_memslots = init_data->num_memslots; worker->generation_bits = init_data->memslot_gen_bits; worker->mem_slot_bits = init_data->memslot_id_bits; + worker->internal_groupslot_id = init_data->internal_groupslot_id; red_create_mem_slots(worker); message = RED_WORKER_MESSAGE_READY; @@ -8701,12 +9112,14 @@ void *red_worker_main(void *arg) worker.epoll_timeout = MIN(red_get_streams_timout(&worker), worker.epoll_timeout); num_events = epoll_wait(worker.epoll, events, MAX_EPOLL_SOURCES, worker.epoll_timeout); red_handle_streams_timout(&worker); + if (worker.display_channel && worker.display_channel->glz_dict) { /* during migration, in the dest, the display channel can be initialized while the global lz data not since migrate data msg hasn't been recieved yet */ red_display_handle_glz_drawables_to_free(worker.display_channel); } + worker.epoll_timeout = INF_EPOLL_WAIT; if (num_events == -1) { if (errno != EINTR) { @@ -8732,7 +9145,7 @@ void *red_worker_main(void *arg) free(evt_listener); } - if (worker.attached && worker.running) { + if (worker.running) { red_process_cursor(&worker, MAX_PIPE_SIZE); red_process_commands(&worker, MAX_PIPE_SIZE); } @@ -8768,7 +9181,7 @@ static void dump_line(FILE *f, uint8_t* line, uint16_t n_pixel_bits, int width, #define RAM_PATH "/tmp/tmpfs" -static void dump_bitmap(RedWorker *worker, Bitmap *bitmap) +static void dump_bitmap(RedWorker *worker, Bitmap *bitmap, uint32_t group_id) { static uint32_t file_id = 0; @@ -8823,7 +9236,7 @@ static void dump_bitmap(RedWorker *worker, Bitmap *bitmap) if (!bitmap->palette) { return; // dont dump masks. } - plt = (Palette *)get_virt(worker, bitmap->palette, sizeof(Palette)); + plt = (Palette *)get_virt(worker, bitmap->palette, sizeof(Palette), group_id); } row_size = (((bitmap->x * n_pixel_bits) + 31) / 32) * 4; bitmap_data_offset = header_size; @@ -8879,7 +9292,8 @@ static void dump_bitmap(RedWorker *worker, Bitmap *bitmap) } /* writing the data */ if ((bitmap->flags & QXL_BITMAP_DIRECT)) { - uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, bitmap->stride * bitmap->y); + uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, bitmap->stride * bitmap->y, + group_id); int i; for (i = 0; i < bitmap->y; i++) { dump_line(f, lines + (i * bitmap->stride), n_pixel_bits, bitmap->x, row_size); @@ -8891,9 +9305,10 @@ static void dump_bitmap(RedWorker *worker, Bitmap *bitmap) while (relative_address) { int i; - chunk = (QXLDataChunk *)get_virt(worker, relative_address, sizeof(QXLDataChunk)); + chunk = (QXLDataChunk *)get_virt(worker, relative_address, sizeof(QXLDataChunk), + group_id); validate_virt(worker, chunk->data, get_memslot_id(worker, relative_address), - chunk->data_size); + chunk->data_size, group_id); num_lines = chunk->data_size / bitmap->stride; for (i = 0; i < num_lines; i++) { dump_line(f, chunk->data + (i * bitmap->stride), n_pixel_bits, bitmap->x, row_size); diff --git a/server/red_worker.h b/server/red_worker.h index e7080662..765b7d86 100644 --- a/server/red_worker.h +++ b/server/red_worker.h @@ -46,8 +46,6 @@ enum { RED_WORKER_MESSAGE_UPDATE, RED_WORKER_MESSAGE_WAKEUP, RED_WORKER_MESSAGE_OOM, - RED_WORKER_MESSAGE_ATTACH, - RED_WORKER_MESSAGE_DETACH, RED_WORKER_MESSAGE_READY, RED_WORKER_MESSAGE_DISPLAY_CONNECT, RED_WORKER_MESSAGE_DISPLAY_DISCONNECT, @@ -65,6 +63,12 @@ enum { RED_WORKER_MESSAGE_ADD_MEMSLOT, RED_WORKER_MESSAGE_DEL_MEMSLOT, RED_WORKER_MESSAGE_RESET_MEMSLOTS, + RED_WORKER_MESSAGE_DESTROY_SURFACES, + RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE, + RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE, + RED_WORKER_MESSAGE_RESET_CURSOR, + RED_WORKER_MESSAGE_RESET_IMAGE_CACHE, + RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT, }; typedef uint32_t RedWorkeMessage; @@ -88,8 +92,10 @@ typedef struct WorkerInitData { image_compression_t image_compression; int streaming_video; uint32_t num_memslots; + uint32_t num_memslots_groups; uint8_t memslot_gen_bits; uint8_t memslot_id_bits; + uint8_t internal_groupslot_id; } WorkerInitData; void *red_worker_main(void *arg); diff --git a/server/red_yuv.h b/server/red_yuv.h index 0bc25717..85597475 100644 --- a/server/red_yuv.h +++ b/server/red_yuv.h @@ -86,7 +86,7 @@ static inline void FUNC_NAME(red_rgb_to_yuv420_line)(const uint8_t* line0, const static inline int FUNC_NAME(red_rgb_to_yuv420)(RedWorker *worker, const Rect *src, const Bitmap *image, AVFrame *frame, long phys_delta, int memslot_id, int id, - Stream *stream) + Stream *stream, uint32_t group_id) { QXLDataChunk *chunk; uint32_t image_stride; @@ -108,16 +108,17 @@ static inline int FUNC_NAME(red_rgb_to_yuv420)(RedWorker *worker, const Rect *sr const int skip_lines = stream->top_down ? src->top : image->y - (src->bottom - 0); for (i = 0; i < skip_lines; i++) { - red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, memslot_id); + red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, memslot_id, + group_id); } const int image_hight = src->bottom - src->top; const int image_width = src->right - src->left; for (i = 0; i < image_hight / 2; i++) { uint8_t* line0 = red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, - memslot_id); + memslot_id, group_id); uint8_t* line1 = red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, - memslot_id); + memslot_id, group_id); if (!line0 || !line1) { return FALSE; @@ -135,7 +136,7 @@ static inline int FUNC_NAME(red_rgb_to_yuv420)(RedWorker *worker, const Rect *sr if ((image_hight & 1)) { uint8_t* line = red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, - memslot_id); + memslot_id, group_id); if (!line) { return FALSE; } diff --git a/server/vd_interface.h b/server/vd_interface.h index 89016dba..3adbf7e6 100644 --- a/server/vd_interface.h +++ b/server/vd_interface.h @@ -93,19 +93,20 @@ struct CoreInterface { }; #define VD_INTERFACE_QXL "qxl" -#define VD_INTERFACE_QXL_MAJOR 2 +#define VD_INTERFACE_QXL_MAJOR 3 #define VD_INTERFACE_QXL_MINOR 0 typedef struct QXLInterface QXLInterface; typedef void (*qxl_mode_change_notifier_t)(void *opaque); typedef struct QXLWorker QXLWorker; typedef struct QXLDevMemSlot QXLDevMemSlot; +typedef struct QXLDevSurfaceCreate QXLDevSurfaceCreate; union QXLReleaseInfo; +struct QXLReleaseInfoExt; struct QXLCommand; +struct QXLCommandExt; struct QXLWorker { uint32_t minor_version; uint32_t major_version; - void (*attach)(QXLWorker *worker); - void (*detach)(QXLWorker *worker); void (*wakeup)(QXLWorker *worker); void (*oom)(QXLWorker *worker); void (*save)(QXLWorker *worker); @@ -114,8 +115,15 @@ struct QXLWorker { void (*stop)(QXLWorker *worker); void (*update_area)(QXLWorker *worker); void (*add_memslot)(QXLWorker *worker, QXLDevMemSlot *slot); - void (*del_memslot)(QXLWorker *worker, uint32_t slot_id); + void (*del_memslot)(QXLWorker *worker, uint32_t slot_group_id, uint32_t slot_id); void (*reset_memslots)(QXLWorker *worker); + void (*destroy_surfaces)(QXLWorker *worker); + void (*destroy_primary_surface)(QXLWorker *worker, uint32_t surface_id); + void (*create_primary_surface)(QXLWorker *worker, uint32_t surface_id, + QXLDevSurfaceCreate *surface); + void (*reset_image_cache)(QXLWorker *worker); + void (*reset_cursor)(QXLWorker *worker); + void (*destroy_surface_wait)(QXLWorker *worker, uint32_t surface_id); }; typedef struct DrawArea { @@ -139,17 +147,35 @@ typedef struct QXLDevInfo { } QXLDevInfo; typedef struct QXLDevInitInfo { + uint32_t num_memslots_groups; uint32_t num_memslots; uint8_t memslot_gen_bits; uint8_t memslot_id_bits; + uint32_t qxl_ram_size; + uint8_t internal_groupslot_id; } QXLDevInitInfo; struct QXLDevMemSlot { + uint32_t slot_group_id; uint32_t slot_id; uint32_t generation; unsigned long virt_start; unsigned long virt_end; uint64_t addr_delta; + uint32_t qxl_ram_size; +}; + +struct QXLDevSurfaceCreate { + uint32_t width; + uint32_t height; + int32_t stride; + uint32_t depth; + uint32_t position; + uint32_t mouse_mode; + uint32_t flags; + uint32_t type; + uint64_t mem; + uint32_t group_id; }; struct QXLInterface { @@ -162,17 +188,13 @@ struct QXLInterface { void (*attache_worker)(QXLInterface *qxl, QXLWorker *qxl_worker); void (*set_compression_level)(QXLInterface *qxl, int level); void (*set_mm_time)(QXLInterface *qxl, uint32_t mm_time); - VDObjectRef (*register_mode_change)(QXLInterface *qxl, qxl_mode_change_notifier_t, - void *opaque); - void (*unregister_mode_change)(QXLInterface *qxl, VDObjectRef notifier); void (*get_init_info)(QXLInterface *qxl, QXLDevInitInfo *info); - void (*get_info)(QXLInterface *qxl, QXLDevInfo *info); - int (*get_command)(QXLInterface *qxl, struct QXLCommand *cmd); + int (*get_command)(QXLInterface *qxl, struct QXLCommandExt *cmd); int (*req_cmd_notification)(QXLInterface *qxl); int (*has_command)(QXLInterface *qxl); - void (*release_resource)(QXLInterface *qxl, union QXLReleaseInfo *release_info); - int (*get_cursor_command)(QXLInterface *qxl, struct QXLCommand *cmd); + void (*release_resource)(QXLInterface *qxl, struct QXLReleaseInfoExt release_info); + int (*get_cursor_command)(QXLInterface *qxl, struct QXLCommandExt *cmd); int (*req_cursor_notification)(QXLInterface *qxl); const struct Rect *(*get_update_area)(QXLInterface *qxl); void (*notify_update)(QXLInterface *qxl, uint32_t update_id); |