1 /* 2 * Virtio GPU Device 3 * 4 * Copyright Red Hat, Inc. 2013-2014 5 * 6 * Authors: 7 * Dave Airlie <airlied@redhat.com> 8 * Gerd Hoffmann <kraxel@redhat.com> 9 * 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. 12 */ 13 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 "qemu/log.h" 23 #include "qapi/error.h" 24 25 #define VIRTIO_GPU_VM_VERSION 1 26 27 static struct virtio_gpu_simple_resource* 28 virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); 29 30 #ifdef CONFIG_VIRGL 31 #include <virglrenderer.h> 32 #define VIRGL(_g, _virgl, _simple, ...) \ 33 do { \ 34 if (_g->use_virgl_renderer) { \ 35 _virgl(__VA_ARGS__); \ 36 } else { \ 37 _simple(__VA_ARGS__); \ 38 } \ 39 } while (0) 40 #else 41 #define VIRGL(_g, _virgl, _simple, ...) \ 42 do { \ 43 _simple(__VA_ARGS__); \ 44 } while (0) 45 #endif 46 47 static void update_cursor_data_simple(VirtIOGPU *g, 48 struct virtio_gpu_scanout *s, 49 uint32_t resource_id) 50 { 51 struct virtio_gpu_simple_resource *res; 52 uint32_t pixels; 53 54 res = virtio_gpu_find_resource(g, resource_id); 55 if (!res) { 56 return; 57 } 58 59 if (pixman_image_get_width(res->image) != s->current_cursor->width || 60 pixman_image_get_height(res->image) != s->current_cursor->height) { 61 return; 62 } 63 64 pixels = s->current_cursor->width * s->current_cursor->height; 65 memcpy(s->current_cursor->data, 66 pixman_image_get_data(res->image), 67 pixels * sizeof(uint32_t)); 68 } 69 70 #ifdef CONFIG_VIRGL 71 72 static void update_cursor_data_virgl(VirtIOGPU *g, 73 struct virtio_gpu_scanout *s, 74 uint32_t resource_id) 75 { 76 uint32_t width, height; 77 uint32_t pixels, *data; 78 79 data = virgl_renderer_get_cursor_data(resource_id, &width, &height); 80 if (!data) { 81 return; 82 } 83 84 if (width != s->current_cursor->width || 85 height != s->current_cursor->height) { 86 return; 87 } 88 89 pixels = s->current_cursor->width * s->current_cursor->height; 90 memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t)); 91 free(data); 92 } 93 94 #endif 95 96 static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) 97 { 98 struct virtio_gpu_scanout *s; 99 bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR; 100 101 if (cursor->pos.scanout_id >= g->conf.max_outputs) { 102 return; 103 } 104 s = &g->scanout[cursor->pos.scanout_id]; 105 106 trace_virtio_gpu_update_cursor(cursor->pos.scanout_id, 107 cursor->pos.x, 108 cursor->pos.y, 109 move ? "move" : "update", 110 cursor->resource_id); 111 112 if (!move) { 113 if (!s->current_cursor) { 114 s->current_cursor = cursor_alloc(64, 64); 115 } 116 117 s->current_cursor->hot_x = cursor->hot_x; 118 s->current_cursor->hot_y = cursor->hot_y; 119 120 if (cursor->resource_id > 0) { 121 VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple, 122 g, s, cursor->resource_id); 123 } 124 dpy_cursor_define(s->con, s->current_cursor); 125 126 s->cursor = *cursor; 127 } else { 128 s->cursor.pos.x = cursor->pos.x; 129 s->cursor.pos.y = cursor->pos.y; 130 } 131 dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y, 132 cursor->resource_id ? 1 : 0); 133 } 134 135 static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config) 136 { 137 VirtIOGPU *g = VIRTIO_GPU(vdev); 138 memcpy(config, &g->virtio_config, sizeof(g->virtio_config)); 139 } 140 141 static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config) 142 { 143 VirtIOGPU *g = VIRTIO_GPU(vdev); 144 struct virtio_gpu_config vgconfig; 145 146 memcpy(&vgconfig, config, sizeof(g->virtio_config)); 147 148 if (vgconfig.events_clear) { 149 g->virtio_config.events_read &= ~vgconfig.events_clear; 150 } 151 } 152 153 static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features, 154 Error **errp) 155 { 156 VirtIOGPU *g = VIRTIO_GPU(vdev); 157 158 if (virtio_gpu_virgl_enabled(g->conf)) { 159 features |= (1 << VIRTIO_GPU_F_VIRGL); 160 } 161 return features; 162 } 163 164 static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features) 165 { 166 static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); 167 VirtIOGPU *g = VIRTIO_GPU(vdev); 168 169 g->use_virgl_renderer = ((features & virgl) == virgl); 170 trace_virtio_gpu_features(g->use_virgl_renderer); 171 } 172 173 static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type) 174 { 175 g->virtio_config.events_read |= event_type; 176 virtio_notify_config(&g->parent_obj); 177 } 178 179 static struct virtio_gpu_simple_resource * 180 virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id) 181 { 182 struct virtio_gpu_simple_resource *res; 183 184 QTAILQ_FOREACH(res, &g->reslist, next) { 185 if (res->resource_id == resource_id) { 186 return res; 187 } 188 } 189 return NULL; 190 } 191 192 void virtio_gpu_ctrl_response(VirtIOGPU *g, 193 struct virtio_gpu_ctrl_command *cmd, 194 struct virtio_gpu_ctrl_hdr *resp, 195 size_t resp_len) 196 { 197 size_t s; 198 199 if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) { 200 resp->flags |= VIRTIO_GPU_FLAG_FENCE; 201 resp->fence_id = cmd->cmd_hdr.fence_id; 202 resp->ctx_id = cmd->cmd_hdr.ctx_id; 203 } 204 s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len); 205 if (s != resp_len) { 206 qemu_log_mask(LOG_GUEST_ERROR, 207 "%s: response size incorrect %zu vs %zu\n", 208 __func__, s, resp_len); 209 } 210 virtqueue_push(cmd->vq, &cmd->elem, s); 211 virtio_notify(VIRTIO_DEVICE(g), cmd->vq); 212 cmd->finished = true; 213 } 214 215 void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g, 216 struct virtio_gpu_ctrl_command *cmd, 217 enum virtio_gpu_ctrl_type type) 218 { 219 struct virtio_gpu_ctrl_hdr resp; 220 221 memset(&resp, 0, sizeof(resp)); 222 resp.type = type; 223 virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp)); 224 } 225 226 static void 227 virtio_gpu_fill_display_info(VirtIOGPU *g, 228 struct virtio_gpu_resp_display_info *dpy_info) 229 { 230 int i; 231 232 for (i = 0; i < g->conf.max_outputs; i++) { 233 if (g->enabled_output_bitmask & (1 << i)) { 234 dpy_info->pmodes[i].enabled = 1; 235 dpy_info->pmodes[i].r.width = g->req_state[i].width; 236 dpy_info->pmodes[i].r.height = g->req_state[i].height; 237 } 238 } 239 } 240 241 void virtio_gpu_get_display_info(VirtIOGPU *g, 242 struct virtio_gpu_ctrl_command *cmd) 243 { 244 struct virtio_gpu_resp_display_info display_info; 245 246 trace_virtio_gpu_cmd_get_display_info(); 247 memset(&display_info, 0, sizeof(display_info)); 248 display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO; 249 virtio_gpu_fill_display_info(g, &display_info); 250 virtio_gpu_ctrl_response(g, cmd, &display_info.hdr, 251 sizeof(display_info)); 252 } 253 254 static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format) 255 { 256 switch (virtio_gpu_format) { 257 #ifdef HOST_WORDS_BIGENDIAN 258 case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: 259 return PIXMAN_b8g8r8x8; 260 case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: 261 return PIXMAN_b8g8r8a8; 262 case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: 263 return PIXMAN_x8r8g8b8; 264 case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: 265 return PIXMAN_a8r8g8b8; 266 case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: 267 return PIXMAN_r8g8b8x8; 268 case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: 269 return PIXMAN_r8g8b8a8; 270 case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: 271 return PIXMAN_x8b8g8r8; 272 case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: 273 return PIXMAN_a8b8g8r8; 274 #else 275 case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: 276 return PIXMAN_x8r8g8b8; 277 case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: 278 return PIXMAN_a8r8g8b8; 279 case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: 280 return PIXMAN_b8g8r8x8; 281 case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: 282 return PIXMAN_b8g8r8a8; 283 case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: 284 return PIXMAN_x8b8g8r8; 285 case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: 286 return PIXMAN_a8b8g8r8; 287 case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: 288 return PIXMAN_r8g8b8x8; 289 case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: 290 return PIXMAN_r8g8b8a8; 291 #endif 292 default: 293 return 0; 294 } 295 } 296 297 static void virtio_gpu_resource_create_2d(VirtIOGPU *g, 298 struct virtio_gpu_ctrl_command *cmd) 299 { 300 pixman_format_code_t pformat; 301 struct virtio_gpu_simple_resource *res; 302 struct virtio_gpu_resource_create_2d c2d; 303 304 VIRTIO_GPU_FILL_CMD(c2d); 305 trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, 306 c2d.width, c2d.height); 307 308 if (c2d.resource_id == 0) { 309 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", 310 __func__); 311 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; 312 return; 313 } 314 315 res = virtio_gpu_find_resource(g, c2d.resource_id); 316 if (res) { 317 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", 318 __func__, c2d.resource_id); 319 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; 320 return; 321 } 322 323 res = g_new0(struct virtio_gpu_simple_resource, 1); 324 325 res->width = c2d.width; 326 res->height = c2d.height; 327 res->format = c2d.format; 328 res->resource_id = c2d.resource_id; 329 330 pformat = get_pixman_format(c2d.format); 331 if (!pformat) { 332 qemu_log_mask(LOG_GUEST_ERROR, 333 "%s: host couldn't handle guest format %d\n", 334 __func__, c2d.format); 335 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; 336 return; 337 } 338 res->image = pixman_image_create_bits(pformat, 339 c2d.width, 340 c2d.height, 341 NULL, 0); 342 343 if (!res->image) { 344 qemu_log_mask(LOG_GUEST_ERROR, 345 "%s: resource creation failed %d %d %d\n", 346 __func__, c2d.resource_id, c2d.width, c2d.height); 347 g_free(res); 348 cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; 349 return; 350 } 351 352 QTAILQ_INSERT_HEAD(&g->reslist, res, next); 353 } 354 355 static void virtio_gpu_resource_destroy(VirtIOGPU *g, 356 struct virtio_gpu_simple_resource *res) 357 { 358 pixman_image_unref(res->image); 359 QTAILQ_REMOVE(&g->reslist, res, next); 360 g_free(res); 361 } 362 363 static void virtio_gpu_resource_unref(VirtIOGPU *g, 364 struct virtio_gpu_ctrl_command *cmd) 365 { 366 struct virtio_gpu_simple_resource *res; 367 struct virtio_gpu_resource_unref unref; 368 369 VIRTIO_GPU_FILL_CMD(unref); 370 trace_virtio_gpu_cmd_res_unref(unref.resource_id); 371 372 res = virtio_gpu_find_resource(g, unref.resource_id); 373 if (!res) { 374 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", 375 __func__, unref.resource_id); 376 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; 377 return; 378 } 379 virtio_gpu_resource_destroy(g, res); 380 } 381 382 static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g, 383 struct virtio_gpu_ctrl_command *cmd) 384 { 385 struct virtio_gpu_simple_resource *res; 386 int h; 387 uint32_t src_offset, dst_offset, stride; 388 int bpp; 389 pixman_format_code_t format; 390 struct virtio_gpu_transfer_to_host_2d t2d; 391 392 VIRTIO_GPU_FILL_CMD(t2d); 393 trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id); 394 395 res = virtio_gpu_find_resource(g, t2d.resource_id); 396 if (!res || !res->iov) { 397 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", 398 __func__, t2d.resource_id); 399 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; 400 return; 401 } 402 403 if (t2d.r.x > res->width || 404 t2d.r.y > res->height || 405 t2d.r.width > res->width || 406 t2d.r.height > res->height || 407 t2d.r.x + t2d.r.width > res->width || 408 t2d.r.y + t2d.r.height > res->height) { 409 qemu_log_mask(LOG_GUEST_ERROR, "%s: transfer bounds outside resource" 410 " bounds for resource %d: %d %d %d %d vs %d %d\n", 411 __func__, t2d.resource_id, t2d.r.x, t2d.r.y, 412 t2d.r.width, t2d.r.height, res->width, res->height); 413 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; 414 return; 415 } 416 417 format = pixman_image_get_format(res->image); 418 bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8; 419 stride = pixman_image_get_stride(res->image); 420 421 if (t2d.offset || t2d.r.x || t2d.r.y || 422 t2d.r.width != pixman_image_get_width(res->image)) { 423 void *img_data = pixman_image_get_data(res->image); 424 for (h = 0; h < t2d.r.height; h++) { 425 src_offset = t2d.offset + stride * h; 426 dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp); 427 428 iov_to_buf(res->iov, res->iov_cnt, src_offset, 429 (uint8_t *)img_data 430 + dst_offset, t2d.r.width * bpp); 431 } 432 } else { 433 iov_to_buf(res->iov, res->iov_cnt, 0, 434 pixman_image_get_data(res->image), 435 pixman_image_get_stride(res->image) 436 * pixman_image_get_height(res->image)); 437 } 438 } 439 440 static void virtio_gpu_resource_flush(VirtIOGPU *g, 441 struct virtio_gpu_ctrl_command *cmd) 442 { 443 struct virtio_gpu_simple_resource *res; 444 struct virtio_gpu_resource_flush rf; 445 pixman_region16_t flush_region; 446 int i; 447 448 VIRTIO_GPU_FILL_CMD(rf); 449 trace_virtio_gpu_cmd_res_flush(rf.resource_id, 450 rf.r.width, rf.r.height, rf.r.x, rf.r.y); 451 452 res = virtio_gpu_find_resource(g, rf.resource_id); 453 if (!res) { 454 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", 455 __func__, rf.resource_id); 456 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; 457 return; 458 } 459 460 if (rf.r.x > res->width || 461 rf.r.y > res->height || 462 rf.r.width > res->width || 463 rf.r.height > res->height || 464 rf.r.x + rf.r.width > res->width || 465 rf.r.y + rf.r.height > res->height) { 466 qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside resource" 467 " bounds for resource %d: %d %d %d %d vs %d %d\n", 468 __func__, rf.resource_id, rf.r.x, rf.r.y, 469 rf.r.width, rf.r.height, res->width, res->height); 470 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; 471 return; 472 } 473 474 pixman_region_init_rect(&flush_region, 475 rf.r.x, rf.r.y, rf.r.width, rf.r.height); 476 for (i = 0; i < g->conf.max_outputs; i++) { 477 struct virtio_gpu_scanout *scanout; 478 pixman_region16_t region, finalregion; 479 pixman_box16_t *extents; 480 481 if (!(res->scanout_bitmask & (1 << i))) { 482 continue; 483 } 484 scanout = &g->scanout[i]; 485 486 pixman_region_init(&finalregion); 487 pixman_region_init_rect(®ion, scanout->x, scanout->y, 488 scanout->width, scanout->height); 489 490 pixman_region_intersect(&finalregion, &flush_region, ®ion); 491 pixman_region_translate(&finalregion, -scanout->x, -scanout->y); 492 extents = pixman_region_extents(&finalregion); 493 /* work out the area we need to update for each console */ 494 dpy_gfx_update(g->scanout[i].con, 495 extents->x1, extents->y1, 496 extents->x2 - extents->x1, 497 extents->y2 - extents->y1); 498 499 pixman_region_fini(®ion); 500 pixman_region_fini(&finalregion); 501 } 502 pixman_region_fini(&flush_region); 503 } 504 505 static void virtio_unref_resource(pixman_image_t *image, void *data) 506 { 507 pixman_image_unref(data); 508 } 509 510 static void virtio_gpu_set_scanout(VirtIOGPU *g, 511 struct virtio_gpu_ctrl_command *cmd) 512 { 513 struct virtio_gpu_simple_resource *res; 514 struct virtio_gpu_scanout *scanout; 515 pixman_format_code_t format; 516 uint32_t offset; 517 int bpp; 518 struct virtio_gpu_set_scanout ss; 519 520 VIRTIO_GPU_FILL_CMD(ss); 521 trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, 522 ss.r.width, ss.r.height, ss.r.x, ss.r.y); 523 524 if (ss.scanout_id >= g->conf.max_outputs) { 525 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", 526 __func__, ss.scanout_id); 527 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; 528 return; 529 } 530 531 g->enable = 1; 532 if (ss.resource_id == 0) { 533 scanout = &g->scanout[ss.scanout_id]; 534 if (scanout->resource_id) { 535 res = virtio_gpu_find_resource(g, scanout->resource_id); 536 if (res) { 537 res->scanout_bitmask &= ~(1 << ss.scanout_id); 538 } 539 } 540 if (ss.scanout_id == 0) { 541 qemu_log_mask(LOG_GUEST_ERROR, 542 "%s: illegal scanout id specified %d", 543 __func__, ss.scanout_id); 544 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; 545 return; 546 } 547 dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL); 548 scanout->ds = NULL; 549 scanout->width = 0; 550 scanout->height = 0; 551 return; 552 } 553 554 /* create a surface for this scanout */ 555 res = virtio_gpu_find_resource(g, ss.resource_id); 556 if (!res) { 557 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", 558 __func__, ss.resource_id); 559 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; 560 return; 561 } 562 563 if (ss.r.x > res->width || 564 ss.r.y > res->height || 565 ss.r.width > res->width || 566 ss.r.height > res->height || 567 ss.r.x + ss.r.width > res->width || 568 ss.r.y + ss.r.height > res->height) { 569 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for" 570 " resource %d, (%d,%d)+%d,%d vs %d %d\n", 571 __func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y, 572 ss.r.width, ss.r.height, res->width, res->height); 573 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; 574 return; 575 } 576 577 scanout = &g->scanout[ss.scanout_id]; 578 579 format = pixman_image_get_format(res->image); 580 bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8; 581 offset = (ss.r.x * bpp) + ss.r.y * pixman_image_get_stride(res->image); 582 if (!scanout->ds || surface_data(scanout->ds) 583 != ((uint8_t *)pixman_image_get_data(res->image) + offset) || 584 scanout->width != ss.r.width || 585 scanout->height != ss.r.height) { 586 pixman_image_t *rect; 587 void *ptr = (uint8_t *)pixman_image_get_data(res->image) + offset; 588 rect = pixman_image_create_bits(format, ss.r.width, ss.r.height, ptr, 589 pixman_image_get_stride(res->image)); 590 pixman_image_ref(res->image); 591 pixman_image_set_destroy_function(rect, virtio_unref_resource, 592 res->image); 593 /* realloc the surface ptr */ 594 scanout->ds = qemu_create_displaysurface_pixman(rect); 595 if (!scanout->ds) { 596 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; 597 return; 598 } 599 dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds); 600 } 601 602 res->scanout_bitmask |= (1 << ss.scanout_id); 603 scanout->resource_id = ss.resource_id; 604 scanout->x = ss.r.x; 605 scanout->y = ss.r.y; 606 scanout->width = ss.r.width; 607 scanout->height = ss.r.height; 608 } 609 610 int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, 611 struct virtio_gpu_ctrl_command *cmd, 612 uint64_t **addr, struct iovec **iov) 613 { 614 struct virtio_gpu_mem_entry *ents; 615 size_t esize, s; 616 int i; 617 618 if (ab->nr_entries > 16384) { 619 qemu_log_mask(LOG_GUEST_ERROR, 620 "%s: nr_entries is too big (%d > 16384)\n", 621 __func__, ab->nr_entries); 622 return -1; 623 } 624 625 esize = sizeof(*ents) * ab->nr_entries; 626 ents = g_malloc(esize); 627 s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 628 sizeof(*ab), ents, esize); 629 if (s != esize) { 630 qemu_log_mask(LOG_GUEST_ERROR, 631 "%s: command data size incorrect %zu vs %zu\n", 632 __func__, s, esize); 633 g_free(ents); 634 return -1; 635 } 636 637 *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries); 638 if (addr) { 639 *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries); 640 } 641 for (i = 0; i < ab->nr_entries; i++) { 642 hwaddr len = ents[i].length; 643 (*iov)[i].iov_len = ents[i].length; 644 (*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1); 645 if (addr) { 646 (*addr)[i] = ents[i].addr; 647 } 648 if (!(*iov)[i].iov_base || len != ents[i].length) { 649 qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" 650 " resource %d element %d\n", 651 __func__, ab->resource_id, i); 652 virtio_gpu_cleanup_mapping_iov(*iov, i); 653 g_free(ents); 654 *iov = NULL; 655 if (addr) { 656 g_free(*addr); 657 *addr = NULL; 658 } 659 return -1; 660 } 661 } 662 g_free(ents); 663 return 0; 664 } 665 666 void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count) 667 { 668 int i; 669 670 for (i = 0; i < count; i++) { 671 cpu_physical_memory_unmap(iov[i].iov_base, iov[i].iov_len, 1, 672 iov[i].iov_len); 673 } 674 g_free(iov); 675 } 676 677 static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res) 678 { 679 virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt); 680 res->iov = NULL; 681 res->iov_cnt = 0; 682 g_free(res->addrs); 683 res->addrs = NULL; 684 } 685 686 static void 687 virtio_gpu_resource_attach_backing(VirtIOGPU *g, 688 struct virtio_gpu_ctrl_command *cmd) 689 { 690 struct virtio_gpu_simple_resource *res; 691 struct virtio_gpu_resource_attach_backing ab; 692 int ret; 693 694 VIRTIO_GPU_FILL_CMD(ab); 695 trace_virtio_gpu_cmd_res_back_attach(ab.resource_id); 696 697 res = virtio_gpu_find_resource(g, ab.resource_id); 698 if (!res) { 699 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", 700 __func__, ab.resource_id); 701 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; 702 return; 703 } 704 705 ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->addrs, &res->iov); 706 if (ret != 0) { 707 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; 708 return; 709 } 710 711 res->iov_cnt = ab.nr_entries; 712 } 713 714 static void 715 virtio_gpu_resource_detach_backing(VirtIOGPU *g, 716 struct virtio_gpu_ctrl_command *cmd) 717 { 718 struct virtio_gpu_simple_resource *res; 719 struct virtio_gpu_resource_detach_backing detach; 720 721 VIRTIO_GPU_FILL_CMD(detach); 722 trace_virtio_gpu_cmd_res_back_detach(detach.resource_id); 723 724 res = virtio_gpu_find_resource(g, detach.resource_id); 725 if (!res || !res->iov) { 726 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", 727 __func__, detach.resource_id); 728 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; 729 return; 730 } 731 virtio_gpu_cleanup_mapping(res); 732 } 733 734 static void virtio_gpu_simple_process_cmd(VirtIOGPU *g, 735 struct virtio_gpu_ctrl_command *cmd) 736 { 737 VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); 738 739 switch (cmd->cmd_hdr.type) { 740 case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: 741 virtio_gpu_get_display_info(g, cmd); 742 break; 743 case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: 744 virtio_gpu_resource_create_2d(g, cmd); 745 break; 746 case VIRTIO_GPU_CMD_RESOURCE_UNREF: 747 virtio_gpu_resource_unref(g, cmd); 748 break; 749 case VIRTIO_GPU_CMD_RESOURCE_FLUSH: 750 virtio_gpu_resource_flush(g, cmd); 751 break; 752 case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: 753 virtio_gpu_transfer_to_host_2d(g, cmd); 754 break; 755 case VIRTIO_GPU_CMD_SET_SCANOUT: 756 virtio_gpu_set_scanout(g, cmd); 757 break; 758 case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: 759 virtio_gpu_resource_attach_backing(g, cmd); 760 break; 761 case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: 762 virtio_gpu_resource_detach_backing(g, cmd); 763 break; 764 default: 765 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; 766 break; 767 } 768 if (!cmd->finished) { 769 virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error : 770 VIRTIO_GPU_RESP_OK_NODATA); 771 } 772 } 773 774 static void virtio_gpu_handle_ctrl_cb(VirtIODevice *vdev, VirtQueue *vq) 775 { 776 VirtIOGPU *g = VIRTIO_GPU(vdev); 777 qemu_bh_schedule(g->ctrl_bh); 778 } 779 780 static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq) 781 { 782 VirtIOGPU *g = VIRTIO_GPU(vdev); 783 qemu_bh_schedule(g->cursor_bh); 784 } 785 786 void virtio_gpu_process_cmdq(VirtIOGPU *g) 787 { 788 struct virtio_gpu_ctrl_command *cmd; 789 790 while (!QTAILQ_EMPTY(&g->cmdq)) { 791 cmd = QTAILQ_FIRST(&g->cmdq); 792 793 /* process command */ 794 VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd, 795 g, cmd); 796 if (cmd->waiting) { 797 break; 798 } 799 QTAILQ_REMOVE(&g->cmdq, cmd, next); 800 if (virtio_gpu_stats_enabled(g->conf)) { 801 g->stats.requests++; 802 } 803 804 if (!cmd->finished) { 805 QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next); 806 g->inflight++; 807 if (virtio_gpu_stats_enabled(g->conf)) { 808 if (g->stats.max_inflight < g->inflight) { 809 g->stats.max_inflight = g->inflight; 810 } 811 fprintf(stderr, "inflight: %3d (+)\r", g->inflight); 812 } 813 } else { 814 g_free(cmd); 815 } 816 } 817 } 818 819 static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) 820 { 821 VirtIOGPU *g = VIRTIO_GPU(vdev); 822 struct virtio_gpu_ctrl_command *cmd; 823 824 if (!virtio_queue_ready(vq)) { 825 return; 826 } 827 828 #ifdef CONFIG_VIRGL 829 if (!g->renderer_inited && g->use_virgl_renderer) { 830 virtio_gpu_virgl_init(g); 831 g->renderer_inited = true; 832 } 833 #endif 834 835 cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); 836 while (cmd) { 837 cmd->vq = vq; 838 cmd->error = 0; 839 cmd->finished = false; 840 cmd->waiting = false; 841 QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); 842 cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); 843 } 844 845 virtio_gpu_process_cmdq(g); 846 847 #ifdef CONFIG_VIRGL 848 if (g->use_virgl_renderer) { 849 virtio_gpu_virgl_fence_poll(g); 850 } 851 #endif 852 } 853 854 static void virtio_gpu_ctrl_bh(void *opaque) 855 { 856 VirtIOGPU *g = opaque; 857 virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq); 858 } 859 860 static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) 861 { 862 VirtIOGPU *g = VIRTIO_GPU(vdev); 863 VirtQueueElement *elem; 864 size_t s; 865 struct virtio_gpu_update_cursor cursor_info; 866 867 if (!virtio_queue_ready(vq)) { 868 return; 869 } 870 for (;;) { 871 elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 872 if (!elem) { 873 break; 874 } 875 876 s = iov_to_buf(elem->out_sg, elem->out_num, 0, 877 &cursor_info, sizeof(cursor_info)); 878 if (s != sizeof(cursor_info)) { 879 qemu_log_mask(LOG_GUEST_ERROR, 880 "%s: cursor size incorrect %zu vs %zu\n", 881 __func__, s, sizeof(cursor_info)); 882 } else { 883 update_cursor(g, &cursor_info); 884 } 885 virtqueue_push(vq, elem, 0); 886 virtio_notify(vdev, vq); 887 g_free(elem); 888 } 889 } 890 891 static void virtio_gpu_cursor_bh(void *opaque) 892 { 893 VirtIOGPU *g = opaque; 894 virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq); 895 } 896 897 static void virtio_gpu_invalidate_display(void *opaque) 898 { 899 } 900 901 static void virtio_gpu_update_display(void *opaque) 902 { 903 } 904 905 static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata) 906 { 907 } 908 909 static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) 910 { 911 VirtIOGPU *g = opaque; 912 913 if (idx >= g->conf.max_outputs) { 914 return -1; 915 } 916 917 g->req_state[idx].x = info->xoff; 918 g->req_state[idx].y = info->yoff; 919 g->req_state[idx].width = info->width; 920 g->req_state[idx].height = info->height; 921 922 if (info->width && info->height) { 923 g->enabled_output_bitmask |= (1 << idx); 924 } else { 925 g->enabled_output_bitmask &= ~(1 << idx); 926 } 927 928 /* send event to guest */ 929 virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); 930 return 0; 931 } 932 933 static void virtio_gpu_gl_block(void *opaque, bool block) 934 { 935 VirtIOGPU *g = opaque; 936 937 if (block) { 938 g->renderer_blocked++; 939 } else { 940 g->renderer_blocked--; 941 } 942 assert(g->renderer_blocked >= 0); 943 944 if (g->renderer_blocked == 0) { 945 virtio_gpu_process_cmdq(g); 946 } 947 } 948 949 const GraphicHwOps virtio_gpu_ops = { 950 .invalidate = virtio_gpu_invalidate_display, 951 .gfx_update = virtio_gpu_update_display, 952 .text_update = virtio_gpu_text_update, 953 .ui_info = virtio_gpu_ui_info, 954 .gl_block = virtio_gpu_gl_block, 955 }; 956 957 static const VMStateDescription vmstate_virtio_gpu_scanout = { 958 .name = "virtio-gpu-one-scanout", 959 .version_id = 1, 960 .fields = (VMStateField[]) { 961 VMSTATE_UINT32(resource_id, struct virtio_gpu_scanout), 962 VMSTATE_UINT32(width, struct virtio_gpu_scanout), 963 VMSTATE_UINT32(height, struct virtio_gpu_scanout), 964 VMSTATE_INT32(x, struct virtio_gpu_scanout), 965 VMSTATE_INT32(y, struct virtio_gpu_scanout), 966 VMSTATE_UINT32(cursor.resource_id, struct virtio_gpu_scanout), 967 VMSTATE_UINT32(cursor.hot_x, struct virtio_gpu_scanout), 968 VMSTATE_UINT32(cursor.hot_y, struct virtio_gpu_scanout), 969 VMSTATE_UINT32(cursor.pos.x, struct virtio_gpu_scanout), 970 VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout), 971 VMSTATE_END_OF_LIST() 972 }, 973 }; 974 975 static const VMStateDescription vmstate_virtio_gpu_scanouts = { 976 .name = "virtio-gpu-scanouts", 977 .version_id = 1, 978 .fields = (VMStateField[]) { 979 VMSTATE_INT32(enable, struct VirtIOGPU), 980 VMSTATE_UINT32_EQUAL(conf.max_outputs, struct VirtIOGPU), 981 VMSTATE_STRUCT_VARRAY_UINT32(scanout, struct VirtIOGPU, 982 conf.max_outputs, 1, 983 vmstate_virtio_gpu_scanout, 984 struct virtio_gpu_scanout), 985 VMSTATE_END_OF_LIST() 986 }, 987 }; 988 989 static const VMStateDescription vmstate_virtio_gpu_unmigratable = { 990 .name = "virtio-gpu-with-virgl", 991 .unmigratable = 1, 992 }; 993 994 static void virtio_gpu_save(QEMUFile *f, void *opaque) 995 { 996 VirtIOGPU *g = opaque; 997 VirtIODevice *vdev = VIRTIO_DEVICE(g); 998 struct virtio_gpu_simple_resource *res; 999 int i; 1000 1001 virtio_save(vdev, f); 1002 1003 /* in 2d mode we should never find unprocessed commands here */ 1004 assert(QTAILQ_EMPTY(&g->cmdq)); 1005 1006 QTAILQ_FOREACH(res, &g->reslist, next) { 1007 qemu_put_be32(f, res->resource_id); 1008 qemu_put_be32(f, res->width); 1009 qemu_put_be32(f, res->height); 1010 qemu_put_be32(f, res->format); 1011 qemu_put_be32(f, res->iov_cnt); 1012 for (i = 0; i < res->iov_cnt; i++) { 1013 qemu_put_be64(f, res->addrs[i]); 1014 qemu_put_be32(f, res->iov[i].iov_len); 1015 } 1016 qemu_put_buffer(f, (void *)pixman_image_get_data(res->image), 1017 pixman_image_get_stride(res->image) * res->height); 1018 } 1019 qemu_put_be32(f, 0); /* end of list */ 1020 1021 vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL); 1022 } 1023 1024 static int virtio_gpu_load(QEMUFile *f, void *opaque, int version_id) 1025 { 1026 VirtIOGPU *g = opaque; 1027 VirtIODevice *vdev = VIRTIO_DEVICE(g); 1028 struct virtio_gpu_simple_resource *res; 1029 struct virtio_gpu_scanout *scanout; 1030 uint32_t resource_id, pformat; 1031 int i, ret; 1032 1033 if (version_id != VIRTIO_GPU_VM_VERSION) { 1034 return -EINVAL; 1035 } 1036 1037 ret = virtio_load(vdev, f, version_id); 1038 if (ret) { 1039 return ret; 1040 } 1041 1042 resource_id = qemu_get_be32(f); 1043 while (resource_id != 0) { 1044 res = g_new0(struct virtio_gpu_simple_resource, 1); 1045 res->resource_id = resource_id; 1046 res->width = qemu_get_be32(f); 1047 res->height = qemu_get_be32(f); 1048 res->format = qemu_get_be32(f); 1049 res->iov_cnt = qemu_get_be32(f); 1050 1051 /* allocate */ 1052 pformat = get_pixman_format(res->format); 1053 if (!pformat) { 1054 return -EINVAL; 1055 } 1056 res->image = pixman_image_create_bits(pformat, 1057 res->width, res->height, 1058 NULL, 0); 1059 if (!res->image) { 1060 return -EINVAL; 1061 } 1062 1063 res->addrs = g_new(uint64_t, res->iov_cnt); 1064 res->iov = g_new(struct iovec, res->iov_cnt); 1065 1066 /* read data */ 1067 for (i = 0; i < res->iov_cnt; i++) { 1068 res->addrs[i] = qemu_get_be64(f); 1069 res->iov[i].iov_len = qemu_get_be32(f); 1070 } 1071 qemu_get_buffer(f, (void *)pixman_image_get_data(res->image), 1072 pixman_image_get_stride(res->image) * res->height); 1073 1074 /* restore mapping */ 1075 for (i = 0; i < res->iov_cnt; i++) { 1076 hwaddr len = res->iov[i].iov_len; 1077 res->iov[i].iov_base = 1078 cpu_physical_memory_map(res->addrs[i], &len, 1); 1079 if (!res->iov[i].iov_base || len != res->iov[i].iov_len) { 1080 return -EINVAL; 1081 } 1082 } 1083 1084 QTAILQ_INSERT_HEAD(&g->reslist, res, next); 1085 1086 resource_id = qemu_get_be32(f); 1087 } 1088 1089 /* load & apply scanout state */ 1090 vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1); 1091 for (i = 0; i < g->conf.max_outputs; i++) { 1092 scanout = &g->scanout[i]; 1093 if (!scanout->resource_id) { 1094 continue; 1095 } 1096 res = virtio_gpu_find_resource(g, scanout->resource_id); 1097 if (!res) { 1098 return -EINVAL; 1099 } 1100 scanout->ds = qemu_create_displaysurface_pixman(res->image); 1101 if (!scanout->ds) { 1102 return -EINVAL; 1103 } 1104 1105 dpy_gfx_replace_surface(scanout->con, scanout->ds); 1106 dpy_gfx_update(scanout->con, 0, 0, scanout->width, scanout->height); 1107 update_cursor(g, &scanout->cursor); 1108 res->scanout_bitmask |= (1 << i); 1109 } 1110 1111 return 0; 1112 } 1113 1114 static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) 1115 { 1116 VirtIODevice *vdev = VIRTIO_DEVICE(qdev); 1117 VirtIOGPU *g = VIRTIO_GPU(qdev); 1118 bool have_virgl; 1119 int i; 1120 1121 if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { 1122 error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS); 1123 return; 1124 } 1125 1126 g->config_size = sizeof(struct virtio_gpu_config); 1127 g->virtio_config.num_scanouts = g->conf.max_outputs; 1128 virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, 1129 g->config_size); 1130 1131 g->req_state[0].width = 1024; 1132 g->req_state[0].height = 768; 1133 1134 g->use_virgl_renderer = false; 1135 #if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN) 1136 have_virgl = false; 1137 #else 1138 have_virgl = display_opengl; 1139 #endif 1140 if (!have_virgl) { 1141 g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); 1142 } 1143 1144 if (virtio_gpu_virgl_enabled(g->conf)) { 1145 /* use larger control queue in 3d mode */ 1146 g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb); 1147 g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb); 1148 g->virtio_config.num_capsets = 1; 1149 } else { 1150 g->ctrl_vq = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb); 1151 g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb); 1152 } 1153 1154 g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g); 1155 g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g); 1156 QTAILQ_INIT(&g->reslist); 1157 QTAILQ_INIT(&g->cmdq); 1158 QTAILQ_INIT(&g->fenceq); 1159 1160 g->enabled_output_bitmask = 1; 1161 g->qdev = qdev; 1162 1163 for (i = 0; i < g->conf.max_outputs; i++) { 1164 g->scanout[i].con = 1165 graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); 1166 if (i > 0) { 1167 dpy_gfx_replace_surface(g->scanout[i].con, NULL); 1168 } 1169 } 1170 1171 if (virtio_gpu_virgl_enabled(g->conf)) { 1172 vmstate_register(qdev, -1, &vmstate_virtio_gpu_unmigratable, g); 1173 } else { 1174 register_savevm(qdev, "virtio-gpu", -1, VIRTIO_GPU_VM_VERSION, 1175 virtio_gpu_save, virtio_gpu_load, g); 1176 } 1177 } 1178 1179 static void virtio_gpu_instance_init(Object *obj) 1180 { 1181 } 1182 1183 static void virtio_gpu_reset(VirtIODevice *vdev) 1184 { 1185 VirtIOGPU *g = VIRTIO_GPU(vdev); 1186 struct virtio_gpu_simple_resource *res, *tmp; 1187 int i; 1188 1189 g->enable = 0; 1190 1191 QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { 1192 virtio_gpu_resource_destroy(g, res); 1193 } 1194 for (i = 0; i < g->conf.max_outputs; i++) { 1195 #if 0 1196 g->req_state[i].x = 0; 1197 g->req_state[i].y = 0; 1198 if (i == 0) { 1199 g->req_state[0].width = 1024; 1200 g->req_state[0].height = 768; 1201 } else { 1202 g->req_state[i].width = 0; 1203 g->req_state[i].height = 0; 1204 } 1205 #endif 1206 g->scanout[i].resource_id = 0; 1207 g->scanout[i].width = 0; 1208 g->scanout[i].height = 0; 1209 g->scanout[i].x = 0; 1210 g->scanout[i].y = 0; 1211 g->scanout[i].ds = NULL; 1212 } 1213 g->enabled_output_bitmask = 1; 1214 1215 #ifdef CONFIG_VIRGL 1216 if (g->use_virgl_renderer) { 1217 virtio_gpu_virgl_reset(g); 1218 g->use_virgl_renderer = 0; 1219 } 1220 #endif 1221 } 1222 1223 static Property virtio_gpu_properties[] = { 1224 DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1), 1225 #ifdef CONFIG_VIRGL 1226 DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags, 1227 VIRTIO_GPU_FLAG_VIRGL_ENABLED, true), 1228 DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags, 1229 VIRTIO_GPU_FLAG_STATS_ENABLED, false), 1230 #endif 1231 DEFINE_PROP_END_OF_LIST(), 1232 }; 1233 1234 static void virtio_gpu_class_init(ObjectClass *klass, void *data) 1235 { 1236 DeviceClass *dc = DEVICE_CLASS(klass); 1237 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 1238 1239 vdc->realize = virtio_gpu_device_realize; 1240 vdc->get_config = virtio_gpu_get_config; 1241 vdc->set_config = virtio_gpu_set_config; 1242 vdc->get_features = virtio_gpu_get_features; 1243 vdc->set_features = virtio_gpu_set_features; 1244 1245 vdc->reset = virtio_gpu_reset; 1246 1247 dc->props = virtio_gpu_properties; 1248 } 1249 1250 static const TypeInfo virtio_gpu_info = { 1251 .name = TYPE_VIRTIO_GPU, 1252 .parent = TYPE_VIRTIO_DEVICE, 1253 .instance_size = sizeof(VirtIOGPU), 1254 .instance_init = virtio_gpu_instance_init, 1255 .class_init = virtio_gpu_class_init, 1256 }; 1257 1258 static void virtio_register_types(void) 1259 { 1260 type_register_static(&virtio_gpu_info); 1261 } 1262 1263 type_init(virtio_register_types) 1264 1265 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24); 1266 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56); 1267 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32); 1268 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40); 1269 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48); 1270 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48); 1271 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56); 1272 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16); 1273 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32); 1274 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32); 1275 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408); 1276 1277 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72); 1278 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72); 1279 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96); 1280 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24); 1281 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32); 1282 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32); 1283 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32); 1284 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40); 1285 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32); 1286 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24); 1287