virtio-gpu: tweak scanout disable.
[qemu/ar7.git] / hw / display / virtio-gpu.c
blob054ec73c0a4780e75472a0c6d2a0869c55704f07
1 /*
2 * Virtio GPU Device
4 * Copyright Red Hat, Inc. 2013-2014
6 * Authors:
7 * Dave Airlie <airlied@redhat.com>
8 * Gerd Hoffmann <kraxel@redhat.com>
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "qemu-common.h"
16 #include "qemu/iov.h"
17 #include "ui/console.h"
18 #include "trace.h"
19 #include "hw/virtio/virtio.h"
20 #include "hw/virtio/virtio-gpu.h"
21 #include "hw/virtio/virtio-bus.h"
22 #include "migration/blocker.h"
23 #include "qemu/log.h"
24 #include "qapi/error.h"
26 #define VIRTIO_GPU_VM_VERSION 1
28 static struct virtio_gpu_simple_resource*
29 virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
31 static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res);
33 static void
34 virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr)
36 le32_to_cpus(&hdr->type);
37 le32_to_cpus(&hdr->flags);
38 le64_to_cpus(&hdr->fence_id);
39 le32_to_cpus(&hdr->ctx_id);
40 le32_to_cpus(&hdr->padding);
43 static void virtio_gpu_bswap_32(void *ptr,
44 size_t size)
46 #ifdef HOST_WORDS_BIGENDIAN
48 size_t i;
49 struct virtio_gpu_ctrl_hdr *hdr = (struct virtio_gpu_ctrl_hdr *) ptr;
51 virtio_gpu_ctrl_hdr_bswap(hdr);
53 i = sizeof(struct virtio_gpu_ctrl_hdr);
54 while (i < size) {
55 le32_to_cpus((uint32_t *)(ptr + i));
56 i = i + sizeof(uint32_t);
59 #endif
62 static void
63 virtio_gpu_t2d_bswap(struct virtio_gpu_transfer_to_host_2d *t2d)
65 virtio_gpu_ctrl_hdr_bswap(&t2d->hdr);
66 le32_to_cpus(&t2d->r.x);
67 le32_to_cpus(&t2d->r.y);
68 le32_to_cpus(&t2d->r.width);
69 le32_to_cpus(&t2d->r.height);
70 le64_to_cpus(&t2d->offset);
71 le32_to_cpus(&t2d->resource_id);
72 le32_to_cpus(&t2d->padding);
75 #ifdef CONFIG_VIRGL
76 #include <virglrenderer.h>
77 #define VIRGL(_g, _virgl, _simple, ...) \
78 do { \
79 if (_g->use_virgl_renderer) { \
80 _virgl(__VA_ARGS__); \
81 } else { \
82 _simple(__VA_ARGS__); \
83 } \
84 } while (0)
85 #else
86 #define VIRGL(_g, _virgl, _simple, ...) \
87 do { \
88 _simple(__VA_ARGS__); \
89 } while (0)
90 #endif
92 static void update_cursor_data_simple(VirtIOGPU *g,
93 struct virtio_gpu_scanout *s,
94 uint32_t resource_id)
96 struct virtio_gpu_simple_resource *res;
97 uint32_t pixels;
99 res = virtio_gpu_find_resource(g, resource_id);
100 if (!res) {
101 return;
104 if (pixman_image_get_width(res->image) != s->current_cursor->width ||
105 pixman_image_get_height(res->image) != s->current_cursor->height) {
106 return;
109 pixels = s->current_cursor->width * s->current_cursor->height;
110 memcpy(s->current_cursor->data,
111 pixman_image_get_data(res->image),
112 pixels * sizeof(uint32_t));
115 #ifdef CONFIG_VIRGL
117 static void update_cursor_data_virgl(VirtIOGPU *g,
118 struct virtio_gpu_scanout *s,
119 uint32_t resource_id)
121 uint32_t width, height;
122 uint32_t pixels, *data;
124 data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
125 if (!data) {
126 return;
129 if (width != s->current_cursor->width ||
130 height != s->current_cursor->height) {
131 free(data);
132 return;
135 pixels = s->current_cursor->width * s->current_cursor->height;
136 memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
137 free(data);
140 #endif
142 static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
144 struct virtio_gpu_scanout *s;
145 bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR;
147 if (cursor->pos.scanout_id >= g->conf.max_outputs) {
148 return;
150 s = &g->scanout[cursor->pos.scanout_id];
152 trace_virtio_gpu_update_cursor(cursor->pos.scanout_id,
153 cursor->pos.x,
154 cursor->pos.y,
155 move ? "move" : "update",
156 cursor->resource_id);
158 if (!move) {
159 if (!s->current_cursor) {
160 s->current_cursor = cursor_alloc(64, 64);
163 s->current_cursor->hot_x = cursor->hot_x;
164 s->current_cursor->hot_y = cursor->hot_y;
166 if (cursor->resource_id > 0) {
167 VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple,
168 g, s, cursor->resource_id);
170 dpy_cursor_define(s->con, s->current_cursor);
172 s->cursor = *cursor;
173 } else {
174 s->cursor.pos.x = cursor->pos.x;
175 s->cursor.pos.y = cursor->pos.y;
177 dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y,
178 cursor->resource_id ? 1 : 0);
181 static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config)
183 VirtIOGPU *g = VIRTIO_GPU(vdev);
184 memcpy(config, &g->virtio_config, sizeof(g->virtio_config));
187 static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
189 VirtIOGPU *g = VIRTIO_GPU(vdev);
190 struct virtio_gpu_config vgconfig;
192 memcpy(&vgconfig, config, sizeof(g->virtio_config));
194 if (vgconfig.events_clear) {
195 g->virtio_config.events_read &= ~vgconfig.events_clear;
199 static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features,
200 Error **errp)
202 VirtIOGPU *g = VIRTIO_GPU(vdev);
204 if (virtio_gpu_virgl_enabled(g->conf)) {
205 features |= (1 << VIRTIO_GPU_F_VIRGL);
207 return features;
210 static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
212 static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL);
213 VirtIOGPU *g = VIRTIO_GPU(vdev);
215 g->use_virgl_renderer = ((features & virgl) == virgl);
216 trace_virtio_gpu_features(g->use_virgl_renderer);
219 static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type)
221 g->virtio_config.events_read |= event_type;
222 virtio_notify_config(&g->parent_obj);
225 static struct virtio_gpu_simple_resource *
226 virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
228 struct virtio_gpu_simple_resource *res;
230 QTAILQ_FOREACH(res, &g->reslist, next) {
231 if (res->resource_id == resource_id) {
232 return res;
235 return NULL;
238 void virtio_gpu_ctrl_response(VirtIOGPU *g,
239 struct virtio_gpu_ctrl_command *cmd,
240 struct virtio_gpu_ctrl_hdr *resp,
241 size_t resp_len)
243 size_t s;
245 if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) {
246 resp->flags |= VIRTIO_GPU_FLAG_FENCE;
247 resp->fence_id = cmd->cmd_hdr.fence_id;
248 resp->ctx_id = cmd->cmd_hdr.ctx_id;
250 virtio_gpu_ctrl_hdr_bswap(resp);
251 s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len);
252 if (s != resp_len) {
253 qemu_log_mask(LOG_GUEST_ERROR,
254 "%s: response size incorrect %zu vs %zu\n",
255 __func__, s, resp_len);
257 virtqueue_push(cmd->vq, &cmd->elem, s);
258 virtio_notify(VIRTIO_DEVICE(g), cmd->vq);
259 cmd->finished = true;
262 void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
263 struct virtio_gpu_ctrl_command *cmd,
264 enum virtio_gpu_ctrl_type type)
266 struct virtio_gpu_ctrl_hdr resp;
268 memset(&resp, 0, sizeof(resp));
269 resp.type = type;
270 virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp));
273 static void
274 virtio_gpu_fill_display_info(VirtIOGPU *g,
275 struct virtio_gpu_resp_display_info *dpy_info)
277 int i;
279 for (i = 0; i < g->conf.max_outputs; i++) {
280 if (g->enabled_output_bitmask & (1 << i)) {
281 dpy_info->pmodes[i].enabled = 1;
282 dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width);
283 dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height);
288 void virtio_gpu_get_display_info(VirtIOGPU *g,
289 struct virtio_gpu_ctrl_command *cmd)
291 struct virtio_gpu_resp_display_info display_info;
293 trace_virtio_gpu_cmd_get_display_info();
294 memset(&display_info, 0, sizeof(display_info));
295 display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
296 virtio_gpu_fill_display_info(g, &display_info);
297 virtio_gpu_ctrl_response(g, cmd, &display_info.hdr,
298 sizeof(display_info));
301 static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format)
303 switch (virtio_gpu_format) {
304 case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
305 return PIXMAN_BE_b8g8r8x8;
306 case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
307 return PIXMAN_BE_b8g8r8a8;
308 case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
309 return PIXMAN_BE_x8r8g8b8;
310 case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
311 return PIXMAN_BE_a8r8g8b8;
312 case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
313 return PIXMAN_BE_r8g8b8x8;
314 case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
315 return PIXMAN_BE_r8g8b8a8;
316 case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
317 return PIXMAN_BE_x8b8g8r8;
318 case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
319 return PIXMAN_BE_a8b8g8r8;
320 default:
321 return 0;
325 static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
326 uint32_t width, uint32_t height)
328 /* Copied from pixman/pixman-bits-image.c, skip integer overflow check.
329 * pixman_image_create_bits will fail in case it overflow.
332 int bpp = PIXMAN_FORMAT_BPP(pformat);
333 int stride = ((width * bpp + 0x1f) >> 5) * sizeof(uint32_t);
334 return height * stride;
337 static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
338 struct virtio_gpu_ctrl_command *cmd)
340 pixman_format_code_t pformat;
341 struct virtio_gpu_simple_resource *res;
342 struct virtio_gpu_resource_create_2d c2d;
344 VIRTIO_GPU_FILL_CMD(c2d);
345 virtio_gpu_bswap_32(&c2d, sizeof(c2d));
346 trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
347 c2d.width, c2d.height);
349 if (c2d.resource_id == 0) {
350 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
351 __func__);
352 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
353 return;
356 res = virtio_gpu_find_resource(g, c2d.resource_id);
357 if (res) {
358 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
359 __func__, c2d.resource_id);
360 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
361 return;
364 res = g_new0(struct virtio_gpu_simple_resource, 1);
366 res->width = c2d.width;
367 res->height = c2d.height;
368 res->format = c2d.format;
369 res->resource_id = c2d.resource_id;
371 pformat = get_pixman_format(c2d.format);
372 if (!pformat) {
373 qemu_log_mask(LOG_GUEST_ERROR,
374 "%s: host couldn't handle guest format %d\n",
375 __func__, c2d.format);
376 g_free(res);
377 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
378 return;
381 res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
382 if (res->hostmem + g->hostmem < g->conf.max_hostmem) {
383 res->image = pixman_image_create_bits(pformat,
384 c2d.width,
385 c2d.height,
386 NULL, 0);
389 if (!res->image) {
390 qemu_log_mask(LOG_GUEST_ERROR,
391 "%s: resource creation failed %d %d %d\n",
392 __func__, c2d.resource_id, c2d.width, c2d.height);
393 g_free(res);
394 cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
395 return;
398 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
399 g->hostmem += res->hostmem;
402 static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
404 struct virtio_gpu_scanout *scanout = &g->scanout[scanout_id];
405 struct virtio_gpu_simple_resource *res;
406 DisplaySurface *ds = NULL;
408 if (scanout->resource_id == 0) {
409 return;
412 res = virtio_gpu_find_resource(g, scanout->resource_id);
413 if (res) {
414 res->scanout_bitmask &= ~(1 << scanout_id);
417 if (scanout_id == 0) {
418 /* primary head */
419 ds = qemu_create_message_surface(scanout->width ?: 640,
420 scanout->height ?: 480,
421 "Guest disabled display.");
423 dpy_gfx_replace_surface(scanout->con, ds);
424 scanout->resource_id = 0;
425 scanout->ds = NULL;
426 scanout->width = 0;
427 scanout->height = 0;
430 static void virtio_gpu_resource_destroy(VirtIOGPU *g,
431 struct virtio_gpu_simple_resource *res)
433 pixman_image_unref(res->image);
434 virtio_gpu_cleanup_mapping(res);
435 QTAILQ_REMOVE(&g->reslist, res, next);
436 g->hostmem -= res->hostmem;
437 g_free(res);
440 static void virtio_gpu_resource_unref(VirtIOGPU *g,
441 struct virtio_gpu_ctrl_command *cmd)
443 struct virtio_gpu_simple_resource *res;
444 struct virtio_gpu_resource_unref unref;
446 VIRTIO_GPU_FILL_CMD(unref);
447 virtio_gpu_bswap_32(&unref, sizeof(unref));
448 trace_virtio_gpu_cmd_res_unref(unref.resource_id);
450 res = virtio_gpu_find_resource(g, unref.resource_id);
451 if (!res) {
452 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
453 __func__, unref.resource_id);
454 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
455 return;
457 virtio_gpu_resource_destroy(g, res);
460 static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
461 struct virtio_gpu_ctrl_command *cmd)
463 struct virtio_gpu_simple_resource *res;
464 int h;
465 uint32_t src_offset, dst_offset, stride;
466 int bpp;
467 pixman_format_code_t format;
468 struct virtio_gpu_transfer_to_host_2d t2d;
470 VIRTIO_GPU_FILL_CMD(t2d);
471 virtio_gpu_t2d_bswap(&t2d);
472 trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
474 res = virtio_gpu_find_resource(g, t2d.resource_id);
475 if (!res || !res->iov) {
476 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
477 __func__, t2d.resource_id);
478 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
479 return;
482 if (t2d.r.x > res->width ||
483 t2d.r.y > res->height ||
484 t2d.r.width > res->width ||
485 t2d.r.height > res->height ||
486 t2d.r.x + t2d.r.width > res->width ||
487 t2d.r.y + t2d.r.height > res->height) {
488 qemu_log_mask(LOG_GUEST_ERROR, "%s: transfer bounds outside resource"
489 " bounds for resource %d: %d %d %d %d vs %d %d\n",
490 __func__, t2d.resource_id, t2d.r.x, t2d.r.y,
491 t2d.r.width, t2d.r.height, res->width, res->height);
492 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
493 return;
496 format = pixman_image_get_format(res->image);
497 bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
498 stride = pixman_image_get_stride(res->image);
500 if (t2d.offset || t2d.r.x || t2d.r.y ||
501 t2d.r.width != pixman_image_get_width(res->image)) {
502 void *img_data = pixman_image_get_data(res->image);
503 for (h = 0; h < t2d.r.height; h++) {
504 src_offset = t2d.offset + stride * h;
505 dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
507 iov_to_buf(res->iov, res->iov_cnt, src_offset,
508 (uint8_t *)img_data
509 + dst_offset, t2d.r.width * bpp);
511 } else {
512 iov_to_buf(res->iov, res->iov_cnt, 0,
513 pixman_image_get_data(res->image),
514 pixman_image_get_stride(res->image)
515 * pixman_image_get_height(res->image));
519 static void virtio_gpu_resource_flush(VirtIOGPU *g,
520 struct virtio_gpu_ctrl_command *cmd)
522 struct virtio_gpu_simple_resource *res;
523 struct virtio_gpu_resource_flush rf;
524 pixman_region16_t flush_region;
525 int i;
527 VIRTIO_GPU_FILL_CMD(rf);
528 virtio_gpu_bswap_32(&rf, sizeof(rf));
529 trace_virtio_gpu_cmd_res_flush(rf.resource_id,
530 rf.r.width, rf.r.height, rf.r.x, rf.r.y);
532 res = virtio_gpu_find_resource(g, rf.resource_id);
533 if (!res) {
534 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
535 __func__, rf.resource_id);
536 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
537 return;
540 if (rf.r.x > res->width ||
541 rf.r.y > res->height ||
542 rf.r.width > res->width ||
543 rf.r.height > res->height ||
544 rf.r.x + rf.r.width > res->width ||
545 rf.r.y + rf.r.height > res->height) {
546 qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside resource"
547 " bounds for resource %d: %d %d %d %d vs %d %d\n",
548 __func__, rf.resource_id, rf.r.x, rf.r.y,
549 rf.r.width, rf.r.height, res->width, res->height);
550 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
551 return;
554 pixman_region_init_rect(&flush_region,
555 rf.r.x, rf.r.y, rf.r.width, rf.r.height);
556 for (i = 0; i < g->conf.max_outputs; i++) {
557 struct virtio_gpu_scanout *scanout;
558 pixman_region16_t region, finalregion;
559 pixman_box16_t *extents;
561 if (!(res->scanout_bitmask & (1 << i))) {
562 continue;
564 scanout = &g->scanout[i];
566 pixman_region_init(&finalregion);
567 pixman_region_init_rect(&region, scanout->x, scanout->y,
568 scanout->width, scanout->height);
570 pixman_region_intersect(&finalregion, &flush_region, &region);
571 pixman_region_translate(&finalregion, -scanout->x, -scanout->y);
572 extents = pixman_region_extents(&finalregion);
573 /* work out the area we need to update for each console */
574 dpy_gfx_update(g->scanout[i].con,
575 extents->x1, extents->y1,
576 extents->x2 - extents->x1,
577 extents->y2 - extents->y1);
579 pixman_region_fini(&region);
580 pixman_region_fini(&finalregion);
582 pixman_region_fini(&flush_region);
585 static void virtio_unref_resource(pixman_image_t *image, void *data)
587 pixman_image_unref(data);
590 static void virtio_gpu_set_scanout(VirtIOGPU *g,
591 struct virtio_gpu_ctrl_command *cmd)
593 struct virtio_gpu_simple_resource *res;
594 struct virtio_gpu_scanout *scanout;
595 pixman_format_code_t format;
596 uint32_t offset;
597 int bpp;
598 struct virtio_gpu_set_scanout ss;
600 VIRTIO_GPU_FILL_CMD(ss);
601 virtio_gpu_bswap_32(&ss, sizeof(ss));
602 trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
603 ss.r.width, ss.r.height, ss.r.x, ss.r.y);
605 if (ss.scanout_id >= g->conf.max_outputs) {
606 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
607 __func__, ss.scanout_id);
608 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
609 return;
612 g->enable = 1;
613 if (ss.resource_id == 0) {
614 virtio_gpu_disable_scanout(g, ss.scanout_id);
615 return;
618 /* create a surface for this scanout */
619 res = virtio_gpu_find_resource(g, ss.resource_id);
620 if (!res) {
621 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
622 __func__, ss.resource_id);
623 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
624 return;
627 if (ss.r.x > res->width ||
628 ss.r.y > res->height ||
629 ss.r.width > res->width ||
630 ss.r.height > res->height ||
631 ss.r.x + ss.r.width > res->width ||
632 ss.r.y + ss.r.height > res->height) {
633 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
634 " resource %d, (%d,%d)+%d,%d vs %d %d\n",
635 __func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y,
636 ss.r.width, ss.r.height, res->width, res->height);
637 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
638 return;
641 scanout = &g->scanout[ss.scanout_id];
643 format = pixman_image_get_format(res->image);
644 bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
645 offset = (ss.r.x * bpp) + ss.r.y * pixman_image_get_stride(res->image);
646 if (!scanout->ds || surface_data(scanout->ds)
647 != ((uint8_t *)pixman_image_get_data(res->image) + offset) ||
648 scanout->width != ss.r.width ||
649 scanout->height != ss.r.height) {
650 pixman_image_t *rect;
651 void *ptr = (uint8_t *)pixman_image_get_data(res->image) + offset;
652 rect = pixman_image_create_bits(format, ss.r.width, ss.r.height, ptr,
653 pixman_image_get_stride(res->image));
654 pixman_image_ref(res->image);
655 pixman_image_set_destroy_function(rect, virtio_unref_resource,
656 res->image);
657 /* realloc the surface ptr */
658 scanout->ds = qemu_create_displaysurface_pixman(rect);
659 if (!scanout->ds) {
660 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
661 return;
663 pixman_image_unref(rect);
664 dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
667 res->scanout_bitmask |= (1 << ss.scanout_id);
668 scanout->resource_id = ss.resource_id;
669 scanout->x = ss.r.x;
670 scanout->y = ss.r.y;
671 scanout->width = ss.r.width;
672 scanout->height = ss.r.height;
675 int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
676 struct virtio_gpu_ctrl_command *cmd,
677 uint64_t **addr, struct iovec **iov)
679 struct virtio_gpu_mem_entry *ents;
680 size_t esize, s;
681 int i;
683 if (ab->nr_entries > 16384) {
684 qemu_log_mask(LOG_GUEST_ERROR,
685 "%s: nr_entries is too big (%d > 16384)\n",
686 __func__, ab->nr_entries);
687 return -1;
690 esize = sizeof(*ents) * ab->nr_entries;
691 ents = g_malloc(esize);
692 s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
693 sizeof(*ab), ents, esize);
694 if (s != esize) {
695 qemu_log_mask(LOG_GUEST_ERROR,
696 "%s: command data size incorrect %zu vs %zu\n",
697 __func__, s, esize);
698 g_free(ents);
699 return -1;
702 *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
703 if (addr) {
704 *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries);
706 for (i = 0; i < ab->nr_entries; i++) {
707 uint64_t a = le64_to_cpu(ents[i].addr);
708 uint32_t l = le32_to_cpu(ents[i].length);
709 hwaddr len = l;
710 (*iov)[i].iov_len = l;
711 (*iov)[i].iov_base = cpu_physical_memory_map(a, &len, 1);
712 if (addr) {
713 (*addr)[i] = a;
715 if (!(*iov)[i].iov_base || len != l) {
716 qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
717 " resource %d element %d\n",
718 __func__, ab->resource_id, i);
719 virtio_gpu_cleanup_mapping_iov(*iov, i);
720 g_free(ents);
721 *iov = NULL;
722 if (addr) {
723 g_free(*addr);
724 *addr = NULL;
726 return -1;
729 g_free(ents);
730 return 0;
733 void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count)
735 int i;
737 for (i = 0; i < count; i++) {
738 cpu_physical_memory_unmap(iov[i].iov_base, iov[i].iov_len, 1,
739 iov[i].iov_len);
741 g_free(iov);
744 static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res)
746 virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt);
747 res->iov = NULL;
748 res->iov_cnt = 0;
749 g_free(res->addrs);
750 res->addrs = NULL;
753 static void
754 virtio_gpu_resource_attach_backing(VirtIOGPU *g,
755 struct virtio_gpu_ctrl_command *cmd)
757 struct virtio_gpu_simple_resource *res;
758 struct virtio_gpu_resource_attach_backing ab;
759 int ret;
761 VIRTIO_GPU_FILL_CMD(ab);
762 virtio_gpu_bswap_32(&ab, sizeof(ab));
763 trace_virtio_gpu_cmd_res_back_attach(ab.resource_id);
765 res = virtio_gpu_find_resource(g, ab.resource_id);
766 if (!res) {
767 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
768 __func__, ab.resource_id);
769 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
770 return;
773 if (res->iov) {
774 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
775 return;
778 ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->addrs, &res->iov);
779 if (ret != 0) {
780 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
781 return;
784 res->iov_cnt = ab.nr_entries;
787 static void
788 virtio_gpu_resource_detach_backing(VirtIOGPU *g,
789 struct virtio_gpu_ctrl_command *cmd)
791 struct virtio_gpu_simple_resource *res;
792 struct virtio_gpu_resource_detach_backing detach;
794 VIRTIO_GPU_FILL_CMD(detach);
795 virtio_gpu_bswap_32(&detach, sizeof(detach));
796 trace_virtio_gpu_cmd_res_back_detach(detach.resource_id);
798 res = virtio_gpu_find_resource(g, detach.resource_id);
799 if (!res || !res->iov) {
800 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
801 __func__, detach.resource_id);
802 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
803 return;
805 virtio_gpu_cleanup_mapping(res);
808 static void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
809 struct virtio_gpu_ctrl_command *cmd)
811 VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
812 virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr);
814 switch (cmd->cmd_hdr.type) {
815 case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
816 virtio_gpu_get_display_info(g, cmd);
817 break;
818 case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
819 virtio_gpu_resource_create_2d(g, cmd);
820 break;
821 case VIRTIO_GPU_CMD_RESOURCE_UNREF:
822 virtio_gpu_resource_unref(g, cmd);
823 break;
824 case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
825 virtio_gpu_resource_flush(g, cmd);
826 break;
827 case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
828 virtio_gpu_transfer_to_host_2d(g, cmd);
829 break;
830 case VIRTIO_GPU_CMD_SET_SCANOUT:
831 virtio_gpu_set_scanout(g, cmd);
832 break;
833 case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
834 virtio_gpu_resource_attach_backing(g, cmd);
835 break;
836 case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
837 virtio_gpu_resource_detach_backing(g, cmd);
838 break;
839 default:
840 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
841 break;
843 if (!cmd->finished) {
844 virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error :
845 VIRTIO_GPU_RESP_OK_NODATA);
849 static void virtio_gpu_handle_ctrl_cb(VirtIODevice *vdev, VirtQueue *vq)
851 VirtIOGPU *g = VIRTIO_GPU(vdev);
852 qemu_bh_schedule(g->ctrl_bh);
855 static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
857 VirtIOGPU *g = VIRTIO_GPU(vdev);
858 qemu_bh_schedule(g->cursor_bh);
861 void virtio_gpu_process_cmdq(VirtIOGPU *g)
863 struct virtio_gpu_ctrl_command *cmd;
865 while (!QTAILQ_EMPTY(&g->cmdq)) {
866 cmd = QTAILQ_FIRST(&g->cmdq);
868 /* process command */
869 VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd,
870 g, cmd);
871 if (cmd->waiting) {
872 break;
874 QTAILQ_REMOVE(&g->cmdq, cmd, next);
875 if (virtio_gpu_stats_enabled(g->conf)) {
876 g->stats.requests++;
879 if (!cmd->finished) {
880 QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
881 g->inflight++;
882 if (virtio_gpu_stats_enabled(g->conf)) {
883 if (g->stats.max_inflight < g->inflight) {
884 g->stats.max_inflight = g->inflight;
886 fprintf(stderr, "inflight: %3d (+)\r", g->inflight);
888 } else {
889 g_free(cmd);
894 static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
896 VirtIOGPU *g = VIRTIO_GPU(vdev);
897 struct virtio_gpu_ctrl_command *cmd;
899 if (!virtio_queue_ready(vq)) {
900 return;
903 #ifdef CONFIG_VIRGL
904 if (!g->renderer_inited && g->use_virgl_renderer) {
905 virtio_gpu_virgl_init(g);
906 g->renderer_inited = true;
908 #endif
910 cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
911 while (cmd) {
912 cmd->vq = vq;
913 cmd->error = 0;
914 cmd->finished = false;
915 cmd->waiting = false;
916 QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
917 cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
920 virtio_gpu_process_cmdq(g);
922 #ifdef CONFIG_VIRGL
923 if (g->use_virgl_renderer) {
924 virtio_gpu_virgl_fence_poll(g);
926 #endif
929 static void virtio_gpu_ctrl_bh(void *opaque)
931 VirtIOGPU *g = opaque;
932 virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq);
935 static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
937 VirtIOGPU *g = VIRTIO_GPU(vdev);
938 VirtQueueElement *elem;
939 size_t s;
940 struct virtio_gpu_update_cursor cursor_info;
942 if (!virtio_queue_ready(vq)) {
943 return;
945 for (;;) {
946 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
947 if (!elem) {
948 break;
951 s = iov_to_buf(elem->out_sg, elem->out_num, 0,
952 &cursor_info, sizeof(cursor_info));
953 if (s != sizeof(cursor_info)) {
954 qemu_log_mask(LOG_GUEST_ERROR,
955 "%s: cursor size incorrect %zu vs %zu\n",
956 __func__, s, sizeof(cursor_info));
957 } else {
958 virtio_gpu_bswap_32(&cursor_info, sizeof(cursor_info));
959 update_cursor(g, &cursor_info);
961 virtqueue_push(vq, elem, 0);
962 virtio_notify(vdev, vq);
963 g_free(elem);
967 static void virtio_gpu_cursor_bh(void *opaque)
969 VirtIOGPU *g = opaque;
970 virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq);
973 static void virtio_gpu_invalidate_display(void *opaque)
977 static void virtio_gpu_update_display(void *opaque)
981 static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
985 static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
987 VirtIOGPU *g = opaque;
989 if (idx >= g->conf.max_outputs) {
990 return -1;
993 g->req_state[idx].x = info->xoff;
994 g->req_state[idx].y = info->yoff;
995 g->req_state[idx].width = info->width;
996 g->req_state[idx].height = info->height;
998 if (info->width && info->height) {
999 g->enabled_output_bitmask |= (1 << idx);
1000 } else {
1001 g->enabled_output_bitmask &= ~(1 << idx);
1004 /* send event to guest */
1005 virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
1006 return 0;
1009 const GraphicHwOps virtio_gpu_ops = {
1010 .invalidate = virtio_gpu_invalidate_display,
1011 .gfx_update = virtio_gpu_update_display,
1012 .text_update = virtio_gpu_text_update,
1013 .ui_info = virtio_gpu_ui_info,
1014 #ifdef CONFIG_VIRGL
1015 .gl_block = virtio_gpu_gl_block,
1016 #endif
1019 static const VMStateDescription vmstate_virtio_gpu_scanout = {
1020 .name = "virtio-gpu-one-scanout",
1021 .version_id = 1,
1022 .fields = (VMStateField[]) {
1023 VMSTATE_UINT32(resource_id, struct virtio_gpu_scanout),
1024 VMSTATE_UINT32(width, struct virtio_gpu_scanout),
1025 VMSTATE_UINT32(height, struct virtio_gpu_scanout),
1026 VMSTATE_INT32(x, struct virtio_gpu_scanout),
1027 VMSTATE_INT32(y, struct virtio_gpu_scanout),
1028 VMSTATE_UINT32(cursor.resource_id, struct virtio_gpu_scanout),
1029 VMSTATE_UINT32(cursor.hot_x, struct virtio_gpu_scanout),
1030 VMSTATE_UINT32(cursor.hot_y, struct virtio_gpu_scanout),
1031 VMSTATE_UINT32(cursor.pos.x, struct virtio_gpu_scanout),
1032 VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout),
1033 VMSTATE_END_OF_LIST()
1037 static const VMStateDescription vmstate_virtio_gpu_scanouts = {
1038 .name = "virtio-gpu-scanouts",
1039 .version_id = 1,
1040 .fields = (VMStateField[]) {
1041 VMSTATE_INT32(enable, struct VirtIOGPU),
1042 VMSTATE_UINT32_EQUAL(conf.max_outputs, struct VirtIOGPU, NULL),
1043 VMSTATE_STRUCT_VARRAY_UINT32(scanout, struct VirtIOGPU,
1044 conf.max_outputs, 1,
1045 vmstate_virtio_gpu_scanout,
1046 struct virtio_gpu_scanout),
1047 VMSTATE_END_OF_LIST()
1051 static int virtio_gpu_save(QEMUFile *f, void *opaque, size_t size,
1052 VMStateField *field, QJSON *vmdesc)
1054 VirtIOGPU *g = opaque;
1055 struct virtio_gpu_simple_resource *res;
1056 int i;
1058 /* in 2d mode we should never find unprocessed commands here */
1059 assert(QTAILQ_EMPTY(&g->cmdq));
1061 QTAILQ_FOREACH(res, &g->reslist, next) {
1062 qemu_put_be32(f, res->resource_id);
1063 qemu_put_be32(f, res->width);
1064 qemu_put_be32(f, res->height);
1065 qemu_put_be32(f, res->format);
1066 qemu_put_be32(f, res->iov_cnt);
1067 for (i = 0; i < res->iov_cnt; i++) {
1068 qemu_put_be64(f, res->addrs[i]);
1069 qemu_put_be32(f, res->iov[i].iov_len);
1071 qemu_put_buffer(f, (void *)pixman_image_get_data(res->image),
1072 pixman_image_get_stride(res->image) * res->height);
1074 qemu_put_be32(f, 0); /* end of list */
1076 return vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL);
1079 static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
1080 VMStateField *field)
1082 VirtIOGPU *g = opaque;
1083 struct virtio_gpu_simple_resource *res;
1084 struct virtio_gpu_scanout *scanout;
1085 uint32_t resource_id, pformat;
1086 int i;
1088 g->hostmem = 0;
1090 resource_id = qemu_get_be32(f);
1091 while (resource_id != 0) {
1092 res = g_new0(struct virtio_gpu_simple_resource, 1);
1093 res->resource_id = resource_id;
1094 res->width = qemu_get_be32(f);
1095 res->height = qemu_get_be32(f);
1096 res->format = qemu_get_be32(f);
1097 res->iov_cnt = qemu_get_be32(f);
1099 /* allocate */
1100 pformat = get_pixman_format(res->format);
1101 if (!pformat) {
1102 g_free(res);
1103 return -EINVAL;
1105 res->image = pixman_image_create_bits(pformat,
1106 res->width, res->height,
1107 NULL, 0);
1108 if (!res->image) {
1109 g_free(res);
1110 return -EINVAL;
1113 res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
1115 res->addrs = g_new(uint64_t, res->iov_cnt);
1116 res->iov = g_new(struct iovec, res->iov_cnt);
1118 /* read data */
1119 for (i = 0; i < res->iov_cnt; i++) {
1120 res->addrs[i] = qemu_get_be64(f);
1121 res->iov[i].iov_len = qemu_get_be32(f);
1123 qemu_get_buffer(f, (void *)pixman_image_get_data(res->image),
1124 pixman_image_get_stride(res->image) * res->height);
1126 /* restore mapping */
1127 for (i = 0; i < res->iov_cnt; i++) {
1128 hwaddr len = res->iov[i].iov_len;
1129 res->iov[i].iov_base =
1130 cpu_physical_memory_map(res->addrs[i], &len, 1);
1131 if (!res->iov[i].iov_base || len != res->iov[i].iov_len) {
1132 /* Clean up the half-a-mapping we just created... */
1133 if (res->iov[i].iov_base) {
1134 cpu_physical_memory_unmap(res->iov[i].iov_base,
1135 len, 0, 0);
1137 /* ...and the mappings for previous loop iterations */
1138 res->iov_cnt = i;
1139 virtio_gpu_cleanup_mapping(res);
1140 pixman_image_unref(res->image);
1141 g_free(res);
1142 return -EINVAL;
1146 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
1147 g->hostmem += res->hostmem;
1149 resource_id = qemu_get_be32(f);
1152 /* load & apply scanout state */
1153 vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
1154 for (i = 0; i < g->conf.max_outputs; i++) {
1155 scanout = &g->scanout[i];
1156 if (!scanout->resource_id) {
1157 continue;
1159 res = virtio_gpu_find_resource(g, scanout->resource_id);
1160 if (!res) {
1161 return -EINVAL;
1163 scanout->ds = qemu_create_displaysurface_pixman(res->image);
1164 if (!scanout->ds) {
1165 return -EINVAL;
1168 dpy_gfx_replace_surface(scanout->con, scanout->ds);
1169 dpy_gfx_update(scanout->con, 0, 0, scanout->width, scanout->height);
1170 if (scanout->cursor.resource_id) {
1171 update_cursor(g, &scanout->cursor);
1173 res->scanout_bitmask |= (1 << i);
1176 return 0;
1179 static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
1181 VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
1182 VirtIOGPU *g = VIRTIO_GPU(qdev);
1183 bool have_virgl;
1184 Error *local_err = NULL;
1185 int i;
1187 if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
1188 error_setg(errp, "virtio-gpu does not support vIOMMU yet");
1189 return;
1192 if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) {
1193 error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS);
1194 return;
1197 g->use_virgl_renderer = false;
1198 #if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
1199 have_virgl = false;
1200 #else
1201 have_virgl = display_opengl;
1202 #endif
1203 if (!have_virgl) {
1204 g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
1207 if (virtio_gpu_virgl_enabled(g->conf)) {
1208 error_setg(&g->migration_blocker, "virgl is not yet migratable");
1209 migrate_add_blocker(g->migration_blocker, &local_err);
1210 if (local_err) {
1211 error_propagate(errp, local_err);
1212 error_free(g->migration_blocker);
1213 return;
1217 g->config_size = sizeof(struct virtio_gpu_config);
1218 g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs);
1219 virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
1220 g->config_size);
1222 g->req_state[0].width = g->conf.xres;
1223 g->req_state[0].height = g->conf.yres;
1225 if (virtio_gpu_virgl_enabled(g->conf)) {
1226 /* use larger control queue in 3d mode */
1227 g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
1228 g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
1230 #if defined(CONFIG_VIRGL)
1231 g->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g);
1232 #else
1233 g->virtio_config.num_capsets = 0;
1234 #endif
1235 } else {
1236 g->ctrl_vq = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb);
1237 g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
1240 g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
1241 g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
1242 QTAILQ_INIT(&g->reslist);
1243 QTAILQ_INIT(&g->cmdq);
1244 QTAILQ_INIT(&g->fenceq);
1246 g->enabled_output_bitmask = 1;
1247 g->qdev = qdev;
1249 for (i = 0; i < g->conf.max_outputs; i++) {
1250 g->scanout[i].con =
1251 graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
1252 if (i > 0) {
1253 dpy_gfx_replace_surface(g->scanout[i].con, NULL);
1258 static void virtio_gpu_device_unrealize(DeviceState *qdev, Error **errp)
1260 VirtIOGPU *g = VIRTIO_GPU(qdev);
1261 if (g->migration_blocker) {
1262 migrate_del_blocker(g->migration_blocker);
1263 error_free(g->migration_blocker);
1267 static void virtio_gpu_instance_init(Object *obj)
1271 static void virtio_gpu_reset(VirtIODevice *vdev)
1273 VirtIOGPU *g = VIRTIO_GPU(vdev);
1274 struct virtio_gpu_simple_resource *res, *tmp;
1275 int i;
1277 g->enable = 0;
1279 QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
1280 virtio_gpu_resource_destroy(g, res);
1282 for (i = 0; i < g->conf.max_outputs; i++) {
1283 g->scanout[i].resource_id = 0;
1284 g->scanout[i].width = 0;
1285 g->scanout[i].height = 0;
1286 g->scanout[i].x = 0;
1287 g->scanout[i].y = 0;
1288 g->scanout[i].ds = NULL;
1291 #ifdef CONFIG_VIRGL
1292 if (g->use_virgl_renderer) {
1293 virtio_gpu_virgl_reset(g);
1294 g->use_virgl_renderer = 0;
1296 #endif
1300 * For historical reasons virtio_gpu does not adhere to virtio migration
1301 * scheme as described in doc/virtio-migration.txt, in a sense that no
1302 * save/load callback are provided to the core. Instead the device data
1303 * is saved/loaded after the core data.
1305 * Because of this we need a special vmsd.
1307 static const VMStateDescription vmstate_virtio_gpu = {
1308 .name = "virtio-gpu",
1309 .minimum_version_id = VIRTIO_GPU_VM_VERSION,
1310 .version_id = VIRTIO_GPU_VM_VERSION,
1311 .fields = (VMStateField[]) {
1312 VMSTATE_VIRTIO_DEVICE /* core */,
1314 .name = "virtio-gpu",
1315 .info = &(const VMStateInfo) {
1316 .name = "virtio-gpu",
1317 .get = virtio_gpu_load,
1318 .put = virtio_gpu_save,
1320 .flags = VMS_SINGLE,
1321 } /* device */,
1322 VMSTATE_END_OF_LIST()
1326 static Property virtio_gpu_properties[] = {
1327 DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
1328 DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf.max_hostmem,
1329 256 * 1024 * 1024),
1330 #ifdef CONFIG_VIRGL
1331 DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags,
1332 VIRTIO_GPU_FLAG_VIRGL_ENABLED, true),
1333 DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags,
1334 VIRTIO_GPU_FLAG_STATS_ENABLED, false),
1335 #endif
1336 DEFINE_PROP_UINT32("xres", VirtIOGPU, conf.xres, 1024),
1337 DEFINE_PROP_UINT32("yres", VirtIOGPU, conf.yres, 768),
1338 DEFINE_PROP_END_OF_LIST(),
1341 static void virtio_gpu_class_init(ObjectClass *klass, void *data)
1343 DeviceClass *dc = DEVICE_CLASS(klass);
1344 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
1346 vdc->realize = virtio_gpu_device_realize;
1347 vdc->unrealize = virtio_gpu_device_unrealize;
1348 vdc->get_config = virtio_gpu_get_config;
1349 vdc->set_config = virtio_gpu_set_config;
1350 vdc->get_features = virtio_gpu_get_features;
1351 vdc->set_features = virtio_gpu_set_features;
1353 vdc->reset = virtio_gpu_reset;
1355 set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
1356 dc->props = virtio_gpu_properties;
1357 dc->vmsd = &vmstate_virtio_gpu;
1358 dc->hotpluggable = false;
1361 static const TypeInfo virtio_gpu_info = {
1362 .name = TYPE_VIRTIO_GPU,
1363 .parent = TYPE_VIRTIO_DEVICE,
1364 .instance_size = sizeof(VirtIOGPU),
1365 .instance_init = virtio_gpu_instance_init,
1366 .class_init = virtio_gpu_class_init,
1369 static void virtio_register_types(void)
1371 type_register_static(&virtio_gpu_info);
1374 type_init(virtio_register_types)
1376 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24);
1377 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56);
1378 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32);
1379 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40);
1380 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48);
1381 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48);
1382 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56);
1383 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16);
1384 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32);
1385 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32);
1386 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408);
1388 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72);
1389 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72);
1390 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96);
1391 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24);
1392 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32);
1393 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32);
1394 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32);
1395 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40);
1396 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32);
1397 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24);