spice-display.c 19.3 KB
Newer Older
G
Gerd Hoffmann 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright (C) 2010 Red Hat, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 or
 * (at your option) version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include "qemu-common.h"
19
#include "ui/qemu-spice.h"
20 21
#include "qemu/timer.h"
#include "qemu/queue.h"
22
#include "monitor/monitor.h"
23
#include "ui/console.h"
24
#include "sysemu/sysemu.h"
A
Alon Levy 已提交
25
#include "trace.h"
G
Gerd Hoffmann 已提交
26

27
#include "ui/spice-display.h"
G
Gerd Hoffmann 已提交
28 29 30

static int debug = 0;

31
static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...)
G
Gerd Hoffmann 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
{
    va_list args;

    if (level <= debug) {
        va_start(args, fmt);
        vfprintf(stderr, fmt, args);
        va_end(args);
    }
}

int qemu_spice_rect_is_empty(const QXLRect* r)
{
    return r->top == r->bottom || r->left == r->right;
}

void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
{
    if (qemu_spice_rect_is_empty(r)) {
        return;
    }

    if (qemu_spice_rect_is_empty(dest)) {
        *dest = *r;
        return;
    }

    dest->top = MIN(dest->top, r->top);
    dest->left = MIN(dest->left, r->left);
    dest->bottom = MAX(dest->bottom, r->bottom);
    dest->right = MAX(dest->right, r->right);
}

A
Alon Levy 已提交
64 65 66 67 68 69 70 71 72 73
QXLCookie *qxl_cookie_new(int type, uint64_t io)
{
    QXLCookie *cookie;

    cookie = g_malloc0(sizeof(*cookie));
    cookie->type = type;
    cookie->io = io;
    return cookie;
}

74 75
void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
                            qxl_async_io async)
76
{
A
Alon Levy 已提交
77 78 79 80
    trace_qemu_spice_add_memslot(ssd->qxl.id, memslot->slot_id,
                                memslot->virt_start, memslot->virt_end,
                                async);

81
    if (async != QXL_SYNC) {
A
Alon Levy 已提交
82
        spice_qxl_add_memslot_async(&ssd->qxl, memslot,
83 84
                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
                                          QXL_IO_MEMSLOT_ADD_ASYNC));
85
    } else {
86
        spice_qxl_add_memslot(&ssd->qxl, memslot);
87
    }
88 89 90 91
}

void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
{
A
Alon Levy 已提交
92
    trace_qemu_spice_del_memslot(ssd->qxl.id, gid, sid);
93
    spice_qxl_del_memslot(&ssd->qxl, gid, sid);
94 95 96
}

void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
97 98
                                       QXLDevSurfaceCreate *surface,
                                       qxl_async_io async)
99
{
A
Alon Levy 已提交
100
    trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async);
101
    if (async != QXL_SYNC) {
A
Alon Levy 已提交
102
        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface,
103 104
                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
                                          QXL_IO_CREATE_PRIMARY_ASYNC));
105
    } else {
106
        spice_qxl_create_primary_surface(&ssd->qxl, id, surface);
107
    }
108 109
}

110 111
void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
                                        uint32_t id, qxl_async_io async)
112
{
A
Alon Levy 已提交
113
    trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async);
114
    if (async != QXL_SYNC) {
A
Alon Levy 已提交
115
        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id,
116 117
                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
                                          QXL_IO_DESTROY_PRIMARY_ASYNC));
118
    } else {
119
        spice_qxl_destroy_primary_surface(&ssd->qxl, id);
120
    }
121 122 123 124
}

void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
{
A
Alon Levy 已提交
125
    trace_qemu_spice_wakeup(ssd->qxl.id);
126
    spice_qxl_wakeup(&ssd->qxl);
127 128
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
static int spice_display_is_running;

void qemu_spice_display_start(void)
{
    spice_display_is_running = true;
}

void qemu_spice_display_stop(void)
{
    spice_display_is_running = false;
}

int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd)
{
    return spice_display_is_running;
}

146 147
static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd,
                                         QXLRect *rect)
G
Gerd Hoffmann 已提交
148 149 150 151 152
{
    SimpleSpiceUpdate *update;
    QXLDrawable *drawable;
    QXLImage *image;
    QXLCommand *cmd;
G
Gerd Hoffmann 已提交
153
    int bw, bh;
A
Alon Levy 已提交
154
    struct timespec time_space;
G
Gerd Hoffmann 已提交
155
    pixman_image_t *dest;
G
Gerd Hoffmann 已提交
156

A
Alon Levy 已提交
157
    trace_qemu_spice_create_update(
158 159
           rect->left, rect->right,
           rect->top, rect->bottom);
G
Gerd Hoffmann 已提交
160

161
    update   = g_malloc0(sizeof(*update));
G
Gerd Hoffmann 已提交
162 163 164 165
    drawable = &update->drawable;
    image    = &update->image;
    cmd      = &update->ext.cmd;

166 167
    bw       = rect->right - rect->left;
    bh       = rect->bottom - rect->top;
168
    update->bitmap = g_malloc(bw * bh * 4);
G
Gerd Hoffmann 已提交
169

170
    drawable->bbox            = *rect;
G
Gerd Hoffmann 已提交
171 172
    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
    drawable->effect          = QXL_EFFECT_OPAQUE;
173
    drawable->release_info.id = (uintptr_t)update;
G
Gerd Hoffmann 已提交
174 175 176 177
    drawable->type            = QXL_DRAW_COPY;
    drawable->surfaces_dest[0] = -1;
    drawable->surfaces_dest[1] = -1;
    drawable->surfaces_dest[2] = -1;
A
Alon Levy 已提交
178 179 180 181
    clock_gettime(CLOCK_MONOTONIC, &time_space);
    /* time in milliseconds from epoch. */
    drawable->mm_time = time_space.tv_sec * 1000
                      + time_space.tv_nsec / 1000 / 1000;
G
Gerd Hoffmann 已提交
182 183

    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
184
    drawable->u.copy.src_bitmap      = (uintptr_t)image;
G
Gerd Hoffmann 已提交
185 186 187 188 189 190 191 192 193
    drawable->u.copy.src_area.right  = bw;
    drawable->u.copy.src_area.bottom = bh;

    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++);
    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
    image->bitmap.stride     = bw * 4;
    image->descriptor.width  = image->bitmap.x = bw;
    image->descriptor.height = image->bitmap.y = bh;
194
    image->bitmap.data = (uintptr_t)(update->bitmap);
G
Gerd Hoffmann 已提交
195 196 197
    image->bitmap.palette = 0;
    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;

G
Gerd Hoffmann 已提交
198 199 200 201 202 203 204 205 206
    dest = pixman_image_create_bits(PIXMAN_x8r8g8b8, bw, bh,
                                    (void *)update->bitmap, bw * 4);
    pixman_image_composite(PIXMAN_OP_SRC, ssd->surface, NULL, ssd->mirror,
                           rect->left, rect->top, 0, 0,
                           rect->left, rect->top, bw, bh);
    pixman_image_composite(PIXMAN_OP_SRC, ssd->mirror, NULL, dest,
                           rect->left, rect->top, 0, 0,
                           0, 0, bw, bh);
    pixman_image_unref(dest);
G
Gerd Hoffmann 已提交
207 208

    cmd->type = QXL_CMD_DRAW;
209
    cmd->data = (uintptr_t)drawable;
G
Gerd Hoffmann 已提交
210

211
    QTAILQ_INSERT_TAIL(&ssd->updates, update, next);
G
Gerd Hoffmann 已提交
212 213
}

214 215
static void qemu_spice_create_update(SimpleSpiceDisplay *ssd)
{
216
    static const int blksize = 32;
G
Gerd Hoffmann 已提交
217
    int blocks = (surface_width(ssd->ds) + blksize - 1) / blksize;
218 219
    int dirty_top[blocks];
    int y, yoff, x, xoff, blk, bw;
G
Gerd Hoffmann 已提交
220
    int bpp = surface_bytes_per_pixel(ssd->ds);
221 222
    uint8_t *guest, *mirror;

223 224 225
    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
        return;
    };
G
Gerd Hoffmann 已提交
226

G
Gerd Hoffmann 已提交
227
    if (ssd->surface == NULL) {
G
Gerd Hoffmann 已提交
228 229 230
        ssd->surface = pixman_image_ref(ssd->ds->image);
        ssd->mirror  = qemu_pixman_mirror_create(ssd->ds->format,
                                                 ssd->ds->image);
G
Gerd Hoffmann 已提交
231 232
    }

233 234 235 236
    for (blk = 0; blk < blocks; blk++) {
        dirty_top[blk] = -1;
    }

G
Gerd Hoffmann 已提交
237
    guest = surface_data(ssd->ds);
G
Gerd Hoffmann 已提交
238
    mirror = (void *)pixman_image_get_data(ssd->mirror);
239
    for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) {
G
Gerd Hoffmann 已提交
240
        yoff = y * surface_stride(ssd->ds);
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
        for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) {
            xoff = x * bpp;
            blk = x / blksize;
            bw = MIN(blksize, ssd->dirty.right - x);
            if (memcmp(guest + yoff + xoff,
                       mirror + yoff + xoff,
                       bw * bpp) == 0) {
                if (dirty_top[blk] != -1) {
                    QXLRect update = {
                        .top    = dirty_top[blk],
                        .bottom = y,
                        .left   = x,
                        .right  = x + bw,
                    };
                    qemu_spice_create_one_update(ssd, &update);
                    dirty_top[blk] = -1;
                }
            } else {
                if (dirty_top[blk] == -1) {
                    dirty_top[blk] = y;
                }
            }
        }
    }

    for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) {
        blk = x / blksize;
        bw = MIN(blksize, ssd->dirty.right - x);
        if (dirty_top[blk] != -1) {
            QXLRect update = {
                .top    = dirty_top[blk],
                .bottom = ssd->dirty.bottom,
                .left   = x,
                .right  = x + bw,
            };
            qemu_spice_create_one_update(ssd, &update);
            dirty_top[blk] = -1;
        }
    }

281 282 283
    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
}

G
Gerd Hoffmann 已提交
284
/*
285
 * Called from spice server thread context (via interface_release_resource)
G
Gerd Hoffmann 已提交
286
 * We do *not* hold the global qemu mutex here, so extra care is needed
S
Stefan Weil 已提交
287
 * when calling qemu functions.  QEMU interfaces used:
288
 *    - g_free (underlying glibc free is re-entrant).
G
Gerd Hoffmann 已提交
289 290 291
 */
void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
{
292 293
    g_free(update->bitmap);
    g_free(update);
G
Gerd Hoffmann 已提交
294 295 296 297 298 299
}

void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
{
    QXLDevMemSlot memslot;

300
    dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
G
Gerd Hoffmann 已提交
301 302 303 304

    memset(&memslot, 0, sizeof(memslot));
    memslot.slot_group_id = MEMSLOT_GROUP_HOST;
    memslot.virt_end = ~0;
305
    qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC);
G
Gerd Hoffmann 已提交
306 307 308 309 310 311
}

void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
{
    QXLDevSurfaceCreate surface;

312 313
    memset(&surface, 0, sizeof(surface));

314
    dprint(1, "%s/%d: %dx%d\n", __func__, ssd->qxl.id,
G
Gerd Hoffmann 已提交
315
           surface_width(ssd->ds), surface_height(ssd->ds));
G
Gerd Hoffmann 已提交
316 317

    surface.format     = SPICE_SURFACE_FMT_32_xRGB;
G
Gerd Hoffmann 已提交
318 319
    surface.width      = surface_width(ssd->ds);
    surface.height     = surface_height(ssd->ds);
G
Gerd Hoffmann 已提交
320
    surface.stride     = -surface.width * 4;
G
Gerd Hoffmann 已提交
321
    surface.mouse_mode = true;
G
Gerd Hoffmann 已提交
322 323
    surface.flags      = 0;
    surface.type       = 0;
324
    surface.mem        = (uintptr_t)ssd->buf;
G
Gerd Hoffmann 已提交
325
    surface.group_id   = MEMSLOT_GROUP_HOST;
326

327
    qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
G
Gerd Hoffmann 已提交
328 329 330 331
}

void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
{
332
    dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
G
Gerd Hoffmann 已提交
333

334
    qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
G
Gerd Hoffmann 已提交
335 336
}

337
void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd)
338 339
{
    qemu_mutex_init(&ssd->lock);
340
    QTAILQ_INIT(&ssd->updates);
341 342
    ssd->mouse_x = -1;
    ssd->mouse_y = -1;
343 344 345
    if (ssd->num_surfaces == 0) {
        ssd->num_surfaces = 1024;
    }
346
    ssd->bufsize = (16 * 1024 * 1024);
347
    ssd->buf = g_malloc(ssd->bufsize);
348 349
}

G
Gerd Hoffmann 已提交
350 351 352 353 354 355 356
/* display listener callbacks */

void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
                               int x, int y, int w, int h)
{
    QXLRect update_area;

357 358
    dprint(2, "%s/%d: x %d y %d w %d h %d\n", __func__,
           ssd->qxl.id, x, y, w, h);
G
Gerd Hoffmann 已提交
359 360 361 362 363 364 365 366 367 368 369
    update_area.left = x,
    update_area.right = x + w;
    update_area.top = y;
    update_area.bottom = y + h;

    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
        ssd->notify++;
    }
    qemu_spice_rect_union(&ssd->dirty, &update_area);
}

370 371
void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,
                               DisplaySurface *surface)
G
Gerd Hoffmann 已提交
372
{
373 374
    SimpleSpiceUpdate *update;

375
    dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
G
Gerd Hoffmann 已提交
376 377

    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
G
Gerd Hoffmann 已提交
378 379 380 381 382 383
    if (ssd->surface) {
        pixman_image_unref(ssd->surface);
        ssd->surface = NULL;
        pixman_image_unref(ssd->mirror);
        ssd->mirror = NULL;
    }
G
Gerd Hoffmann 已提交
384

385
    qemu_mutex_lock(&ssd->lock);
G
Gerd Hoffmann 已提交
386
    ssd->ds = surface;
387 388 389
    while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) {
        QTAILQ_REMOVE(&ssd->updates, update, next);
        qemu_spice_destroy_update(ssd, update);
390 391
    }
    qemu_mutex_unlock(&ssd->lock);
G
Gerd Hoffmann 已提交
392 393 394 395 396 397 398
    qemu_spice_destroy_host_primary(ssd);
    qemu_spice_create_host_primary(ssd);

    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
    ssd->notify++;
}

399
void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd)
G
Gerd Hoffmann 已提交
400
{
401
    if (ssd->cursor) {
402 403
        assert(ssd->dcl.con);
        dpy_cursor_define(ssd->dcl.con, ssd->cursor);
404 405 406 407
        cursor_put(ssd->cursor);
        ssd->cursor = NULL;
    }
    if (ssd->mouse_x != -1 && ssd->mouse_y != -1) {
408 409
        assert(ssd->dcl.con);
        dpy_mouse_set(ssd->dcl.con, ssd->mouse_x, ssd->mouse_y, 1);
410 411 412
        ssd->mouse_x = -1;
        ssd->mouse_y = -1;
    }
413 414 415 416
}

void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
{
417
    dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
418
    graphic_hw_update(ssd->dcl.con);
419 420

    qemu_mutex_lock(&ssd->lock);
G
Gerd Hoffmann 已提交
421
    if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) {
422
        qemu_spice_create_update(ssd);
423 424 425
        ssd->notify++;
    }
    qemu_spice_cursor_refresh_unlocked(ssd);
426 427
    qemu_mutex_unlock(&ssd->lock);

G
Gerd Hoffmann 已提交
428 429
    if (ssd->notify) {
        ssd->notify = 0;
430
        qemu_spice_wakeup(ssd);
431
        dprint(2, "%s/%d: notify\n", __func__, ssd->qxl.id);
G
Gerd Hoffmann 已提交
432 433 434 435 436 437 438 439 440
    }
}

/* spice display interface callbacks */

static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
{
    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);

441
    dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
G
Gerd Hoffmann 已提交
442 443 444 445 446
    ssd->worker = qxl_worker;
}

static void interface_set_compression_level(QXLInstance *sin, int level)
{
447
    dprint(1, "%s/%d:\n", __func__, sin->id);
G
Gerd Hoffmann 已提交
448 449 450 451 452
    /* nothing to do */
}

static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
{
453
    dprint(3, "%s/%d:\n", __func__, sin->id);
G
Gerd Hoffmann 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466
    /* nothing to do */
}

static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
{
    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);

    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
    info->memslot_id_bits  = MEMSLOT_SLOT_BITS;
    info->num_memslots = NUM_MEMSLOTS;
    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
    info->internal_groupslot_id = 0;
    info->qxl_ram_size = ssd->bufsize;
467
    info->n_surfaces = ssd->num_surfaces;
G
Gerd Hoffmann 已提交
468 469 470 471 472 473
}

static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
{
    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
    SimpleSpiceUpdate *update;
474
    int ret = false;
G
Gerd Hoffmann 已提交
475

476
    dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
477 478

    qemu_mutex_lock(&ssd->lock);
479 480 481
    update = QTAILQ_FIRST(&ssd->updates);
    if (update != NULL) {
        QTAILQ_REMOVE(&ssd->updates, update, next);
482 483
        *ext = update->ext;
        ret = true;
G
Gerd Hoffmann 已提交
484
    }
485 486 487
    qemu_mutex_unlock(&ssd->lock);

    return ret;
G
Gerd Hoffmann 已提交
488 489 490 491
}

static int interface_req_cmd_notification(QXLInstance *sin)
{
492
    dprint(1, "%s/%d:\n", __func__, sin->id);
G
Gerd Hoffmann 已提交
493 494 495 496 497 498 499 500 501
    return 1;
}

static void interface_release_resource(QXLInstance *sin,
                                       struct QXLReleaseInfoExt ext)
{
    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
    uintptr_t id;

502
    dprint(2, "%s/%d:\n", __func__, ssd->qxl.id);
G
Gerd Hoffmann 已提交
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
    id = ext.info->id;
    qemu_spice_destroy_update(ssd, (void*)id);
}

static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
{
    dprint(3, "%s:\n", __FUNCTION__);
    return false;
}

static int interface_req_cursor_notification(QXLInstance *sin)
{
    dprint(1, "%s:\n", __FUNCTION__);
    return 1;
}

static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
{
    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
    abort();
}

static int interface_flush_resources(QXLInstance *sin)
{
    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
    abort();
    return 0;
}

532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
static void interface_update_area_complete(QXLInstance *sin,
        uint32_t surface_id,
        QXLRect *dirty, uint32_t num_updated_rects)
{
    /* should never be called, used in qxl native mode only */
    fprintf(stderr, "%s: abort()\n", __func__);
    abort();
}

/* called from spice server thread context only */
static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
{
    /* should never be called, used in qxl native mode only */
    fprintf(stderr, "%s: abort()\n", __func__);
    abort();
}

static void interface_set_client_capabilities(QXLInstance *sin,
                                              uint8_t client_present,
                                              uint8_t caps[58])
{
    dprint(3, "%s:\n", __func__);
}

static int interface_client_monitors_config(QXLInstance *sin,
                                        VDAgentMonitorsConfig *monitors_config)
{
    dprint(3, "%s:\n", __func__);
    return 0; /* == not supported by guest */
}

G
Gerd Hoffmann 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
static const QXLInterface dpy_interface = {
    .base.type               = SPICE_INTERFACE_QXL,
    .base.description        = "qemu simple display",
    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,

    .attache_worker          = interface_attach_worker,
    .set_compression_level   = interface_set_compression_level,
    .set_mm_time             = interface_set_mm_time,
    .get_init_info           = interface_get_init_info,

    /* the callbacks below are called from spice server thread context */
    .get_command             = interface_get_command,
    .req_cmd_notification    = interface_req_cmd_notification,
    .release_resource        = interface_release_resource,
    .get_cursor_command      = interface_get_cursor_command,
    .req_cursor_notification = interface_req_cursor_notification,
    .notify_update           = interface_notify_update,
    .flush_resources         = interface_flush_resources,
582 583 584 585
    .async_complete          = interface_async_complete,
    .update_area_complete    = interface_update_area_complete,
    .set_client_capabilities = interface_set_client_capabilities,
    .client_monitors_config  = interface_client_monitors_config,
G
Gerd Hoffmann 已提交
586 587
};

588 589
static void display_update(DisplayChangeListener *dcl,
                           int x, int y, int w, int h)
G
Gerd Hoffmann 已提交
590
{
G
Gerd Hoffmann 已提交
591 592
    SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
    qemu_spice_display_update(ssd, x, y, w, h);
G
Gerd Hoffmann 已提交
593 594
}

595 596
static void display_switch(DisplayChangeListener *dcl,
                           struct DisplaySurface *surface)
G
Gerd Hoffmann 已提交
597
{
G
Gerd Hoffmann 已提交
598
    SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
599
    qemu_spice_display_switch(ssd, surface);
G
Gerd Hoffmann 已提交
600 601
}

602
static void display_refresh(DisplayChangeListener *dcl)
G
Gerd Hoffmann 已提交
603
{
G
Gerd Hoffmann 已提交
604 605
    SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
    qemu_spice_display_refresh(ssd);
G
Gerd Hoffmann 已提交
606 607
}

608 609
static const DisplayChangeListenerOps display_listener_ops = {
    .dpy_name        = "spice",
610
    .dpy_gfx_update  = display_update,
611
    .dpy_gfx_switch  = display_switch,
612
    .dpy_refresh     = display_refresh,
G
Gerd Hoffmann 已提交
613 614
};

G
Gerd Hoffmann 已提交
615
static void qemu_spice_display_init_one(QemuConsole *con)
G
Gerd Hoffmann 已提交
616
{
G
Gerd Hoffmann 已提交
617 618
    SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1);

619
    qemu_spice_display_init_common(ssd);
G
Gerd Hoffmann 已提交
620

G
Gerd Hoffmann 已提交
621
    ssd->qxl.base.sif = &dpy_interface.base;
G
Gerd Hoffmann 已提交
622
    qemu_spice_add_display_interface(&ssd->qxl, con);
G
Gerd Hoffmann 已提交
623
    assert(ssd->worker);
G
Gerd Hoffmann 已提交
624

G
Gerd Hoffmann 已提交
625
    qemu_spice_create_host_memslot(ssd);
626

G
Gerd Hoffmann 已提交
627
    ssd->dcl.ops = &display_listener_ops;
G
Gerd Hoffmann 已提交
628
    ssd->dcl.con = con;
629
    register_displaychangelistener(&ssd->dcl);
G
Gerd Hoffmann 已提交
630 631

    qemu_spice_create_host_primary(ssd);
G
Gerd Hoffmann 已提交
632
}
G
Gerd Hoffmann 已提交
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649

void qemu_spice_display_init(void)
{
    QemuConsole *con;
    int i;

    for (i = 0;; i++) {
        con = qemu_console_lookup_by_index(i);
        if (!con || !qemu_console_is_graphic(con)) {
            break;
        }
        if (qemu_spice_have_display_interface(con)) {
            continue;
        }
        qemu_spice_display_init_one(con);
    }
}