1a3e22260SGerd Hoffmann /* 2a3e22260SGerd Hoffmann * Copyright (C) 2010 Red Hat, Inc. 3a3e22260SGerd Hoffmann * 4a3e22260SGerd Hoffmann * This program is free software; you can redistribute it and/or 5a3e22260SGerd Hoffmann * modify it under the terms of the GNU General Public License as 6a3e22260SGerd Hoffmann * published by the Free Software Foundation; either version 2 or 7a3e22260SGerd Hoffmann * (at your option) version 3 of the License. 8a3e22260SGerd Hoffmann * 9a3e22260SGerd Hoffmann * This program is distributed in the hope that it will be useful, 10a3e22260SGerd Hoffmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 11a3e22260SGerd Hoffmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12a3e22260SGerd Hoffmann * GNU General Public License for more details. 13a3e22260SGerd Hoffmann * 14a3e22260SGerd Hoffmann * You should have received a copy of the GNU General Public License 15a3e22260SGerd Hoffmann * along with this program; if not, see <http://www.gnu.org/licenses/>. 16a3e22260SGerd Hoffmann */ 17a3e22260SGerd Hoffmann 18e16f4c87SPeter Maydell #include "qemu/osdep.h" 19a3e22260SGerd Hoffmann #include "qemu-common.h" 2028ecbaeeSPaolo Bonzini #include "ui/qemu-spice.h" 211de7afc9SPaolo Bonzini #include "qemu/timer.h" 221de7afc9SPaolo Bonzini #include "qemu/queue.h" 2328ecbaeeSPaolo Bonzini #include "ui/console.h" 249c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 25c480bb7dSAlon Levy #include "trace.h" 26a3e22260SGerd Hoffmann 2728ecbaeeSPaolo Bonzini #include "ui/spice-display.h" 28a3e22260SGerd Hoffmann 29a3e22260SGerd Hoffmann static int debug = 0; 30fe5c44f9SGerd Hoffmann bool spice_opengl; 31a3e22260SGerd Hoffmann 322c80e423SStefan Weil static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...) 33a3e22260SGerd Hoffmann { 34a3e22260SGerd Hoffmann va_list args; 35a3e22260SGerd Hoffmann 36a3e22260SGerd Hoffmann if (level <= debug) { 37a3e22260SGerd Hoffmann va_start(args, fmt); 38a3e22260SGerd Hoffmann vfprintf(stderr, fmt, args); 39a3e22260SGerd Hoffmann va_end(args); 40a3e22260SGerd Hoffmann } 41a3e22260SGerd Hoffmann } 42a3e22260SGerd Hoffmann 43a3e22260SGerd Hoffmann int qemu_spice_rect_is_empty(const QXLRect* r) 44a3e22260SGerd Hoffmann { 45a3e22260SGerd Hoffmann return r->top == r->bottom || r->left == r->right; 46a3e22260SGerd Hoffmann } 47a3e22260SGerd Hoffmann 48a3e22260SGerd Hoffmann void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) 49a3e22260SGerd Hoffmann { 50a3e22260SGerd Hoffmann if (qemu_spice_rect_is_empty(r)) { 51a3e22260SGerd Hoffmann return; 52a3e22260SGerd Hoffmann } 53a3e22260SGerd Hoffmann 54a3e22260SGerd Hoffmann if (qemu_spice_rect_is_empty(dest)) { 55a3e22260SGerd Hoffmann *dest = *r; 56a3e22260SGerd Hoffmann return; 57a3e22260SGerd Hoffmann } 58a3e22260SGerd Hoffmann 59a3e22260SGerd Hoffmann dest->top = MIN(dest->top, r->top); 60a3e22260SGerd Hoffmann dest->left = MIN(dest->left, r->left); 61a3e22260SGerd Hoffmann dest->bottom = MAX(dest->bottom, r->bottom); 62a3e22260SGerd Hoffmann dest->right = MAX(dest->right, r->right); 63a3e22260SGerd Hoffmann } 64a3e22260SGerd Hoffmann 652e1a98c9SAlon Levy QXLCookie *qxl_cookie_new(int type, uint64_t io) 662e1a98c9SAlon Levy { 672e1a98c9SAlon Levy QXLCookie *cookie; 682e1a98c9SAlon Levy 692e1a98c9SAlon Levy cookie = g_malloc0(sizeof(*cookie)); 702e1a98c9SAlon Levy cookie->type = type; 712e1a98c9SAlon Levy cookie->io = io; 722e1a98c9SAlon Levy return cookie; 732e1a98c9SAlon Levy } 742e1a98c9SAlon Levy 755ff4e36cSAlon Levy void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, 765ff4e36cSAlon Levy qxl_async_io async) 775c59d118SGerd Hoffmann { 78c480bb7dSAlon Levy trace_qemu_spice_add_memslot(ssd->qxl.id, memslot->slot_id, 79c480bb7dSAlon Levy memslot->virt_start, memslot->virt_end, 80c480bb7dSAlon Levy async); 81c480bb7dSAlon Levy 825ff4e36cSAlon Levy if (async != QXL_SYNC) { 832e1a98c9SAlon Levy spice_qxl_add_memslot_async(&ssd->qxl, memslot, 8434d14c6dSPeter Maydell (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, 852e1a98c9SAlon Levy QXL_IO_MEMSLOT_ADD_ASYNC)); 865ff4e36cSAlon Levy } else { 8726defe81SMarc-André Lureau spice_qxl_add_memslot(&ssd->qxl, memslot); 885c59d118SGerd Hoffmann } 895ff4e36cSAlon Levy } 905c59d118SGerd Hoffmann 915c59d118SGerd Hoffmann void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) 925c59d118SGerd Hoffmann { 93c480bb7dSAlon Levy trace_qemu_spice_del_memslot(ssd->qxl.id, gid, sid); 9426defe81SMarc-André Lureau spice_qxl_del_memslot(&ssd->qxl, gid, sid); 955c59d118SGerd Hoffmann } 965c59d118SGerd Hoffmann 975c59d118SGerd Hoffmann void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, 985ff4e36cSAlon Levy QXLDevSurfaceCreate *surface, 995ff4e36cSAlon Levy qxl_async_io async) 1005c59d118SGerd Hoffmann { 101c480bb7dSAlon Levy trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async); 1025ff4e36cSAlon Levy if (async != QXL_SYNC) { 1032e1a98c9SAlon Levy spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 10434d14c6dSPeter Maydell (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, 1052e1a98c9SAlon Levy QXL_IO_CREATE_PRIMARY_ASYNC)); 1065ff4e36cSAlon Levy } else { 10726defe81SMarc-André Lureau spice_qxl_create_primary_surface(&ssd->qxl, id, surface); 1085c59d118SGerd Hoffmann } 1095ff4e36cSAlon Levy } 1105c59d118SGerd Hoffmann 1115ff4e36cSAlon Levy void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, 1125ff4e36cSAlon Levy uint32_t id, qxl_async_io async) 1135c59d118SGerd Hoffmann { 114c480bb7dSAlon Levy trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async); 1155ff4e36cSAlon Levy if (async != QXL_SYNC) { 1162e1a98c9SAlon Levy spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 11734d14c6dSPeter Maydell (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, 1182e1a98c9SAlon Levy QXL_IO_DESTROY_PRIMARY_ASYNC)); 1195ff4e36cSAlon Levy } else { 12026defe81SMarc-André Lureau spice_qxl_destroy_primary_surface(&ssd->qxl, id); 1215c59d118SGerd Hoffmann } 1225ff4e36cSAlon Levy } 1235c59d118SGerd Hoffmann 1245c59d118SGerd Hoffmann void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) 1255c59d118SGerd Hoffmann { 126c480bb7dSAlon Levy trace_qemu_spice_wakeup(ssd->qxl.id); 12726defe81SMarc-André Lureau spice_qxl_wakeup(&ssd->qxl); 1285c59d118SGerd Hoffmann } 1295c59d118SGerd Hoffmann 130c60319a3SGerd Hoffmann static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, 131c60319a3SGerd Hoffmann QXLRect *rect) 132a3e22260SGerd Hoffmann { 133a3e22260SGerd Hoffmann SimpleSpiceUpdate *update; 134a3e22260SGerd Hoffmann QXLDrawable *drawable; 135a3e22260SGerd Hoffmann QXLImage *image; 136a3e22260SGerd Hoffmann QXLCommand *cmd; 137d9a86569SGerd Hoffmann int bw, bh; 13822795174SAlon Levy struct timespec time_space; 139d9a86569SGerd Hoffmann pixman_image_t *dest; 140a3e22260SGerd Hoffmann 141c480bb7dSAlon Levy trace_qemu_spice_create_update( 142c60319a3SGerd Hoffmann rect->left, rect->right, 143c60319a3SGerd Hoffmann rect->top, rect->bottom); 144a3e22260SGerd Hoffmann 1457267c094SAnthony Liguori update = g_malloc0(sizeof(*update)); 146a3e22260SGerd Hoffmann drawable = &update->drawable; 147a3e22260SGerd Hoffmann image = &update->image; 148a3e22260SGerd Hoffmann cmd = &update->ext.cmd; 149a3e22260SGerd Hoffmann 150c60319a3SGerd Hoffmann bw = rect->right - rect->left; 151c60319a3SGerd Hoffmann bh = rect->bottom - rect->top; 1527267c094SAnthony Liguori update->bitmap = g_malloc(bw * bh * 4); 153a3e22260SGerd Hoffmann 154c60319a3SGerd Hoffmann drawable->bbox = *rect; 155a3e22260SGerd Hoffmann drawable->clip.type = SPICE_CLIP_TYPE_NONE; 156a3e22260SGerd Hoffmann drawable->effect = QXL_EFFECT_OPAQUE; 1575643fc01SGerd Hoffmann drawable->release_info.id = (uintptr_t)(&update->ext); 158a3e22260SGerd Hoffmann drawable->type = QXL_DRAW_COPY; 159a3e22260SGerd Hoffmann drawable->surfaces_dest[0] = -1; 160a3e22260SGerd Hoffmann drawable->surfaces_dest[1] = -1; 161a3e22260SGerd Hoffmann drawable->surfaces_dest[2] = -1; 16222795174SAlon Levy clock_gettime(CLOCK_MONOTONIC, &time_space); 16322795174SAlon Levy /* time in milliseconds from epoch. */ 16422795174SAlon Levy drawable->mm_time = time_space.tv_sec * 1000 16522795174SAlon Levy + time_space.tv_nsec / 1000 / 1000; 166a3e22260SGerd Hoffmann 167a3e22260SGerd Hoffmann drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; 168a13ccc99SAlon Levy drawable->u.copy.src_bitmap = (uintptr_t)image; 169a3e22260SGerd Hoffmann drawable->u.copy.src_area.right = bw; 170a3e22260SGerd Hoffmann drawable->u.copy.src_area.bottom = bh; 171a3e22260SGerd Hoffmann 172a3e22260SGerd Hoffmann QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++); 173a3e22260SGerd Hoffmann image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP; 174a3e22260SGerd Hoffmann image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN; 175a3e22260SGerd Hoffmann image->bitmap.stride = bw * 4; 176a3e22260SGerd Hoffmann image->descriptor.width = image->bitmap.x = bw; 177a3e22260SGerd Hoffmann image->descriptor.height = image->bitmap.y = bh; 178a13ccc99SAlon Levy image->bitmap.data = (uintptr_t)(update->bitmap); 179a3e22260SGerd Hoffmann image->bitmap.palette = 0; 180a3e22260SGerd Hoffmann image->bitmap.format = SPICE_BITMAP_FMT_32BIT; 181a3e22260SGerd Hoffmann 182c1d37cd3SGerd Hoffmann dest = pixman_image_create_bits(PIXMAN_LE_x8r8g8b8, bw, bh, 183d9a86569SGerd Hoffmann (void *)update->bitmap, bw * 4); 184d9a86569SGerd Hoffmann pixman_image_composite(PIXMAN_OP_SRC, ssd->surface, NULL, ssd->mirror, 185d9a86569SGerd Hoffmann rect->left, rect->top, 0, 0, 186d9a86569SGerd Hoffmann rect->left, rect->top, bw, bh); 187d9a86569SGerd Hoffmann pixman_image_composite(PIXMAN_OP_SRC, ssd->mirror, NULL, dest, 188d9a86569SGerd Hoffmann rect->left, rect->top, 0, 0, 189d9a86569SGerd Hoffmann 0, 0, bw, bh); 190d9a86569SGerd Hoffmann pixman_image_unref(dest); 191a3e22260SGerd Hoffmann 192a3e22260SGerd Hoffmann cmd->type = QXL_CMD_DRAW; 193a13ccc99SAlon Levy cmd->data = (uintptr_t)drawable; 194a3e22260SGerd Hoffmann 195b1af98baSGerd Hoffmann QTAILQ_INSERT_TAIL(&ssd->updates, update, next); 196a3e22260SGerd Hoffmann } 197a3e22260SGerd Hoffmann 198c60319a3SGerd Hoffmann static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) 199c60319a3SGerd Hoffmann { 200b021bd29SGerd Hoffmann static const int blksize = 32; 2015d61cafdSLaurent Vivier int blocks = DIV_ROUND_UP(surface_width(ssd->ds), blksize); 202b021bd29SGerd Hoffmann int dirty_top[blocks]; 203c6e48470SGerd Hoffmann int y, yoff1, yoff2, x, xoff, blk, bw; 20471874c17SGerd Hoffmann int bpp = surface_bytes_per_pixel(ssd->ds); 205b021bd29SGerd Hoffmann uint8_t *guest, *mirror; 206b021bd29SGerd Hoffmann 207c60319a3SGerd Hoffmann if (qemu_spice_rect_is_empty(&ssd->dirty)) { 208c60319a3SGerd Hoffmann return; 209c60319a3SGerd Hoffmann }; 210a7310dd3SGerd Hoffmann 211b021bd29SGerd Hoffmann for (blk = 0; blk < blocks; blk++) { 212b021bd29SGerd Hoffmann dirty_top[blk] = -1; 213b021bd29SGerd Hoffmann } 214b021bd29SGerd Hoffmann 21571874c17SGerd Hoffmann guest = surface_data(ssd->ds); 216d9a86569SGerd Hoffmann mirror = (void *)pixman_image_get_data(ssd->mirror); 217b021bd29SGerd Hoffmann for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { 218c6e48470SGerd Hoffmann yoff1 = y * surface_stride(ssd->ds); 219c6e48470SGerd Hoffmann yoff2 = y * pixman_image_get_stride(ssd->mirror); 220b021bd29SGerd Hoffmann for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { 221b021bd29SGerd Hoffmann xoff = x * bpp; 222b021bd29SGerd Hoffmann blk = x / blksize; 223b021bd29SGerd Hoffmann bw = MIN(blksize, ssd->dirty.right - x); 224c6e48470SGerd Hoffmann if (memcmp(guest + yoff1 + xoff, 225c6e48470SGerd Hoffmann mirror + yoff2 + xoff, 226b021bd29SGerd Hoffmann bw * bpp) == 0) { 227b021bd29SGerd Hoffmann if (dirty_top[blk] != -1) { 228b021bd29SGerd Hoffmann QXLRect update = { 229b021bd29SGerd Hoffmann .top = dirty_top[blk], 230b021bd29SGerd Hoffmann .bottom = y, 231b021bd29SGerd Hoffmann .left = x, 232b021bd29SGerd Hoffmann .right = x + bw, 233b021bd29SGerd Hoffmann }; 234b021bd29SGerd Hoffmann qemu_spice_create_one_update(ssd, &update); 235b021bd29SGerd Hoffmann dirty_top[blk] = -1; 236b021bd29SGerd Hoffmann } 237b021bd29SGerd Hoffmann } else { 238b021bd29SGerd Hoffmann if (dirty_top[blk] == -1) { 239b021bd29SGerd Hoffmann dirty_top[blk] = y; 240b021bd29SGerd Hoffmann } 241b021bd29SGerd Hoffmann } 242b021bd29SGerd Hoffmann } 243b021bd29SGerd Hoffmann } 244b021bd29SGerd Hoffmann 245b021bd29SGerd Hoffmann for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { 246b021bd29SGerd Hoffmann blk = x / blksize; 247b021bd29SGerd Hoffmann bw = MIN(blksize, ssd->dirty.right - x); 248b021bd29SGerd Hoffmann if (dirty_top[blk] != -1) { 249b021bd29SGerd Hoffmann QXLRect update = { 250b021bd29SGerd Hoffmann .top = dirty_top[blk], 251b021bd29SGerd Hoffmann .bottom = ssd->dirty.bottom, 252b021bd29SGerd Hoffmann .left = x, 253b021bd29SGerd Hoffmann .right = x + bw, 254b021bd29SGerd Hoffmann }; 255b021bd29SGerd Hoffmann qemu_spice_create_one_update(ssd, &update); 256b021bd29SGerd Hoffmann dirty_top[blk] = -1; 257b021bd29SGerd Hoffmann } 258b021bd29SGerd Hoffmann } 259b021bd29SGerd Hoffmann 260c60319a3SGerd Hoffmann memset(&ssd->dirty, 0, sizeof(ssd->dirty)); 261c60319a3SGerd Hoffmann } 262c60319a3SGerd Hoffmann 2635643fc01SGerd Hoffmann static SimpleSpiceCursor* 2645643fc01SGerd Hoffmann qemu_spice_create_cursor_update(SimpleSpiceDisplay *ssd, 265700cd855SMarc-André Lureau QEMUCursor *c, 266700cd855SMarc-André Lureau int on) 2675643fc01SGerd Hoffmann { 2685643fc01SGerd Hoffmann size_t size = c ? c->width * c->height * 4 : 0; 2695643fc01SGerd Hoffmann SimpleSpiceCursor *update; 2705643fc01SGerd Hoffmann QXLCursorCmd *ccmd; 2715643fc01SGerd Hoffmann QXLCursor *cursor; 2725643fc01SGerd Hoffmann QXLCommand *cmd; 2735643fc01SGerd Hoffmann 2745643fc01SGerd Hoffmann update = g_malloc0(sizeof(*update) + size); 2755643fc01SGerd Hoffmann ccmd = &update->cmd; 2765643fc01SGerd Hoffmann cursor = &update->cursor; 2775643fc01SGerd Hoffmann cmd = &update->ext.cmd; 2785643fc01SGerd Hoffmann 2795643fc01SGerd Hoffmann if (c) { 2805643fc01SGerd Hoffmann ccmd->type = QXL_CURSOR_SET; 281dc8dceeeSMarc-André Lureau ccmd->u.set.position.x = ssd->ptr_x + ssd->hot_x; 282dc8dceeeSMarc-André Lureau ccmd->u.set.position.y = ssd->ptr_y + ssd->hot_y; 2835643fc01SGerd Hoffmann ccmd->u.set.visible = true; 2845643fc01SGerd Hoffmann ccmd->u.set.shape = (uintptr_t)cursor; 2855643fc01SGerd Hoffmann cursor->header.unique = ssd->unique++; 2865643fc01SGerd Hoffmann cursor->header.type = SPICE_CURSOR_TYPE_ALPHA; 2875643fc01SGerd Hoffmann cursor->header.width = c->width; 2885643fc01SGerd Hoffmann cursor->header.height = c->height; 2895643fc01SGerd Hoffmann cursor->header.hot_spot_x = c->hot_x; 2905643fc01SGerd Hoffmann cursor->header.hot_spot_y = c->hot_y; 2915643fc01SGerd Hoffmann cursor->data_size = size; 2925643fc01SGerd Hoffmann cursor->chunk.data_size = size; 2935643fc01SGerd Hoffmann memcpy(cursor->chunk.data, c->data, size); 294700cd855SMarc-André Lureau } else if (!on) { 295700cd855SMarc-André Lureau ccmd->type = QXL_CURSOR_HIDE; 2965643fc01SGerd Hoffmann } else { 2975643fc01SGerd Hoffmann ccmd->type = QXL_CURSOR_MOVE; 298dc8dceeeSMarc-André Lureau ccmd->u.position.x = ssd->ptr_x + ssd->hot_x; 299dc8dceeeSMarc-André Lureau ccmd->u.position.y = ssd->ptr_y + ssd->hot_y; 3005643fc01SGerd Hoffmann } 3015643fc01SGerd Hoffmann ccmd->release_info.id = (uintptr_t)(&update->ext); 3025643fc01SGerd Hoffmann 3035643fc01SGerd Hoffmann cmd->type = QXL_CMD_CURSOR; 3045643fc01SGerd Hoffmann cmd->data = (uintptr_t)ccmd; 3055643fc01SGerd Hoffmann 3065643fc01SGerd Hoffmann return update; 3075643fc01SGerd Hoffmann } 3085643fc01SGerd Hoffmann 309a3e22260SGerd Hoffmann /* 3104580c490SStefan Weil * Called from spice server thread context (via interface_release_resource) 311a3e22260SGerd Hoffmann * We do *not* hold the global qemu mutex here, so extra care is needed 3125cbdb3a3SStefan Weil * when calling qemu functions. QEMU interfaces used: 3137267c094SAnthony Liguori * - g_free (underlying glibc free is re-entrant). 314a3e22260SGerd Hoffmann */ 315a3e22260SGerd Hoffmann void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update) 316a3e22260SGerd Hoffmann { 3177267c094SAnthony Liguori g_free(update->bitmap); 3187267c094SAnthony Liguori g_free(update); 319a3e22260SGerd Hoffmann } 320a3e22260SGerd Hoffmann 321a3e22260SGerd Hoffmann void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) 322a3e22260SGerd Hoffmann { 323a3e22260SGerd Hoffmann QXLDevMemSlot memslot; 324a3e22260SGerd Hoffmann 32535b2122dSGerd Hoffmann dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); 326a3e22260SGerd Hoffmann 327a3e22260SGerd Hoffmann memset(&memslot, 0, sizeof(memslot)); 328a3e22260SGerd Hoffmann memslot.slot_group_id = MEMSLOT_GROUP_HOST; 329a3e22260SGerd Hoffmann memslot.virt_end = ~0; 3305ff4e36cSAlon Levy qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC); 331a3e22260SGerd Hoffmann } 332a3e22260SGerd Hoffmann 333a3e22260SGerd Hoffmann void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) 334a3e22260SGerd Hoffmann { 335a3e22260SGerd Hoffmann QXLDevSurfaceCreate surface; 336ab9509ccSGerd Hoffmann uint64_t surface_size; 337a3e22260SGerd Hoffmann 338160c31f7SAlon Levy memset(&surface, 0, sizeof(surface)); 339160c31f7SAlon Levy 340ab9509ccSGerd Hoffmann surface_size = (uint64_t) surface_width(ssd->ds) * 341ab9509ccSGerd Hoffmann surface_height(ssd->ds) * 4; 342ab9509ccSGerd Hoffmann assert(surface_size > 0); 343ab9509ccSGerd Hoffmann assert(surface_size < INT_MAX); 344ab9509ccSGerd Hoffmann if (ssd->bufsize < surface_size) { 345ab9509ccSGerd Hoffmann ssd->bufsize = surface_size; 346ab9509ccSGerd Hoffmann g_free(ssd->buf); 347ab9509ccSGerd Hoffmann ssd->buf = g_malloc(ssd->bufsize); 348ab9509ccSGerd Hoffmann } 349ab9509ccSGerd Hoffmann 350ab9509ccSGerd Hoffmann dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id, 351ab9509ccSGerd Hoffmann surface_width(ssd->ds), surface_height(ssd->ds), 352ab9509ccSGerd Hoffmann surface_size, ssd->bufsize); 353a3e22260SGerd Hoffmann 354a3e22260SGerd Hoffmann surface.format = SPICE_SURFACE_FMT_32_xRGB; 35571874c17SGerd Hoffmann surface.width = surface_width(ssd->ds); 35671874c17SGerd Hoffmann surface.height = surface_height(ssd->ds); 357a3e22260SGerd Hoffmann surface.stride = -surface.width * 4; 358869564a9SGerd Hoffmann surface.mouse_mode = true; 359a3e22260SGerd Hoffmann surface.flags = 0; 360a3e22260SGerd Hoffmann surface.type = 0; 361a13ccc99SAlon Levy surface.mem = (uintptr_t)ssd->buf; 362a3e22260SGerd Hoffmann surface.group_id = MEMSLOT_GROUP_HOST; 3637466bc49SGerd Hoffmann 3645ff4e36cSAlon Levy qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC); 365a3e22260SGerd Hoffmann } 366a3e22260SGerd Hoffmann 367a3e22260SGerd Hoffmann void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) 368a3e22260SGerd Hoffmann { 36935b2122dSGerd Hoffmann dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); 370a3e22260SGerd Hoffmann 3715ff4e36cSAlon Levy qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); 372a3e22260SGerd Hoffmann } 373a3e22260SGerd Hoffmann 374c78f7137SGerd Hoffmann void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd) 375a963f876SGerd Hoffmann { 376a963f876SGerd Hoffmann qemu_mutex_init(&ssd->lock); 377b1af98baSGerd Hoffmann QTAILQ_INIT(&ssd->updates); 378a963f876SGerd Hoffmann ssd->mouse_x = -1; 379a963f876SGerd Hoffmann ssd->mouse_y = -1; 380ddd8fdc7SGerd Hoffmann if (ssd->num_surfaces == 0) { 381ddd8fdc7SGerd Hoffmann ssd->num_surfaces = 1024; 382ddd8fdc7SGerd Hoffmann } 383a963f876SGerd Hoffmann } 384a963f876SGerd Hoffmann 385a3e22260SGerd Hoffmann /* display listener callbacks */ 386a3e22260SGerd Hoffmann 387a3e22260SGerd Hoffmann void qemu_spice_display_update(SimpleSpiceDisplay *ssd, 388a3e22260SGerd Hoffmann int x, int y, int w, int h) 389a3e22260SGerd Hoffmann { 390a3e22260SGerd Hoffmann QXLRect update_area; 391a3e22260SGerd Hoffmann 39235b2122dSGerd Hoffmann dprint(2, "%s/%d: x %d y %d w %d h %d\n", __func__, 39335b2122dSGerd Hoffmann ssd->qxl.id, x, y, w, h); 394a3e22260SGerd Hoffmann update_area.left = x, 395a3e22260SGerd Hoffmann update_area.right = x + w; 396a3e22260SGerd Hoffmann update_area.top = y; 397a3e22260SGerd Hoffmann update_area.bottom = y + h; 398a3e22260SGerd Hoffmann 399a3e22260SGerd Hoffmann if (qemu_spice_rect_is_empty(&ssd->dirty)) { 400a3e22260SGerd Hoffmann ssd->notify++; 401a3e22260SGerd Hoffmann } 402a3e22260SGerd Hoffmann qemu_spice_rect_union(&ssd->dirty, &update_area); 403a3e22260SGerd Hoffmann } 404a3e22260SGerd Hoffmann 405c12aeb86SGerd Hoffmann void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, 406c12aeb86SGerd Hoffmann DisplaySurface *surface) 407a3e22260SGerd Hoffmann { 408b1af98baSGerd Hoffmann SimpleSpiceUpdate *update; 4094b87dc4cSGerd Hoffmann bool need_destroy; 410b1af98baSGerd Hoffmann 411555e72f2SGerd Hoffmann if (surface && ssd->surface && 412555e72f2SGerd Hoffmann surface_width(surface) == pixman_image_get_width(ssd->surface) && 413b2af43ccSGerd Hoffmann surface_height(surface) == pixman_image_get_height(ssd->surface) && 414b2af43ccSGerd Hoffmann surface_format(surface) == pixman_image_get_format(ssd->surface)) { 415555e72f2SGerd Hoffmann /* no-resize fast path: just swap backing store */ 416555e72f2SGerd Hoffmann dprint(1, "%s/%d: fast (%dx%d)\n", __func__, ssd->qxl.id, 417555e72f2SGerd Hoffmann surface_width(surface), surface_height(surface)); 418555e72f2SGerd Hoffmann qemu_mutex_lock(&ssd->lock); 419555e72f2SGerd Hoffmann ssd->ds = surface; 420555e72f2SGerd Hoffmann pixman_image_unref(ssd->surface); 421555e72f2SGerd Hoffmann ssd->surface = pixman_image_ref(ssd->ds->image); 422555e72f2SGerd Hoffmann qemu_mutex_unlock(&ssd->lock); 423555e72f2SGerd Hoffmann qemu_spice_display_update(ssd, 0, 0, 424555e72f2SGerd Hoffmann surface_width(surface), 425555e72f2SGerd Hoffmann surface_height(surface)); 426555e72f2SGerd Hoffmann return; 427555e72f2SGerd Hoffmann } 428555e72f2SGerd Hoffmann 429555e72f2SGerd Hoffmann /* full mode switch */ 430555e72f2SGerd Hoffmann dprint(1, "%s/%d: full (%dx%d -> %dx%d)\n", __func__, ssd->qxl.id, 431555e72f2SGerd Hoffmann ssd->surface ? pixman_image_get_width(ssd->surface) : 0, 432555e72f2SGerd Hoffmann ssd->surface ? pixman_image_get_height(ssd->surface) : 0, 433555e72f2SGerd Hoffmann surface ? surface_width(surface) : 0, 434555e72f2SGerd Hoffmann surface ? surface_height(surface) : 0); 435a3e22260SGerd Hoffmann 436a3e22260SGerd Hoffmann memset(&ssd->dirty, 0, sizeof(ssd->dirty)); 437d9a86569SGerd Hoffmann if (ssd->surface) { 438d9a86569SGerd Hoffmann pixman_image_unref(ssd->surface); 439d9a86569SGerd Hoffmann ssd->surface = NULL; 440d9a86569SGerd Hoffmann pixman_image_unref(ssd->mirror); 441d9a86569SGerd Hoffmann ssd->mirror = NULL; 442d9a86569SGerd Hoffmann } 443a3e22260SGerd Hoffmann 444e0c64d08SGerd Hoffmann qemu_mutex_lock(&ssd->lock); 4454b87dc4cSGerd Hoffmann need_destroy = (ssd->ds != NULL); 44671874c17SGerd Hoffmann ssd->ds = surface; 447b1af98baSGerd Hoffmann while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { 448b1af98baSGerd Hoffmann QTAILQ_REMOVE(&ssd->updates, update, next); 449b1af98baSGerd Hoffmann qemu_spice_destroy_update(ssd, update); 450e0c64d08SGerd Hoffmann } 451e0c64d08SGerd Hoffmann qemu_mutex_unlock(&ssd->lock); 4524b87dc4cSGerd Hoffmann if (need_destroy) { 453a3e22260SGerd Hoffmann qemu_spice_destroy_host_primary(ssd); 4544b87dc4cSGerd Hoffmann } 4554b87dc4cSGerd Hoffmann if (ssd->ds) { 45651a09099SGerd Hoffmann ssd->surface = pixman_image_ref(ssd->ds->image); 45751a09099SGerd Hoffmann ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, 45851a09099SGerd Hoffmann ssd->ds->image); 459a3e22260SGerd Hoffmann qemu_spice_create_host_primary(ssd); 4604b87dc4cSGerd Hoffmann } 461a3e22260SGerd Hoffmann 462a3e22260SGerd Hoffmann memset(&ssd->dirty, 0, sizeof(ssd->dirty)); 463a3e22260SGerd Hoffmann ssd->notify++; 46458c7b618SMarc-André Lureau 46558c7b618SMarc-André Lureau qemu_mutex_lock(&ssd->lock); 46658c7b618SMarc-André Lureau if (ssd->cursor) { 46758c7b618SMarc-André Lureau g_free(ssd->ptr_define); 46858c7b618SMarc-André Lureau ssd->ptr_define = qemu_spice_create_cursor_update(ssd, ssd->cursor, 0); 46958c7b618SMarc-André Lureau } 47058c7b618SMarc-André Lureau qemu_mutex_unlock(&ssd->lock); 471a3e22260SGerd Hoffmann } 472a3e22260SGerd Hoffmann 4730b2824e5SGerd Hoffmann static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) 474a3e22260SGerd Hoffmann { 47507536094SGerd Hoffmann if (ssd->cursor) { 476284d1c6bSGerd Hoffmann assert(ssd->dcl.con); 477284d1c6bSGerd Hoffmann dpy_cursor_define(ssd->dcl.con, ssd->cursor); 47807536094SGerd Hoffmann } 47907536094SGerd Hoffmann if (ssd->mouse_x != -1 && ssd->mouse_y != -1) { 480284d1c6bSGerd Hoffmann assert(ssd->dcl.con); 481284d1c6bSGerd Hoffmann dpy_mouse_set(ssd->dcl.con, ssd->mouse_x, ssd->mouse_y, 1); 48207536094SGerd Hoffmann ssd->mouse_x = -1; 48307536094SGerd Hoffmann ssd->mouse_y = -1; 48407536094SGerd Hoffmann } 485bb5a8cd5SAlon Levy } 486bb5a8cd5SAlon Levy 4870b2824e5SGerd Hoffmann void qemu_spice_cursor_refresh_bh(void *opaque) 4880b2824e5SGerd Hoffmann { 4890b2824e5SGerd Hoffmann SimpleSpiceDisplay *ssd = opaque; 4900b2824e5SGerd Hoffmann 4910b2824e5SGerd Hoffmann qemu_mutex_lock(&ssd->lock); 4920b2824e5SGerd Hoffmann qemu_spice_cursor_refresh_unlocked(ssd); 4930b2824e5SGerd Hoffmann qemu_mutex_unlock(&ssd->lock); 4940b2824e5SGerd Hoffmann } 4950b2824e5SGerd Hoffmann 496bb5a8cd5SAlon Levy void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) 497bb5a8cd5SAlon Levy { 49835b2122dSGerd Hoffmann dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); 499284d1c6bSGerd Hoffmann graphic_hw_update(ssd->dcl.con); 500bb5a8cd5SAlon Levy 501bb5a8cd5SAlon Levy qemu_mutex_lock(&ssd->lock); 50271874c17SGerd Hoffmann if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) { 503b1af98baSGerd Hoffmann qemu_spice_create_update(ssd); 504bb5a8cd5SAlon Levy ssd->notify++; 505bb5a8cd5SAlon Levy } 506e0c64d08SGerd Hoffmann qemu_mutex_unlock(&ssd->lock); 507e0c64d08SGerd Hoffmann 508a3e22260SGerd Hoffmann if (ssd->notify) { 509a3e22260SGerd Hoffmann ssd->notify = 0; 5105c59d118SGerd Hoffmann qemu_spice_wakeup(ssd); 51135b2122dSGerd Hoffmann dprint(2, "%s/%d: notify\n", __func__, ssd->qxl.id); 512a3e22260SGerd Hoffmann } 513a3e22260SGerd Hoffmann } 514a3e22260SGerd Hoffmann 515a3e22260SGerd Hoffmann /* spice display interface callbacks */ 516a3e22260SGerd Hoffmann 517a3e22260SGerd Hoffmann static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) 518a3e22260SGerd Hoffmann { 519a3e22260SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); 520a3e22260SGerd Hoffmann 52135b2122dSGerd Hoffmann dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); 522a3e22260SGerd Hoffmann } 523a3e22260SGerd Hoffmann 524a3e22260SGerd Hoffmann static void interface_set_compression_level(QXLInstance *sin, int level) 525a3e22260SGerd Hoffmann { 52635b2122dSGerd Hoffmann dprint(1, "%s/%d:\n", __func__, sin->id); 527a3e22260SGerd Hoffmann /* nothing to do */ 528a3e22260SGerd Hoffmann } 529a3e22260SGerd Hoffmann 530015e02f8SJohn Snow #if SPICE_NEEDS_SET_MM_TIME 531a3e22260SGerd Hoffmann static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) 532a3e22260SGerd Hoffmann { 53335b2122dSGerd Hoffmann dprint(3, "%s/%d:\n", __func__, sin->id); 534a3e22260SGerd Hoffmann /* nothing to do */ 535a3e22260SGerd Hoffmann } 536015e02f8SJohn Snow #endif 537a3e22260SGerd Hoffmann 538a3e22260SGerd Hoffmann static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) 539a3e22260SGerd Hoffmann { 540a3e22260SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); 541a3e22260SGerd Hoffmann 542a3e22260SGerd Hoffmann info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; 543a3e22260SGerd Hoffmann info->memslot_id_bits = MEMSLOT_SLOT_BITS; 544a3e22260SGerd Hoffmann info->num_memslots = NUM_MEMSLOTS; 545a3e22260SGerd Hoffmann info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; 546a3e22260SGerd Hoffmann info->internal_groupslot_id = 0; 547ab9509ccSGerd Hoffmann info->qxl_ram_size = 16 * 1024 * 1024; 548ddd8fdc7SGerd Hoffmann info->n_surfaces = ssd->num_surfaces; 549a3e22260SGerd Hoffmann } 550a3e22260SGerd Hoffmann 551c9f88ce3SChih-Min Chao static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext) 552a3e22260SGerd Hoffmann { 553a3e22260SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); 554a3e22260SGerd Hoffmann SimpleSpiceUpdate *update; 555e0c64d08SGerd Hoffmann int ret = false; 556a3e22260SGerd Hoffmann 55735b2122dSGerd Hoffmann dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); 558e0c64d08SGerd Hoffmann 559e0c64d08SGerd Hoffmann qemu_mutex_lock(&ssd->lock); 560b1af98baSGerd Hoffmann update = QTAILQ_FIRST(&ssd->updates); 561b1af98baSGerd Hoffmann if (update != NULL) { 562b1af98baSGerd Hoffmann QTAILQ_REMOVE(&ssd->updates, update, next); 563a3e22260SGerd Hoffmann *ext = update->ext; 564e0c64d08SGerd Hoffmann ret = true; 565e0c64d08SGerd Hoffmann } 566e0c64d08SGerd Hoffmann qemu_mutex_unlock(&ssd->lock); 567e0c64d08SGerd Hoffmann 568e0c64d08SGerd Hoffmann return ret; 569a3e22260SGerd Hoffmann } 570a3e22260SGerd Hoffmann 571a3e22260SGerd Hoffmann static int interface_req_cmd_notification(QXLInstance *sin) 572a3e22260SGerd Hoffmann { 57322672a37SGerd Hoffmann dprint(2, "%s/%d:\n", __func__, sin->id); 574a3e22260SGerd Hoffmann return 1; 575a3e22260SGerd Hoffmann } 576a3e22260SGerd Hoffmann 577a3e22260SGerd Hoffmann static void interface_release_resource(QXLInstance *sin, 578c9f88ce3SChih-Min Chao QXLReleaseInfoExt rext) 579a3e22260SGerd Hoffmann { 580a3e22260SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); 5815643fc01SGerd Hoffmann SimpleSpiceUpdate *update; 5825643fc01SGerd Hoffmann SimpleSpiceCursor *cursor; 5835643fc01SGerd Hoffmann QXLCommandExt *ext; 584a3e22260SGerd Hoffmann 58535b2122dSGerd Hoffmann dprint(2, "%s/%d:\n", __func__, ssd->qxl.id); 586e8e23b7dSGerd Hoffmann ext = (void *)(intptr_t)(rext.info->id); 5875643fc01SGerd Hoffmann switch (ext->cmd.type) { 5885643fc01SGerd Hoffmann case QXL_CMD_DRAW: 5895643fc01SGerd Hoffmann update = container_of(ext, SimpleSpiceUpdate, ext); 5905643fc01SGerd Hoffmann qemu_spice_destroy_update(ssd, update); 5915643fc01SGerd Hoffmann break; 5925643fc01SGerd Hoffmann case QXL_CMD_CURSOR: 5935643fc01SGerd Hoffmann cursor = container_of(ext, SimpleSpiceCursor, ext); 5945643fc01SGerd Hoffmann g_free(cursor); 5955643fc01SGerd Hoffmann break; 5965643fc01SGerd Hoffmann default: 5975643fc01SGerd Hoffmann g_assert_not_reached(); 5985643fc01SGerd Hoffmann } 599a3e22260SGerd Hoffmann } 600a3e22260SGerd Hoffmann 601c9f88ce3SChih-Min Chao static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext) 602a3e22260SGerd Hoffmann { 6035643fc01SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); 6045643fc01SGerd Hoffmann int ret; 6055643fc01SGerd Hoffmann 6065643fc01SGerd Hoffmann dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); 6075643fc01SGerd Hoffmann 6085643fc01SGerd Hoffmann qemu_mutex_lock(&ssd->lock); 6095643fc01SGerd Hoffmann if (ssd->ptr_define) { 6105643fc01SGerd Hoffmann *ext = ssd->ptr_define->ext; 6115643fc01SGerd Hoffmann ssd->ptr_define = NULL; 6125643fc01SGerd Hoffmann ret = true; 6135643fc01SGerd Hoffmann } else if (ssd->ptr_move) { 6145643fc01SGerd Hoffmann *ext = ssd->ptr_move->ext; 6155643fc01SGerd Hoffmann ssd->ptr_move = NULL; 6165643fc01SGerd Hoffmann ret = true; 6175643fc01SGerd Hoffmann } else { 6185643fc01SGerd Hoffmann ret = false; 6195643fc01SGerd Hoffmann } 6205643fc01SGerd Hoffmann qemu_mutex_unlock(&ssd->lock); 6215643fc01SGerd Hoffmann return ret; 622a3e22260SGerd Hoffmann } 623a3e22260SGerd Hoffmann 624a3e22260SGerd Hoffmann static int interface_req_cursor_notification(QXLInstance *sin) 625a3e22260SGerd Hoffmann { 62622672a37SGerd Hoffmann dprint(2, "%s:\n", __func__); 627a3e22260SGerd Hoffmann return 1; 628a3e22260SGerd Hoffmann } 629a3e22260SGerd Hoffmann 630a3e22260SGerd Hoffmann static void interface_notify_update(QXLInstance *sin, uint32_t update_id) 631a3e22260SGerd Hoffmann { 632*a89f364aSAlistair Francis fprintf(stderr, "%s: abort()\n", __func__); 633a3e22260SGerd Hoffmann abort(); 634a3e22260SGerd Hoffmann } 635a3e22260SGerd Hoffmann 636a3e22260SGerd Hoffmann static int interface_flush_resources(QXLInstance *sin) 637a3e22260SGerd Hoffmann { 638*a89f364aSAlistair Francis fprintf(stderr, "%s: abort()\n", __func__); 639a3e22260SGerd Hoffmann abort(); 640a3e22260SGerd Hoffmann return 0; 641a3e22260SGerd Hoffmann } 642a3e22260SGerd Hoffmann 64321a50d0bSGerd Hoffmann static void interface_update_area_complete(QXLInstance *sin, 64421a50d0bSGerd Hoffmann uint32_t surface_id, 64521a50d0bSGerd Hoffmann QXLRect *dirty, uint32_t num_updated_rects) 64621a50d0bSGerd Hoffmann { 64721a50d0bSGerd Hoffmann /* should never be called, used in qxl native mode only */ 64821a50d0bSGerd Hoffmann fprintf(stderr, "%s: abort()\n", __func__); 64921a50d0bSGerd Hoffmann abort(); 65021a50d0bSGerd Hoffmann } 65121a50d0bSGerd Hoffmann 65221a50d0bSGerd Hoffmann /* called from spice server thread context only */ 65321a50d0bSGerd Hoffmann static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) 65421a50d0bSGerd Hoffmann { 655474114b7SGerd Hoffmann QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token; 656474114b7SGerd Hoffmann 657474114b7SGerd Hoffmann switch (cookie->type) { 658474114b7SGerd Hoffmann #ifdef HAVE_SPICE_GL 659474114b7SGerd Hoffmann case QXL_COOKIE_TYPE_GL_DRAW_DONE: 660474114b7SGerd Hoffmann { 661474114b7SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); 662474114b7SGerd Hoffmann qemu_bh_schedule(ssd->gl_unblock_bh); 663474114b7SGerd Hoffmann break; 664474114b7SGerd Hoffmann } 66539414ef4SGerd Hoffmann case QXL_COOKIE_TYPE_IO: 66639414ef4SGerd Hoffmann if (cookie->io == QXL_IO_MONITORS_CONFIG_ASYNC) { 66739414ef4SGerd Hoffmann g_free(cookie->u.data); 66839414ef4SGerd Hoffmann } 66939414ef4SGerd Hoffmann break; 670474114b7SGerd Hoffmann #endif 671474114b7SGerd Hoffmann default: 67221a50d0bSGerd Hoffmann /* should never be called, used in qxl native mode only */ 67321a50d0bSGerd Hoffmann fprintf(stderr, "%s: abort()\n", __func__); 67421a50d0bSGerd Hoffmann abort(); 67521a50d0bSGerd Hoffmann } 676474114b7SGerd Hoffmann g_free(cookie); 677474114b7SGerd Hoffmann } 67821a50d0bSGerd Hoffmann 67921a50d0bSGerd Hoffmann static void interface_set_client_capabilities(QXLInstance *sin, 68021a50d0bSGerd Hoffmann uint8_t client_present, 68121a50d0bSGerd Hoffmann uint8_t caps[58]) 68221a50d0bSGerd Hoffmann { 68321a50d0bSGerd Hoffmann dprint(3, "%s:\n", __func__); 68421a50d0bSGerd Hoffmann } 68521a50d0bSGerd Hoffmann 68621a50d0bSGerd Hoffmann static int interface_client_monitors_config(QXLInstance *sin, 6879b74d0d5SGerd Hoffmann VDAgentMonitorsConfig *mc) 68821a50d0bSGerd Hoffmann { 6899b74d0d5SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); 6909b74d0d5SGerd Hoffmann QemuUIInfo info; 691c61d8126SMarc-André Lureau int head; 6925a9259a0SGerd Hoffmann 6935a9259a0SGerd Hoffmann if (!dpy_ui_info_supported(ssd->dcl.con)) { 6945a9259a0SGerd Hoffmann return 0; /* == not supported by guest */ 6955a9259a0SGerd Hoffmann } 6969b74d0d5SGerd Hoffmann 697dc491cfcSGerd Hoffmann if (!mc) { 698dc491cfcSGerd Hoffmann return 1; 699dc491cfcSGerd Hoffmann } 700dc491cfcSGerd Hoffmann 7019b74d0d5SGerd Hoffmann memset(&info, 0, sizeof(info)); 702c61d8126SMarc-André Lureau 703c61d8126SMarc-André Lureau head = qemu_console_get_head(ssd->dcl.con); 704c61d8126SMarc-André Lureau if (mc->num_of_monitors > head) { 705c61d8126SMarc-André Lureau info.width = mc->monitors[head].width; 706c61d8126SMarc-André Lureau info.height = mc->monitors[head].height; 7079b74d0d5SGerd Hoffmann } 7085a9259a0SGerd Hoffmann dpy_set_ui_info(ssd->dcl.con, &info); 7095a9259a0SGerd Hoffmann dprint(1, "%s/%d: size %dx%d\n", __func__, ssd->qxl.id, 7105a9259a0SGerd Hoffmann info.width, info.height); 7119b74d0d5SGerd Hoffmann return 1; 7129b74d0d5SGerd Hoffmann } 71321a50d0bSGerd Hoffmann 714a3e22260SGerd Hoffmann static const QXLInterface dpy_interface = { 715a3e22260SGerd Hoffmann .base.type = SPICE_INTERFACE_QXL, 716a3e22260SGerd Hoffmann .base.description = "qemu simple display", 717a3e22260SGerd Hoffmann .base.major_version = SPICE_INTERFACE_QXL_MAJOR, 718a3e22260SGerd Hoffmann .base.minor_version = SPICE_INTERFACE_QXL_MINOR, 719a3e22260SGerd Hoffmann 720a3e22260SGerd Hoffmann .attache_worker = interface_attach_worker, 721a3e22260SGerd Hoffmann .set_compression_level = interface_set_compression_level, 722015e02f8SJohn Snow #if SPICE_NEEDS_SET_MM_TIME 723a3e22260SGerd Hoffmann .set_mm_time = interface_set_mm_time, 724015e02f8SJohn Snow #endif 725a3e22260SGerd Hoffmann .get_init_info = interface_get_init_info, 726a3e22260SGerd Hoffmann 727a3e22260SGerd Hoffmann /* the callbacks below are called from spice server thread context */ 728a3e22260SGerd Hoffmann .get_command = interface_get_command, 729a3e22260SGerd Hoffmann .req_cmd_notification = interface_req_cmd_notification, 730a3e22260SGerd Hoffmann .release_resource = interface_release_resource, 731a3e22260SGerd Hoffmann .get_cursor_command = interface_get_cursor_command, 732a3e22260SGerd Hoffmann .req_cursor_notification = interface_req_cursor_notification, 733a3e22260SGerd Hoffmann .notify_update = interface_notify_update, 734a3e22260SGerd Hoffmann .flush_resources = interface_flush_resources, 73521a50d0bSGerd Hoffmann .async_complete = interface_async_complete, 73621a50d0bSGerd Hoffmann .update_area_complete = interface_update_area_complete, 73721a50d0bSGerd Hoffmann .set_client_capabilities = interface_set_client_capabilities, 73821a50d0bSGerd Hoffmann .client_monitors_config = interface_client_monitors_config, 739a3e22260SGerd Hoffmann }; 740a3e22260SGerd Hoffmann 7417c20b4a3SGerd Hoffmann static void display_update(DisplayChangeListener *dcl, 7427c20b4a3SGerd Hoffmann int x, int y, int w, int h) 743a3e22260SGerd Hoffmann { 7449c80a315SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 7459c80a315SGerd Hoffmann qemu_spice_display_update(ssd, x, y, w, h); 746a3e22260SGerd Hoffmann } 747a3e22260SGerd Hoffmann 748c12aeb86SGerd Hoffmann static void display_switch(DisplayChangeListener *dcl, 7499425c004SChih-Min Chao DisplaySurface *surface) 750a3e22260SGerd Hoffmann { 7519c80a315SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 752c12aeb86SGerd Hoffmann qemu_spice_display_switch(ssd, surface); 753a3e22260SGerd Hoffmann } 754a3e22260SGerd Hoffmann 755bc2ed970SGerd Hoffmann static void display_refresh(DisplayChangeListener *dcl) 756a3e22260SGerd Hoffmann { 7579c80a315SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 7589c80a315SGerd Hoffmann qemu_spice_display_refresh(ssd); 759a3e22260SGerd Hoffmann } 760a3e22260SGerd Hoffmann 7615643fc01SGerd Hoffmann static void display_mouse_set(DisplayChangeListener *dcl, 7625643fc01SGerd Hoffmann int x, int y, int on) 7635643fc01SGerd Hoffmann { 7645643fc01SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 7655643fc01SGerd Hoffmann 7665643fc01SGerd Hoffmann qemu_mutex_lock(&ssd->lock); 7675643fc01SGerd Hoffmann ssd->ptr_x = x; 768d0df04a1SMarc-André Lureau ssd->ptr_y = y; 7695643fc01SGerd Hoffmann g_free(ssd->ptr_move); 770700cd855SMarc-André Lureau ssd->ptr_move = qemu_spice_create_cursor_update(ssd, NULL, on); 7715643fc01SGerd Hoffmann qemu_mutex_unlock(&ssd->lock); 77251e0b654SMarc-André Lureau qemu_spice_wakeup(ssd); 7735643fc01SGerd Hoffmann } 7745643fc01SGerd Hoffmann 7755643fc01SGerd Hoffmann static void display_mouse_define(DisplayChangeListener *dcl, 7765643fc01SGerd Hoffmann QEMUCursor *c) 7775643fc01SGerd Hoffmann { 7785643fc01SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 7795643fc01SGerd Hoffmann 7805643fc01SGerd Hoffmann qemu_mutex_lock(&ssd->lock); 78158c7b618SMarc-André Lureau cursor_get(c); 78258c7b618SMarc-André Lureau cursor_put(ssd->cursor); 78358c7b618SMarc-André Lureau ssd->cursor = c; 784dc8dceeeSMarc-André Lureau ssd->hot_x = c->hot_x; 785dc8dceeeSMarc-André Lureau ssd->hot_y = c->hot_y; 7865643fc01SGerd Hoffmann g_free(ssd->ptr_move); 7875643fc01SGerd Hoffmann ssd->ptr_move = NULL; 7885643fc01SGerd Hoffmann g_free(ssd->ptr_define); 789700cd855SMarc-André Lureau ssd->ptr_define = qemu_spice_create_cursor_update(ssd, c, 0); 7905643fc01SGerd Hoffmann qemu_mutex_unlock(&ssd->lock); 79151e0b654SMarc-André Lureau qemu_spice_wakeup(ssd); 7925643fc01SGerd Hoffmann } 7935643fc01SGerd Hoffmann 7947c20b4a3SGerd Hoffmann static const DisplayChangeListenerOps display_listener_ops = { 7957c20b4a3SGerd Hoffmann .dpy_name = "spice", 796a93a4a22SGerd Hoffmann .dpy_gfx_update = display_update, 797c12aeb86SGerd Hoffmann .dpy_gfx_switch = display_switch, 7980002a518SGerd Hoffmann .dpy_gfx_check_format = qemu_pixman_check_format, 799a3e22260SGerd Hoffmann .dpy_refresh = display_refresh, 8005643fc01SGerd Hoffmann .dpy_mouse_set = display_mouse_set, 8015643fc01SGerd Hoffmann .dpy_cursor_define = display_mouse_define, 802a3e22260SGerd Hoffmann }; 803a3e22260SGerd Hoffmann 804474114b7SGerd Hoffmann #ifdef HAVE_SPICE_GL 805474114b7SGerd Hoffmann 80639414ef4SGerd Hoffmann static void qemu_spice_gl_monitor_config(SimpleSpiceDisplay *ssd, 80739414ef4SGerd Hoffmann int x, int y, int w, int h) 80839414ef4SGerd Hoffmann { 80939414ef4SGerd Hoffmann QXLMonitorsConfig *config; 81039414ef4SGerd Hoffmann QXLCookie *cookie; 81139414ef4SGerd Hoffmann 81239414ef4SGerd Hoffmann config = g_malloc0(sizeof(QXLMonitorsConfig) + sizeof(QXLHead)); 81339414ef4SGerd Hoffmann config->count = 1; 81439414ef4SGerd Hoffmann config->max_allowed = 1; 81539414ef4SGerd Hoffmann config->heads[0].x = x; 81639414ef4SGerd Hoffmann config->heads[0].y = y; 81739414ef4SGerd Hoffmann config->heads[0].width = w; 81839414ef4SGerd Hoffmann config->heads[0].height = h; 81939414ef4SGerd Hoffmann cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, 82039414ef4SGerd Hoffmann QXL_IO_MONITORS_CONFIG_ASYNC); 82139414ef4SGerd Hoffmann cookie->u.data = config; 82239414ef4SGerd Hoffmann 82339414ef4SGerd Hoffmann spice_qxl_monitors_config_async(&ssd->qxl, 82439414ef4SGerd Hoffmann (uintptr_t)config, 82539414ef4SGerd Hoffmann MEMSLOT_GROUP_HOST, 82639414ef4SGerd Hoffmann (uintptr_t)cookie); 82739414ef4SGerd Hoffmann } 82839414ef4SGerd Hoffmann 829474114b7SGerd Hoffmann static void qemu_spice_gl_block(SimpleSpiceDisplay *ssd, bool block) 830474114b7SGerd Hoffmann { 8318e388e90SGerd Hoffmann uint64_t timeout; 8328e388e90SGerd Hoffmann 8338e388e90SGerd Hoffmann if (block) { 8348e388e90SGerd Hoffmann timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); 8358e388e90SGerd Hoffmann timeout += 1000; /* one sec */ 8368e388e90SGerd Hoffmann timer_mod(ssd->gl_unblock_timer, timeout); 8378e388e90SGerd Hoffmann } else { 8388e388e90SGerd Hoffmann timer_del(ssd->gl_unblock_timer); 8398e388e90SGerd Hoffmann } 840474114b7SGerd Hoffmann graphic_hw_gl_block(ssd->dcl.con, block); 841474114b7SGerd Hoffmann } 842474114b7SGerd Hoffmann 843474114b7SGerd Hoffmann static void qemu_spice_gl_unblock_bh(void *opaque) 844474114b7SGerd Hoffmann { 845474114b7SGerd Hoffmann SimpleSpiceDisplay *ssd = opaque; 846474114b7SGerd Hoffmann 847474114b7SGerd Hoffmann qemu_spice_gl_block(ssd, false); 848474114b7SGerd Hoffmann } 849474114b7SGerd Hoffmann 8508e388e90SGerd Hoffmann static void qemu_spice_gl_block_timer(void *opaque) 8518e388e90SGerd Hoffmann { 8522ab4b135SAlistair Francis warn_report("spice: no gl-draw-done within one second"); 8538e388e90SGerd Hoffmann } 8548e388e90SGerd Hoffmann 85544231843SGerd Hoffmann static void spice_gl_refresh(DisplayChangeListener *dcl) 85644231843SGerd Hoffmann { 85744231843SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 85844231843SGerd Hoffmann uint64_t cookie; 85944231843SGerd Hoffmann 86044231843SGerd Hoffmann if (!ssd->ds || qemu_console_is_gl_blocked(ssd->dcl.con)) { 86144231843SGerd Hoffmann return; 86244231843SGerd Hoffmann } 86344231843SGerd Hoffmann 86444231843SGerd Hoffmann graphic_hw_update(dcl->con); 86544231843SGerd Hoffmann if (ssd->gl_updates && ssd->have_surface) { 86644231843SGerd Hoffmann qemu_spice_gl_block(ssd, true); 86744231843SGerd Hoffmann cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0); 86844231843SGerd Hoffmann spice_qxl_gl_draw_async(&ssd->qxl, 0, 0, 86944231843SGerd Hoffmann surface_width(ssd->ds), 87044231843SGerd Hoffmann surface_height(ssd->ds), 87144231843SGerd Hoffmann cookie); 87244231843SGerd Hoffmann ssd->gl_updates = 0; 87344231843SGerd Hoffmann } 87444231843SGerd Hoffmann } 87544231843SGerd Hoffmann 87644231843SGerd Hoffmann static void spice_gl_update(DisplayChangeListener *dcl, 87744231843SGerd Hoffmann int x, int y, int w, int h) 87844231843SGerd Hoffmann { 87944231843SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 88044231843SGerd Hoffmann 88144231843SGerd Hoffmann surface_gl_update_texture(ssd->gls, ssd->ds, x, y, w, h); 88244231843SGerd Hoffmann ssd->gl_updates++; 88344231843SGerd Hoffmann } 88444231843SGerd Hoffmann 88544231843SGerd Hoffmann static void spice_gl_switch(DisplayChangeListener *dcl, 88644231843SGerd Hoffmann struct DisplaySurface *new_surface) 88744231843SGerd Hoffmann { 88844231843SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 88944231843SGerd Hoffmann EGLint stride, fourcc; 89044231843SGerd Hoffmann int fd; 89144231843SGerd Hoffmann 89244231843SGerd Hoffmann if (ssd->ds) { 89344231843SGerd Hoffmann surface_gl_destroy_texture(ssd->gls, ssd->ds); 89444231843SGerd Hoffmann } 89544231843SGerd Hoffmann ssd->ds = new_surface; 89644231843SGerd Hoffmann if (ssd->ds) { 89744231843SGerd Hoffmann surface_gl_create_texture(ssd->gls, ssd->ds); 89844231843SGerd Hoffmann fd = egl_get_fd_for_texture(ssd->ds->texture, 89944231843SGerd Hoffmann &stride, &fourcc); 90044231843SGerd Hoffmann if (fd < 0) { 90144231843SGerd Hoffmann surface_gl_destroy_texture(ssd->gls, ssd->ds); 90244231843SGerd Hoffmann return; 90344231843SGerd Hoffmann } 90444231843SGerd Hoffmann 90544231843SGerd Hoffmann dprint(1, "%s: %dx%d (stride %d/%d, fourcc 0x%x)\n", __func__, 90644231843SGerd Hoffmann surface_width(ssd->ds), surface_height(ssd->ds), 90744231843SGerd Hoffmann surface_stride(ssd->ds), stride, fourcc); 90844231843SGerd Hoffmann 90944231843SGerd Hoffmann /* note: spice server will close the fd */ 91044231843SGerd Hoffmann spice_qxl_gl_scanout(&ssd->qxl, fd, 91144231843SGerd Hoffmann surface_width(ssd->ds), 91244231843SGerd Hoffmann surface_height(ssd->ds), 91344231843SGerd Hoffmann stride, fourcc, false); 91444231843SGerd Hoffmann ssd->have_surface = true; 91544231843SGerd Hoffmann ssd->have_scanout = false; 91644231843SGerd Hoffmann 91744231843SGerd Hoffmann qemu_spice_gl_monitor_config(ssd, 0, 0, 91844231843SGerd Hoffmann surface_width(ssd->ds), 91944231843SGerd Hoffmann surface_height(ssd->ds)); 92044231843SGerd Hoffmann } 92144231843SGerd Hoffmann } 92244231843SGerd Hoffmann 923474114b7SGerd Hoffmann static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl, 924474114b7SGerd Hoffmann QEMUGLParams *params) 925474114b7SGerd Hoffmann { 926474114b7SGerd Hoffmann eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, 927474114b7SGerd Hoffmann qemu_egl_rn_ctx); 928474114b7SGerd Hoffmann return qemu_egl_create_context(dcl, params); 929474114b7SGerd Hoffmann } 930474114b7SGerd Hoffmann 93146ffd0c0SGerd Hoffmann static void qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl) 93246ffd0c0SGerd Hoffmann { 93346ffd0c0SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 93446ffd0c0SGerd Hoffmann 93546ffd0c0SGerd Hoffmann dprint(1, "%s: no framebuffer\n", __func__); 93646ffd0c0SGerd Hoffmann spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false); 93746ffd0c0SGerd Hoffmann qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0); 93846ffd0c0SGerd Hoffmann ssd->have_surface = false; 93946ffd0c0SGerd Hoffmann ssd->have_scanout = false; 94046ffd0c0SGerd Hoffmann } 94146ffd0c0SGerd Hoffmann 942f4c36bdaSGerd Hoffmann static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl, 943474114b7SGerd Hoffmann uint32_t tex_id, 944474114b7SGerd Hoffmann bool y_0_top, 9459d8256ebSMarc-André Lureau uint32_t backing_width, 9469d8256ebSMarc-André Lureau uint32_t backing_height, 947474114b7SGerd Hoffmann uint32_t x, uint32_t y, 948474114b7SGerd Hoffmann uint32_t w, uint32_t h) 949474114b7SGerd Hoffmann { 950474114b7SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 951474114b7SGerd Hoffmann EGLint stride = 0, fourcc = 0; 952474114b7SGerd Hoffmann int fd = -1; 953474114b7SGerd Hoffmann 95446ffd0c0SGerd Hoffmann assert(tex_id); 955474114b7SGerd Hoffmann fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc); 956474114b7SGerd Hoffmann if (fd < 0) { 957474114b7SGerd Hoffmann fprintf(stderr, "%s: failed to get fd for texture\n", __func__); 958474114b7SGerd Hoffmann return; 959474114b7SGerd Hoffmann } 96022672a37SGerd Hoffmann dprint(1, "%s: %dx%d (stride %d, fourcc 0x%x)\n", __func__, 961474114b7SGerd Hoffmann w, h, stride, fourcc); 962474114b7SGerd Hoffmann 963474114b7SGerd Hoffmann /* note: spice server will close the fd */ 9649d8256ebSMarc-André Lureau spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height, 965474114b7SGerd Hoffmann stride, fourcc, y_0_top); 96639414ef4SGerd Hoffmann qemu_spice_gl_monitor_config(ssd, x, y, w, h); 96746ffd0c0SGerd Hoffmann ssd->have_surface = false; 96846ffd0c0SGerd Hoffmann ssd->have_scanout = true; 969474114b7SGerd Hoffmann } 970474114b7SGerd Hoffmann 971474114b7SGerd Hoffmann static void qemu_spice_gl_update(DisplayChangeListener *dcl, 972474114b7SGerd Hoffmann uint32_t x, uint32_t y, uint32_t w, uint32_t h) 973474114b7SGerd Hoffmann { 974474114b7SGerd Hoffmann SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 975474114b7SGerd Hoffmann uint64_t cookie; 976474114b7SGerd Hoffmann 97744231843SGerd Hoffmann if (!ssd->have_scanout) { 97844231843SGerd Hoffmann return; 97944231843SGerd Hoffmann } 98044231843SGerd Hoffmann 98122672a37SGerd Hoffmann dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y); 982474114b7SGerd Hoffmann qemu_spice_gl_block(ssd, true); 983474114b7SGerd Hoffmann cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0); 984474114b7SGerd Hoffmann spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie); 985474114b7SGerd Hoffmann } 986474114b7SGerd Hoffmann 987474114b7SGerd Hoffmann static const DisplayChangeListenerOps display_listener_gl_ops = { 988474114b7SGerd Hoffmann .dpy_name = "spice-egl", 98944231843SGerd Hoffmann .dpy_gfx_update = spice_gl_update, 99044231843SGerd Hoffmann .dpy_gfx_switch = spice_gl_switch, 99144231843SGerd Hoffmann .dpy_gfx_check_format = console_gl_check_format, 99244231843SGerd Hoffmann .dpy_refresh = spice_gl_refresh, 993474114b7SGerd Hoffmann .dpy_mouse_set = display_mouse_set, 994474114b7SGerd Hoffmann .dpy_cursor_define = display_mouse_define, 995474114b7SGerd Hoffmann 996474114b7SGerd Hoffmann .dpy_gl_ctx_create = qemu_spice_gl_create_context, 997474114b7SGerd Hoffmann .dpy_gl_ctx_destroy = qemu_egl_destroy_context, 998474114b7SGerd Hoffmann .dpy_gl_ctx_make_current = qemu_egl_make_context_current, 999474114b7SGerd Hoffmann .dpy_gl_ctx_get_current = qemu_egl_get_current_context, 1000474114b7SGerd Hoffmann 100146ffd0c0SGerd Hoffmann .dpy_gl_scanout_disable = qemu_spice_gl_scanout_disable, 1002f4c36bdaSGerd Hoffmann .dpy_gl_scanout_texture = qemu_spice_gl_scanout_texture, 1003474114b7SGerd Hoffmann .dpy_gl_update = qemu_spice_gl_update, 1004474114b7SGerd Hoffmann }; 1005474114b7SGerd Hoffmann 1006474114b7SGerd Hoffmann #endif /* HAVE_SPICE_GL */ 1007474114b7SGerd Hoffmann 10089fa03286SGerd Hoffmann static void qemu_spice_display_init_one(QemuConsole *con) 1009a3e22260SGerd Hoffmann { 10109c80a315SGerd Hoffmann SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1); 1011a3e22260SGerd Hoffmann 1012c78f7137SGerd Hoffmann qemu_spice_display_init_common(ssd); 1013a3e22260SGerd Hoffmann 1014b5e751b5SGerd Hoffmann ssd->dcl.ops = &display_listener_ops; 1015474114b7SGerd Hoffmann #ifdef HAVE_SPICE_GL 1016fe5c44f9SGerd Hoffmann if (spice_opengl) { 1017474114b7SGerd Hoffmann ssd->dcl.ops = &display_listener_gl_ops; 1018474114b7SGerd Hoffmann ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd); 10198e388e90SGerd Hoffmann ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME, 10208e388e90SGerd Hoffmann qemu_spice_gl_block_timer, ssd); 102146e19e14SGerd Hoffmann ssd->gls = qemu_gl_init_shader(); 102244231843SGerd Hoffmann ssd->have_surface = false; 102344231843SGerd Hoffmann ssd->have_scanout = false; 1024474114b7SGerd Hoffmann } 1025474114b7SGerd Hoffmann #endif 1026b5e751b5SGerd Hoffmann ssd->dcl.con = con; 1027b5e751b5SGerd Hoffmann 10289c80a315SGerd Hoffmann ssd->qxl.base.sif = &dpy_interface.base; 10299fa03286SGerd Hoffmann qemu_spice_add_display_interface(&ssd->qxl, con); 10309c80a315SGerd Hoffmann qemu_spice_create_host_memslot(ssd); 10319c80a315SGerd Hoffmann 10325209089fSGerd Hoffmann register_displaychangelistener(&ssd->dcl); 1033a3e22260SGerd Hoffmann } 10349fa03286SGerd Hoffmann 10359fa03286SGerd Hoffmann void qemu_spice_display_init(void) 10369fa03286SGerd Hoffmann { 10378bf69b49SGerd Hoffmann QemuOptsList *olist = qemu_find_opts("spice"); 10388bf69b49SGerd Hoffmann QemuOpts *opts = QTAILQ_FIRST(&olist->head); 10398bf69b49SGerd Hoffmann QemuConsole *spice_con, *con; 10408bf69b49SGerd Hoffmann const char *str; 10419fa03286SGerd Hoffmann int i; 10429fa03286SGerd Hoffmann 10438bf69b49SGerd Hoffmann str = qemu_opt_get(opts, "display"); 10448bf69b49SGerd Hoffmann if (str) { 10458bf69b49SGerd Hoffmann int head = qemu_opt_get_number(opts, "head", 0); 10468bf69b49SGerd Hoffmann Error *err = NULL; 10478bf69b49SGerd Hoffmann 10488bf69b49SGerd Hoffmann spice_con = qemu_console_lookup_by_device_name(str, head, &err); 10498bf69b49SGerd Hoffmann if (err) { 10508bf69b49SGerd Hoffmann error_report("Failed to lookup display/head"); 10518bf69b49SGerd Hoffmann exit(1); 10528bf69b49SGerd Hoffmann } 10538bf69b49SGerd Hoffmann } else { 10548bf69b49SGerd Hoffmann spice_con = NULL; 10558bf69b49SGerd Hoffmann } 10568bf69b49SGerd Hoffmann 10579fa03286SGerd Hoffmann for (i = 0;; i++) { 10589fa03286SGerd Hoffmann con = qemu_console_lookup_by_index(i); 10599fa03286SGerd Hoffmann if (!con || !qemu_console_is_graphic(con)) { 10609fa03286SGerd Hoffmann break; 10619fa03286SGerd Hoffmann } 10629fa03286SGerd Hoffmann if (qemu_spice_have_display_interface(con)) { 10639fa03286SGerd Hoffmann continue; 10649fa03286SGerd Hoffmann } 10658bf69b49SGerd Hoffmann if (spice_con != NULL && spice_con != con) { 10668bf69b49SGerd Hoffmann continue; 10678bf69b49SGerd Hoffmann } 10689fa03286SGerd Hoffmann qemu_spice_display_init_one(con); 10699fa03286SGerd Hoffmann } 10709fa03286SGerd Hoffmann } 1071