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" 20*ee3729d9SErico Nunes #include "hw/display/edid.h" 2150d8e25eSMarc-André Lureau #include "trace.h" 2250d8e25eSMarc-André Lureau 2350d8e25eSMarc-André Lureau void 2450d8e25eSMarc-André Lureau virtio_gpu_base_reset(VirtIOGPUBase *g) 2550d8e25eSMarc-André Lureau { 2650d8e25eSMarc-André Lureau int i; 2750d8e25eSMarc-André Lureau 2850d8e25eSMarc-André Lureau g->enable = 0; 2950d8e25eSMarc-André Lureau 3050d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 3150d8e25eSMarc-André Lureau g->scanout[i].resource_id = 0; 3250d8e25eSMarc-André Lureau g->scanout[i].width = 0; 3350d8e25eSMarc-André Lureau g->scanout[i].height = 0; 3450d8e25eSMarc-André Lureau g->scanout[i].x = 0; 3550d8e25eSMarc-André Lureau g->scanout[i].y = 0; 3650d8e25eSMarc-André Lureau g->scanout[i].ds = NULL; 3750d8e25eSMarc-André Lureau } 3850d8e25eSMarc-André Lureau } 3950d8e25eSMarc-André Lureau 4050d8e25eSMarc-André Lureau void 4150d8e25eSMarc-André Lureau virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, 4250d8e25eSMarc-André Lureau struct virtio_gpu_resp_display_info *dpy_info) 4350d8e25eSMarc-André Lureau { 4450d8e25eSMarc-André Lureau int i; 4550d8e25eSMarc-André Lureau 4650d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 4750d8e25eSMarc-André Lureau if (g->enabled_output_bitmask & (1 << i)) { 4850d8e25eSMarc-André Lureau dpy_info->pmodes[i].enabled = 1; 4950d8e25eSMarc-André Lureau dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); 5050d8e25eSMarc-André Lureau dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); 5150d8e25eSMarc-André Lureau } 5250d8e25eSMarc-André Lureau } 5350d8e25eSMarc-André Lureau } 5450d8e25eSMarc-André Lureau 55*ee3729d9SErico Nunes void 56*ee3729d9SErico Nunes virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout, 57*ee3729d9SErico Nunes struct virtio_gpu_resp_edid *edid) 58*ee3729d9SErico Nunes { 59*ee3729d9SErico Nunes qemu_edid_info info = { 60*ee3729d9SErico Nunes .width_mm = g->req_state[scanout].width_mm, 61*ee3729d9SErico Nunes .height_mm = g->req_state[scanout].height_mm, 62*ee3729d9SErico Nunes .prefx = g->req_state[scanout].width, 63*ee3729d9SErico Nunes .prefy = g->req_state[scanout].height, 64*ee3729d9SErico Nunes .refresh_rate = g->req_state[scanout].refresh_rate, 65*ee3729d9SErico Nunes }; 66*ee3729d9SErico Nunes 67*ee3729d9SErico Nunes edid->size = cpu_to_le32(sizeof(edid->edid)); 68*ee3729d9SErico Nunes qemu_edid_generate(edid->edid, sizeof(edid->edid), &info); 69*ee3729d9SErico Nunes } 70*ee3729d9SErico Nunes 7150d8e25eSMarc-André Lureau static void virtio_gpu_invalidate_display(void *opaque) 7250d8e25eSMarc-André Lureau { 7350d8e25eSMarc-André Lureau } 7450d8e25eSMarc-André Lureau 7550d8e25eSMarc-André Lureau static void virtio_gpu_update_display(void *opaque) 7650d8e25eSMarc-André Lureau { 7750d8e25eSMarc-André Lureau } 7850d8e25eSMarc-André Lureau 7950d8e25eSMarc-André Lureau static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata) 8050d8e25eSMarc-André Lureau { 8150d8e25eSMarc-André Lureau } 8250d8e25eSMarc-André Lureau 8350d8e25eSMarc-André Lureau static void virtio_gpu_notify_event(VirtIOGPUBase *g, uint32_t event_type) 8450d8e25eSMarc-André Lureau { 8550d8e25eSMarc-André Lureau g->virtio_config.events_read |= event_type; 8650d8e25eSMarc-André Lureau virtio_notify_config(&g->parent_obj); 8750d8e25eSMarc-André Lureau } 8850d8e25eSMarc-André Lureau 89362239c0SAkihiko Odaki static void virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) 9050d8e25eSMarc-André Lureau { 9150d8e25eSMarc-André Lureau VirtIOGPUBase *g = opaque; 9250d8e25eSMarc-André Lureau 9350d8e25eSMarc-André Lureau if (idx >= g->conf.max_outputs) { 94362239c0SAkihiko Odaki return; 9550d8e25eSMarc-André Lureau } 9650d8e25eSMarc-André Lureau 9750d8e25eSMarc-André Lureau g->req_state[idx].x = info->xoff; 9850d8e25eSMarc-André Lureau g->req_state[idx].y = info->yoff; 99b95b5631SAkihiko Odaki g->req_state[idx].refresh_rate = info->refresh_rate; 10050d8e25eSMarc-André Lureau g->req_state[idx].width = info->width; 10150d8e25eSMarc-André Lureau g->req_state[idx].height = info->height; 1024bf47f36SMarc-André Lureau g->req_state[idx].width_mm = info->width_mm; 1034bf47f36SMarc-André Lureau g->req_state[idx].height_mm = info->height_mm; 10450d8e25eSMarc-André Lureau 10550d8e25eSMarc-André Lureau if (info->width && info->height) { 10650d8e25eSMarc-André Lureau g->enabled_output_bitmask |= (1 << idx); 10750d8e25eSMarc-André Lureau } else { 10850d8e25eSMarc-André Lureau g->enabled_output_bitmask &= ~(1 << idx); 10950d8e25eSMarc-André Lureau } 11050d8e25eSMarc-André Lureau 11150d8e25eSMarc-André Lureau /* send event to guest */ 11250d8e25eSMarc-André Lureau virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); 113362239c0SAkihiko Odaki return; 11450d8e25eSMarc-André Lureau } 11550d8e25eSMarc-André Lureau 11650d8e25eSMarc-André Lureau static void 1173cddb8b9SMarc-André Lureau virtio_gpu_gl_flushed(void *opaque) 11850d8e25eSMarc-André Lureau { 11950d8e25eSMarc-André Lureau VirtIOGPUBase *g = opaque; 12050d8e25eSMarc-André Lureau VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_GET_CLASS(g); 12150d8e25eSMarc-André Lureau 1223cddb8b9SMarc-André Lureau if (vgc->gl_flushed) { 1233cddb8b9SMarc-André Lureau vgc->gl_flushed(g); 1243cddb8b9SMarc-André Lureau } 1253cddb8b9SMarc-André Lureau } 1263cddb8b9SMarc-André Lureau 1273cddb8b9SMarc-André Lureau static void 1283cddb8b9SMarc-André Lureau virtio_gpu_gl_block(void *opaque, bool block) 1293cddb8b9SMarc-André Lureau { 1303cddb8b9SMarc-André Lureau VirtIOGPUBase *g = opaque; 1313cddb8b9SMarc-André Lureau 13250d8e25eSMarc-André Lureau if (block) { 13350d8e25eSMarc-André Lureau g->renderer_blocked++; 13450d8e25eSMarc-André Lureau } else { 13550d8e25eSMarc-André Lureau g->renderer_blocked--; 13650d8e25eSMarc-André Lureau } 13750d8e25eSMarc-André Lureau assert(g->renderer_blocked >= 0); 138f6413cbfSMarc-André Lureau 139f6413cbfSMarc-André Lureau if (!block && g->renderer_blocked == 0) { 140f6413cbfSMarc-André Lureau virtio_gpu_gl_flushed(g); 141f6413cbfSMarc-André Lureau } 14250d8e25eSMarc-André Lureau } 14350d8e25eSMarc-André Lureau 144a7dfbe28SMarc-André Lureau static int 145a7dfbe28SMarc-André Lureau virtio_gpu_get_flags(void *opaque) 146a7dfbe28SMarc-André Lureau { 147a7dfbe28SMarc-André Lureau VirtIOGPUBase *g = opaque; 148a7dfbe28SMarc-André Lureau int flags = GRAPHIC_FLAGS_NONE; 149a7dfbe28SMarc-André Lureau 150a7dfbe28SMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 151a7dfbe28SMarc-André Lureau flags |= GRAPHIC_FLAGS_GL; 152a7dfbe28SMarc-André Lureau } 153a7dfbe28SMarc-André Lureau 154a7dfbe28SMarc-André Lureau if (virtio_gpu_dmabuf_enabled(g->conf)) { 155a7dfbe28SMarc-André Lureau flags |= GRAPHIC_FLAGS_DMABUF; 156a7dfbe28SMarc-André Lureau } 157a7dfbe28SMarc-André Lureau 158a7dfbe28SMarc-André Lureau return flags; 159a7dfbe28SMarc-André Lureau } 160a7dfbe28SMarc-André Lureau 1613b593b3fSGerd Hoffmann static const GraphicHwOps virtio_gpu_ops = { 162a7dfbe28SMarc-André Lureau .get_flags = virtio_gpu_get_flags, 16350d8e25eSMarc-André Lureau .invalidate = virtio_gpu_invalidate_display, 16450d8e25eSMarc-André Lureau .gfx_update = virtio_gpu_update_display, 16550d8e25eSMarc-André Lureau .text_update = virtio_gpu_text_update, 16650d8e25eSMarc-André Lureau .ui_info = virtio_gpu_ui_info, 16750d8e25eSMarc-André Lureau .gl_block = virtio_gpu_gl_block, 16850d8e25eSMarc-André Lureau }; 16950d8e25eSMarc-André Lureau 17050d8e25eSMarc-André Lureau bool 17150d8e25eSMarc-André Lureau virtio_gpu_base_device_realize(DeviceState *qdev, 17250d8e25eSMarc-André Lureau VirtIOHandleOutput ctrl_cb, 17350d8e25eSMarc-André Lureau VirtIOHandleOutput cursor_cb, 17450d8e25eSMarc-André Lureau Error **errp) 17550d8e25eSMarc-André Lureau { 17650d8e25eSMarc-André Lureau VirtIODevice *vdev = VIRTIO_DEVICE(qdev); 17750d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); 17850d8e25eSMarc-André Lureau int i; 17950d8e25eSMarc-André Lureau 18050d8e25eSMarc-André Lureau if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { 18150d8e25eSMarc-André Lureau error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS); 18250d8e25eSMarc-André Lureau return false; 18350d8e25eSMarc-André Lureau } 18450d8e25eSMarc-André Lureau 18550d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 18650d8e25eSMarc-André Lureau error_setg(&g->migration_blocker, "virgl is not yet migratable"); 187386f6c07SMarkus Armbruster if (migrate_add_blocker(g->migration_blocker, errp) < 0) { 18850d8e25eSMarc-André Lureau error_free(g->migration_blocker); 18950d8e25eSMarc-André Lureau return false; 19050d8e25eSMarc-André Lureau } 19150d8e25eSMarc-André Lureau } 19250d8e25eSMarc-André Lureau 19350d8e25eSMarc-André Lureau g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); 1943857cd5cSJonah Palmer virtio_init(VIRTIO_DEVICE(g), VIRTIO_ID_GPU, 19550d8e25eSMarc-André Lureau sizeof(struct virtio_gpu_config)); 19650d8e25eSMarc-André Lureau 19750d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 19850d8e25eSMarc-André Lureau /* use larger control queue in 3d mode */ 19950d8e25eSMarc-André Lureau virtio_add_queue(vdev, 256, ctrl_cb); 20050d8e25eSMarc-André Lureau virtio_add_queue(vdev, 16, cursor_cb); 20150d8e25eSMarc-André Lureau } else { 20250d8e25eSMarc-André Lureau virtio_add_queue(vdev, 64, ctrl_cb); 20350d8e25eSMarc-André Lureau virtio_add_queue(vdev, 16, cursor_cb); 20450d8e25eSMarc-André Lureau } 20550d8e25eSMarc-André Lureau 20650d8e25eSMarc-André Lureau g->enabled_output_bitmask = 1; 20750d8e25eSMarc-André Lureau 20850d8e25eSMarc-André Lureau g->req_state[0].width = g->conf.xres; 20950d8e25eSMarc-André Lureau g->req_state[0].height = g->conf.yres; 21050d8e25eSMarc-André Lureau 2113b593b3fSGerd Hoffmann g->hw_ops = &virtio_gpu_ops; 21250d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 21350d8e25eSMarc-André Lureau g->scanout[i].con = 21450d8e25eSMarc-André Lureau graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); 21550d8e25eSMarc-André Lureau } 21650d8e25eSMarc-André Lureau 21750d8e25eSMarc-André Lureau return true; 21850d8e25eSMarc-André Lureau } 21950d8e25eSMarc-André Lureau 22050d8e25eSMarc-André Lureau static uint64_t 22150d8e25eSMarc-André Lureau virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features, 22250d8e25eSMarc-André Lureau Error **errp) 22350d8e25eSMarc-André Lureau { 22450d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); 22550d8e25eSMarc-André Lureau 22650d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 22750d8e25eSMarc-André Lureau features |= (1 << VIRTIO_GPU_F_VIRGL); 22850d8e25eSMarc-André Lureau } 22950d8e25eSMarc-André Lureau if (virtio_gpu_edid_enabled(g->conf)) { 23050d8e25eSMarc-André Lureau features |= (1 << VIRTIO_GPU_F_EDID); 23150d8e25eSMarc-André Lureau } 232cce386e1SVivek Kasireddy if (virtio_gpu_blob_enabled(g->conf)) { 233cce386e1SVivek Kasireddy features |= (1 << VIRTIO_GPU_F_RESOURCE_BLOB); 234cce386e1SVivek Kasireddy } 23550d8e25eSMarc-André Lureau 23650d8e25eSMarc-André Lureau return features; 23750d8e25eSMarc-André Lureau } 23850d8e25eSMarc-André Lureau 23950d8e25eSMarc-André Lureau static void 24050d8e25eSMarc-André Lureau virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) 24150d8e25eSMarc-André Lureau { 24250d8e25eSMarc-André Lureau static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); 24350d8e25eSMarc-André Lureau 24449afbca3SGerd Hoffmann trace_virtio_gpu_features(((features & virgl) == virgl)); 24550d8e25eSMarc-André Lureau } 24650d8e25eSMarc-André Lureau 24750d8e25eSMarc-André Lureau static void 248b69c3c21SMarkus Armbruster virtio_gpu_base_device_unrealize(DeviceState *qdev) 24950d8e25eSMarc-André Lureau { 25050d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); 25150d8e25eSMarc-André Lureau 25250d8e25eSMarc-André Lureau if (g->migration_blocker) { 25350d8e25eSMarc-André Lureau migrate_del_blocker(g->migration_blocker); 25450d8e25eSMarc-André Lureau error_free(g->migration_blocker); 25550d8e25eSMarc-André Lureau } 25650d8e25eSMarc-André Lureau } 25750d8e25eSMarc-André Lureau 25850d8e25eSMarc-André Lureau static void 25950d8e25eSMarc-André Lureau virtio_gpu_base_class_init(ObjectClass *klass, void *data) 26050d8e25eSMarc-André Lureau { 26150d8e25eSMarc-André Lureau DeviceClass *dc = DEVICE_CLASS(klass); 26250d8e25eSMarc-André Lureau VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 26350d8e25eSMarc-André Lureau 26450d8e25eSMarc-André Lureau vdc->unrealize = virtio_gpu_base_device_unrealize; 26550d8e25eSMarc-André Lureau vdc->get_features = virtio_gpu_base_get_features; 26650d8e25eSMarc-André Lureau vdc->set_features = virtio_gpu_base_set_features; 26750d8e25eSMarc-André Lureau 26850d8e25eSMarc-André Lureau set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); 26950d8e25eSMarc-André Lureau dc->hotpluggable = false; 27050d8e25eSMarc-André Lureau } 27150d8e25eSMarc-André Lureau 27250d8e25eSMarc-André Lureau static const TypeInfo virtio_gpu_base_info = { 27350d8e25eSMarc-André Lureau .name = TYPE_VIRTIO_GPU_BASE, 27450d8e25eSMarc-André Lureau .parent = TYPE_VIRTIO_DEVICE, 27550d8e25eSMarc-André Lureau .instance_size = sizeof(VirtIOGPUBase), 27650d8e25eSMarc-André Lureau .class_size = sizeof(VirtIOGPUBaseClass), 27750d8e25eSMarc-André Lureau .class_init = virtio_gpu_base_class_init, 27850d8e25eSMarc-André Lureau .abstract = true 27950d8e25eSMarc-André Lureau }; 280561d0f45SGerd Hoffmann module_obj(TYPE_VIRTIO_GPU_BASE); 28124ce7aa7SJose R. Ziviani module_kconfig(VIRTIO_GPU); 28250d8e25eSMarc-André Lureau 28350d8e25eSMarc-André Lureau static void 28450d8e25eSMarc-André Lureau virtio_register_types(void) 28550d8e25eSMarc-André Lureau { 28650d8e25eSMarc-André Lureau type_register_static(&virtio_gpu_base_info); 28750d8e25eSMarc-André Lureau } 28850d8e25eSMarc-André Lureau 28950d8e25eSMarc-André Lureau type_init(virtio_register_types) 29050d8e25eSMarc-André Lureau 29150d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24); 29250d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56); 29350d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32); 29450d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40); 29550d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48); 29650d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48); 29750d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56); 29850d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16); 29950d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32); 30050d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32); 30150d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408); 30250d8e25eSMarc-André Lureau 30350d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72); 30450d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72); 30550d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96); 30650d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24); 30750d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32); 30850d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32); 30950d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32); 31050d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40); 31150d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32); 31250d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24); 313