150d8e25eSMarc-André Lureau /* 250d8e25eSMarc-André Lureau * Virtio GPU Device 350d8e25eSMarc-André Lureau * 450d8e25eSMarc-André Lureau * Copyright Red Hat, Inc. 2013-2014 550d8e25eSMarc-André Lureau * 650d8e25eSMarc-André Lureau * Authors: 750d8e25eSMarc-André Lureau * Dave Airlie <airlied@redhat.com> 850d8e25eSMarc-André Lureau * Gerd Hoffmann <kraxel@redhat.com> 950d8e25eSMarc-André Lureau * 1050d8e25eSMarc-André Lureau * This work is licensed under the terms of the GNU GPL, version 2 or later. 1150d8e25eSMarc-André Lureau * See the COPYING file in the top-level directory. 1250d8e25eSMarc-André Lureau */ 1350d8e25eSMarc-André Lureau 1450d8e25eSMarc-André Lureau #include "qemu/osdep.h" 1550d8e25eSMarc-André Lureau 1650d8e25eSMarc-André Lureau #include "hw/virtio/virtio-gpu.h" 1750d8e25eSMarc-André Lureau #include "migration/blocker.h" 1850d8e25eSMarc-André Lureau #include "qapi/error.h" 1950d8e25eSMarc-André Lureau #include "qemu/error-report.h" 2050d8e25eSMarc-André Lureau #include "trace.h" 2150d8e25eSMarc-André Lureau 2250d8e25eSMarc-André Lureau void 2350d8e25eSMarc-André Lureau virtio_gpu_base_reset(VirtIOGPUBase *g) 2450d8e25eSMarc-André Lureau { 2550d8e25eSMarc-André Lureau int i; 2650d8e25eSMarc-André Lureau 2750d8e25eSMarc-André Lureau g->enable = 0; 2850d8e25eSMarc-André Lureau 2950d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 3050d8e25eSMarc-André Lureau g->scanout[i].resource_id = 0; 3150d8e25eSMarc-André Lureau g->scanout[i].width = 0; 3250d8e25eSMarc-André Lureau g->scanout[i].height = 0; 3350d8e25eSMarc-André Lureau g->scanout[i].x = 0; 3450d8e25eSMarc-André Lureau g->scanout[i].y = 0; 3550d8e25eSMarc-André Lureau g->scanout[i].ds = NULL; 3650d8e25eSMarc-André Lureau } 3750d8e25eSMarc-André Lureau } 3850d8e25eSMarc-André Lureau 3950d8e25eSMarc-André Lureau void 4050d8e25eSMarc-André Lureau virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, 4150d8e25eSMarc-André Lureau struct virtio_gpu_resp_display_info *dpy_info) 4250d8e25eSMarc-André Lureau { 4350d8e25eSMarc-André Lureau int i; 4450d8e25eSMarc-André Lureau 4550d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 4650d8e25eSMarc-André Lureau if (g->enabled_output_bitmask & (1 << i)) { 4750d8e25eSMarc-André Lureau dpy_info->pmodes[i].enabled = 1; 4850d8e25eSMarc-André Lureau dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); 4950d8e25eSMarc-André Lureau dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); 5050d8e25eSMarc-André Lureau } 5150d8e25eSMarc-André Lureau } 5250d8e25eSMarc-André Lureau } 5350d8e25eSMarc-André Lureau 5450d8e25eSMarc-André Lureau static void virtio_gpu_invalidate_display(void *opaque) 5550d8e25eSMarc-André Lureau { 5650d8e25eSMarc-André Lureau } 5750d8e25eSMarc-André Lureau 5850d8e25eSMarc-André Lureau static void virtio_gpu_update_display(void *opaque) 5950d8e25eSMarc-André Lureau { 6050d8e25eSMarc-André Lureau } 6150d8e25eSMarc-André Lureau 6250d8e25eSMarc-André Lureau static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata) 6350d8e25eSMarc-André Lureau { 6450d8e25eSMarc-André Lureau } 6550d8e25eSMarc-André Lureau 6650d8e25eSMarc-André Lureau static void virtio_gpu_notify_event(VirtIOGPUBase *g, uint32_t event_type) 6750d8e25eSMarc-André Lureau { 6850d8e25eSMarc-André Lureau g->virtio_config.events_read |= event_type; 6950d8e25eSMarc-André Lureau virtio_notify_config(&g->parent_obj); 7050d8e25eSMarc-André Lureau } 7150d8e25eSMarc-André Lureau 72362239c0SAkihiko Odaki static void virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) 7350d8e25eSMarc-André Lureau { 7450d8e25eSMarc-André Lureau VirtIOGPUBase *g = opaque; 7550d8e25eSMarc-André Lureau 7650d8e25eSMarc-André Lureau if (idx >= g->conf.max_outputs) { 77362239c0SAkihiko Odaki return; 7850d8e25eSMarc-André Lureau } 7950d8e25eSMarc-André Lureau 8050d8e25eSMarc-André Lureau g->req_state[idx].x = info->xoff; 8150d8e25eSMarc-André Lureau g->req_state[idx].y = info->yoff; 82*b95b5631SAkihiko Odaki g->req_state[idx].refresh_rate = info->refresh_rate; 8350d8e25eSMarc-André Lureau g->req_state[idx].width = info->width; 8450d8e25eSMarc-André Lureau g->req_state[idx].height = info->height; 854bf47f36SMarc-André Lureau g->req_state[idx].width_mm = info->width_mm; 864bf47f36SMarc-André Lureau g->req_state[idx].height_mm = info->height_mm; 8750d8e25eSMarc-André Lureau 8850d8e25eSMarc-André Lureau if (info->width && info->height) { 8950d8e25eSMarc-André Lureau g->enabled_output_bitmask |= (1 << idx); 9050d8e25eSMarc-André Lureau } else { 9150d8e25eSMarc-André Lureau g->enabled_output_bitmask &= ~(1 << idx); 9250d8e25eSMarc-André Lureau } 9350d8e25eSMarc-André Lureau 9450d8e25eSMarc-André Lureau /* send event to guest */ 9550d8e25eSMarc-André Lureau virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); 96362239c0SAkihiko Odaki return; 9750d8e25eSMarc-André Lureau } 9850d8e25eSMarc-André Lureau 9950d8e25eSMarc-André Lureau static void 1003cddb8b9SMarc-André Lureau virtio_gpu_gl_flushed(void *opaque) 10150d8e25eSMarc-André Lureau { 10250d8e25eSMarc-André Lureau VirtIOGPUBase *g = opaque; 10350d8e25eSMarc-André Lureau VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_GET_CLASS(g); 10450d8e25eSMarc-André Lureau 1053cddb8b9SMarc-André Lureau if (vgc->gl_flushed) { 1063cddb8b9SMarc-André Lureau vgc->gl_flushed(g); 1073cddb8b9SMarc-André Lureau } 1083cddb8b9SMarc-André Lureau } 1093cddb8b9SMarc-André Lureau 1103cddb8b9SMarc-André Lureau static void 1113cddb8b9SMarc-André Lureau virtio_gpu_gl_block(void *opaque, bool block) 1123cddb8b9SMarc-André Lureau { 1133cddb8b9SMarc-André Lureau VirtIOGPUBase *g = opaque; 1143cddb8b9SMarc-André Lureau 11550d8e25eSMarc-André Lureau if (block) { 11650d8e25eSMarc-André Lureau g->renderer_blocked++; 11750d8e25eSMarc-André Lureau } else { 11850d8e25eSMarc-André Lureau g->renderer_blocked--; 11950d8e25eSMarc-André Lureau } 12050d8e25eSMarc-André Lureau assert(g->renderer_blocked >= 0); 121f6413cbfSMarc-André Lureau 122f6413cbfSMarc-André Lureau if (!block && g->renderer_blocked == 0) { 123f6413cbfSMarc-André Lureau virtio_gpu_gl_flushed(g); 124f6413cbfSMarc-André Lureau } 12550d8e25eSMarc-André Lureau } 12650d8e25eSMarc-André Lureau 127a7dfbe28SMarc-André Lureau static int 128a7dfbe28SMarc-André Lureau virtio_gpu_get_flags(void *opaque) 129a7dfbe28SMarc-André Lureau { 130a7dfbe28SMarc-André Lureau VirtIOGPUBase *g = opaque; 131a7dfbe28SMarc-André Lureau int flags = GRAPHIC_FLAGS_NONE; 132a7dfbe28SMarc-André Lureau 133a7dfbe28SMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 134a7dfbe28SMarc-André Lureau flags |= GRAPHIC_FLAGS_GL; 135a7dfbe28SMarc-André Lureau } 136a7dfbe28SMarc-André Lureau 137a7dfbe28SMarc-André Lureau if (virtio_gpu_dmabuf_enabled(g->conf)) { 138a7dfbe28SMarc-André Lureau flags |= GRAPHIC_FLAGS_DMABUF; 139a7dfbe28SMarc-André Lureau } 140a7dfbe28SMarc-André Lureau 141a7dfbe28SMarc-André Lureau return flags; 142a7dfbe28SMarc-André Lureau } 143a7dfbe28SMarc-André Lureau 1443b593b3fSGerd Hoffmann static const GraphicHwOps virtio_gpu_ops = { 145a7dfbe28SMarc-André Lureau .get_flags = virtio_gpu_get_flags, 14650d8e25eSMarc-André Lureau .invalidate = virtio_gpu_invalidate_display, 14750d8e25eSMarc-André Lureau .gfx_update = virtio_gpu_update_display, 14850d8e25eSMarc-André Lureau .text_update = virtio_gpu_text_update, 14950d8e25eSMarc-André Lureau .ui_info = virtio_gpu_ui_info, 15050d8e25eSMarc-André Lureau .gl_block = virtio_gpu_gl_block, 15150d8e25eSMarc-André Lureau }; 15250d8e25eSMarc-André Lureau 15350d8e25eSMarc-André Lureau bool 15450d8e25eSMarc-André Lureau virtio_gpu_base_device_realize(DeviceState *qdev, 15550d8e25eSMarc-André Lureau VirtIOHandleOutput ctrl_cb, 15650d8e25eSMarc-André Lureau VirtIOHandleOutput cursor_cb, 15750d8e25eSMarc-André Lureau Error **errp) 15850d8e25eSMarc-André Lureau { 15950d8e25eSMarc-André Lureau VirtIODevice *vdev = VIRTIO_DEVICE(qdev); 16050d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); 16150d8e25eSMarc-André Lureau int i; 16250d8e25eSMarc-André Lureau 16350d8e25eSMarc-André Lureau if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { 16450d8e25eSMarc-André Lureau error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS); 16550d8e25eSMarc-André Lureau return false; 16650d8e25eSMarc-André Lureau } 16750d8e25eSMarc-André Lureau 16850d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 16950d8e25eSMarc-André Lureau error_setg(&g->migration_blocker, "virgl is not yet migratable"); 170386f6c07SMarkus Armbruster if (migrate_add_blocker(g->migration_blocker, errp) < 0) { 17150d8e25eSMarc-André Lureau error_free(g->migration_blocker); 17250d8e25eSMarc-André Lureau return false; 17350d8e25eSMarc-André Lureau } 17450d8e25eSMarc-André Lureau } 17550d8e25eSMarc-André Lureau 17650d8e25eSMarc-André Lureau g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); 1773857cd5cSJonah Palmer virtio_init(VIRTIO_DEVICE(g), VIRTIO_ID_GPU, 17850d8e25eSMarc-André Lureau sizeof(struct virtio_gpu_config)); 17950d8e25eSMarc-André Lureau 18050d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 18150d8e25eSMarc-André Lureau /* use larger control queue in 3d mode */ 18250d8e25eSMarc-André Lureau virtio_add_queue(vdev, 256, ctrl_cb); 18350d8e25eSMarc-André Lureau virtio_add_queue(vdev, 16, cursor_cb); 18450d8e25eSMarc-André Lureau } else { 18550d8e25eSMarc-André Lureau virtio_add_queue(vdev, 64, ctrl_cb); 18650d8e25eSMarc-André Lureau virtio_add_queue(vdev, 16, cursor_cb); 18750d8e25eSMarc-André Lureau } 18850d8e25eSMarc-André Lureau 18950d8e25eSMarc-André Lureau g->enabled_output_bitmask = 1; 19050d8e25eSMarc-André Lureau 19150d8e25eSMarc-André Lureau g->req_state[0].width = g->conf.xres; 19250d8e25eSMarc-André Lureau g->req_state[0].height = g->conf.yres; 19350d8e25eSMarc-André Lureau 1943b593b3fSGerd Hoffmann g->hw_ops = &virtio_gpu_ops; 19550d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 19650d8e25eSMarc-André Lureau g->scanout[i].con = 19750d8e25eSMarc-André Lureau graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); 19850d8e25eSMarc-André Lureau } 19950d8e25eSMarc-André Lureau 20050d8e25eSMarc-André Lureau return true; 20150d8e25eSMarc-André Lureau } 20250d8e25eSMarc-André Lureau 20350d8e25eSMarc-André Lureau static uint64_t 20450d8e25eSMarc-André Lureau virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features, 20550d8e25eSMarc-André Lureau Error **errp) 20650d8e25eSMarc-André Lureau { 20750d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); 20850d8e25eSMarc-André Lureau 20950d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 21050d8e25eSMarc-André Lureau features |= (1 << VIRTIO_GPU_F_VIRGL); 21150d8e25eSMarc-André Lureau } 21250d8e25eSMarc-André Lureau if (virtio_gpu_edid_enabled(g->conf)) { 21350d8e25eSMarc-André Lureau features |= (1 << VIRTIO_GPU_F_EDID); 21450d8e25eSMarc-André Lureau } 215cce386e1SVivek Kasireddy if (virtio_gpu_blob_enabled(g->conf)) { 216cce386e1SVivek Kasireddy features |= (1 << VIRTIO_GPU_F_RESOURCE_BLOB); 217cce386e1SVivek Kasireddy } 21850d8e25eSMarc-André Lureau 21950d8e25eSMarc-André Lureau return features; 22050d8e25eSMarc-André Lureau } 22150d8e25eSMarc-André Lureau 22250d8e25eSMarc-André Lureau static void 22350d8e25eSMarc-André Lureau virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) 22450d8e25eSMarc-André Lureau { 22550d8e25eSMarc-André Lureau static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); 22650d8e25eSMarc-André Lureau 22749afbca3SGerd Hoffmann trace_virtio_gpu_features(((features & virgl) == virgl)); 22850d8e25eSMarc-André Lureau } 22950d8e25eSMarc-André Lureau 23050d8e25eSMarc-André Lureau static void 231b69c3c21SMarkus Armbruster virtio_gpu_base_device_unrealize(DeviceState *qdev) 23250d8e25eSMarc-André Lureau { 23350d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); 23450d8e25eSMarc-André Lureau 23550d8e25eSMarc-André Lureau if (g->migration_blocker) { 23650d8e25eSMarc-André Lureau migrate_del_blocker(g->migration_blocker); 23750d8e25eSMarc-André Lureau error_free(g->migration_blocker); 23850d8e25eSMarc-André Lureau } 23950d8e25eSMarc-André Lureau } 24050d8e25eSMarc-André Lureau 24150d8e25eSMarc-André Lureau static void 24250d8e25eSMarc-André Lureau virtio_gpu_base_class_init(ObjectClass *klass, void *data) 24350d8e25eSMarc-André Lureau { 24450d8e25eSMarc-André Lureau DeviceClass *dc = DEVICE_CLASS(klass); 24550d8e25eSMarc-André Lureau VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 24650d8e25eSMarc-André Lureau 24750d8e25eSMarc-André Lureau vdc->unrealize = virtio_gpu_base_device_unrealize; 24850d8e25eSMarc-André Lureau vdc->get_features = virtio_gpu_base_get_features; 24950d8e25eSMarc-André Lureau vdc->set_features = virtio_gpu_base_set_features; 25050d8e25eSMarc-André Lureau 25150d8e25eSMarc-André Lureau set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); 25250d8e25eSMarc-André Lureau dc->hotpluggable = false; 25350d8e25eSMarc-André Lureau } 25450d8e25eSMarc-André Lureau 25550d8e25eSMarc-André Lureau static const TypeInfo virtio_gpu_base_info = { 25650d8e25eSMarc-André Lureau .name = TYPE_VIRTIO_GPU_BASE, 25750d8e25eSMarc-André Lureau .parent = TYPE_VIRTIO_DEVICE, 25850d8e25eSMarc-André Lureau .instance_size = sizeof(VirtIOGPUBase), 25950d8e25eSMarc-André Lureau .class_size = sizeof(VirtIOGPUBaseClass), 26050d8e25eSMarc-André Lureau .class_init = virtio_gpu_base_class_init, 26150d8e25eSMarc-André Lureau .abstract = true 26250d8e25eSMarc-André Lureau }; 263561d0f45SGerd Hoffmann module_obj(TYPE_VIRTIO_GPU_BASE); 26424ce7aa7SJose R. Ziviani module_kconfig(VIRTIO_GPU); 26550d8e25eSMarc-André Lureau 26650d8e25eSMarc-André Lureau static void 26750d8e25eSMarc-André Lureau virtio_register_types(void) 26850d8e25eSMarc-André Lureau { 26950d8e25eSMarc-André Lureau type_register_static(&virtio_gpu_base_info); 27050d8e25eSMarc-André Lureau } 27150d8e25eSMarc-André Lureau 27250d8e25eSMarc-André Lureau type_init(virtio_register_types) 27350d8e25eSMarc-André Lureau 27450d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24); 27550d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56); 27650d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32); 27750d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40); 27850d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48); 27950d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48); 28050d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56); 28150d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16); 28250d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32); 28350d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32); 28450d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408); 28550d8e25eSMarc-André Lureau 28650d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72); 28750d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72); 28850d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96); 28950d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24); 29050d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32); 29150d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32); 29250d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32); 29350d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40); 29450d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32); 29550d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24); 296