1*50d8e25eSMarc-André Lureau /* 2*50d8e25eSMarc-André Lureau * Virtio GPU Device 3*50d8e25eSMarc-André Lureau * 4*50d8e25eSMarc-André Lureau * Copyright Red Hat, Inc. 2013-2014 5*50d8e25eSMarc-André Lureau * 6*50d8e25eSMarc-André Lureau * Authors: 7*50d8e25eSMarc-André Lureau * Dave Airlie <airlied@redhat.com> 8*50d8e25eSMarc-André Lureau * Gerd Hoffmann <kraxel@redhat.com> 9*50d8e25eSMarc-André Lureau * 10*50d8e25eSMarc-André Lureau * This work is licensed under the terms of the GNU GPL, version 2 or later. 11*50d8e25eSMarc-André Lureau * See the COPYING file in the top-level directory. 12*50d8e25eSMarc-André Lureau */ 13*50d8e25eSMarc-André Lureau 14*50d8e25eSMarc-André Lureau #include "qemu/osdep.h" 15*50d8e25eSMarc-André Lureau 16*50d8e25eSMarc-André Lureau #include "hw/virtio/virtio-gpu.h" 17*50d8e25eSMarc-André Lureau #include "migration/blocker.h" 18*50d8e25eSMarc-André Lureau #include "qapi/error.h" 19*50d8e25eSMarc-André Lureau #include "qemu/error-report.h" 20*50d8e25eSMarc-André Lureau #include "trace.h" 21*50d8e25eSMarc-André Lureau 22*50d8e25eSMarc-André Lureau void 23*50d8e25eSMarc-André Lureau virtio_gpu_base_reset(VirtIOGPUBase *g) 24*50d8e25eSMarc-André Lureau { 25*50d8e25eSMarc-André Lureau int i; 26*50d8e25eSMarc-André Lureau 27*50d8e25eSMarc-André Lureau g->enable = 0; 28*50d8e25eSMarc-André Lureau g->use_virgl_renderer = false; 29*50d8e25eSMarc-André Lureau 30*50d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 31*50d8e25eSMarc-André Lureau g->scanout[i].resource_id = 0; 32*50d8e25eSMarc-André Lureau g->scanout[i].width = 0; 33*50d8e25eSMarc-André Lureau g->scanout[i].height = 0; 34*50d8e25eSMarc-André Lureau g->scanout[i].x = 0; 35*50d8e25eSMarc-André Lureau g->scanout[i].y = 0; 36*50d8e25eSMarc-André Lureau g->scanout[i].ds = NULL; 37*50d8e25eSMarc-André Lureau } 38*50d8e25eSMarc-André Lureau } 39*50d8e25eSMarc-André Lureau 40*50d8e25eSMarc-André Lureau void 41*50d8e25eSMarc-André Lureau virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, 42*50d8e25eSMarc-André Lureau struct virtio_gpu_resp_display_info *dpy_info) 43*50d8e25eSMarc-André Lureau { 44*50d8e25eSMarc-André Lureau int i; 45*50d8e25eSMarc-André Lureau 46*50d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 47*50d8e25eSMarc-André Lureau if (g->enabled_output_bitmask & (1 << i)) { 48*50d8e25eSMarc-André Lureau dpy_info->pmodes[i].enabled = 1; 49*50d8e25eSMarc-André Lureau dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); 50*50d8e25eSMarc-André Lureau dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); 51*50d8e25eSMarc-André Lureau } 52*50d8e25eSMarc-André Lureau } 53*50d8e25eSMarc-André Lureau } 54*50d8e25eSMarc-André Lureau 55*50d8e25eSMarc-André Lureau static void virtio_gpu_invalidate_display(void *opaque) 56*50d8e25eSMarc-André Lureau { 57*50d8e25eSMarc-André Lureau } 58*50d8e25eSMarc-André Lureau 59*50d8e25eSMarc-André Lureau static void virtio_gpu_update_display(void *opaque) 60*50d8e25eSMarc-André Lureau { 61*50d8e25eSMarc-André Lureau } 62*50d8e25eSMarc-André Lureau 63*50d8e25eSMarc-André Lureau static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata) 64*50d8e25eSMarc-André Lureau { 65*50d8e25eSMarc-André Lureau } 66*50d8e25eSMarc-André Lureau 67*50d8e25eSMarc-André Lureau static void virtio_gpu_notify_event(VirtIOGPUBase *g, uint32_t event_type) 68*50d8e25eSMarc-André Lureau { 69*50d8e25eSMarc-André Lureau g->virtio_config.events_read |= event_type; 70*50d8e25eSMarc-André Lureau virtio_notify_config(&g->parent_obj); 71*50d8e25eSMarc-André Lureau } 72*50d8e25eSMarc-André Lureau 73*50d8e25eSMarc-André Lureau static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) 74*50d8e25eSMarc-André Lureau { 75*50d8e25eSMarc-André Lureau VirtIOGPUBase *g = opaque; 76*50d8e25eSMarc-André Lureau 77*50d8e25eSMarc-André Lureau if (idx >= g->conf.max_outputs) { 78*50d8e25eSMarc-André Lureau return -1; 79*50d8e25eSMarc-André Lureau } 80*50d8e25eSMarc-André Lureau 81*50d8e25eSMarc-André Lureau g->req_state[idx].x = info->xoff; 82*50d8e25eSMarc-André Lureau g->req_state[idx].y = info->yoff; 83*50d8e25eSMarc-André Lureau g->req_state[idx].width = info->width; 84*50d8e25eSMarc-André Lureau g->req_state[idx].height = info->height; 85*50d8e25eSMarc-André Lureau 86*50d8e25eSMarc-André Lureau if (info->width && info->height) { 87*50d8e25eSMarc-André Lureau g->enabled_output_bitmask |= (1 << idx); 88*50d8e25eSMarc-André Lureau } else { 89*50d8e25eSMarc-André Lureau g->enabled_output_bitmask &= ~(1 << idx); 90*50d8e25eSMarc-André Lureau } 91*50d8e25eSMarc-André Lureau 92*50d8e25eSMarc-André Lureau /* send event to guest */ 93*50d8e25eSMarc-André Lureau virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); 94*50d8e25eSMarc-André Lureau return 0; 95*50d8e25eSMarc-André Lureau } 96*50d8e25eSMarc-André Lureau 97*50d8e25eSMarc-André Lureau static void 98*50d8e25eSMarc-André Lureau virtio_gpu_gl_block(void *opaque, bool block) 99*50d8e25eSMarc-André Lureau { 100*50d8e25eSMarc-André Lureau VirtIOGPUBase *g = opaque; 101*50d8e25eSMarc-André Lureau VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_GET_CLASS(g); 102*50d8e25eSMarc-André Lureau 103*50d8e25eSMarc-André Lureau if (block) { 104*50d8e25eSMarc-André Lureau g->renderer_blocked++; 105*50d8e25eSMarc-André Lureau } else { 106*50d8e25eSMarc-André Lureau g->renderer_blocked--; 107*50d8e25eSMarc-André Lureau } 108*50d8e25eSMarc-André Lureau assert(g->renderer_blocked >= 0); 109*50d8e25eSMarc-André Lureau 110*50d8e25eSMarc-André Lureau if (g->renderer_blocked == 0) { 111*50d8e25eSMarc-André Lureau vgc->gl_unblock(g); 112*50d8e25eSMarc-André Lureau } 113*50d8e25eSMarc-André Lureau } 114*50d8e25eSMarc-André Lureau 115*50d8e25eSMarc-André Lureau const GraphicHwOps virtio_gpu_ops = { 116*50d8e25eSMarc-André Lureau .invalidate = virtio_gpu_invalidate_display, 117*50d8e25eSMarc-André Lureau .gfx_update = virtio_gpu_update_display, 118*50d8e25eSMarc-André Lureau .text_update = virtio_gpu_text_update, 119*50d8e25eSMarc-André Lureau .ui_info = virtio_gpu_ui_info, 120*50d8e25eSMarc-André Lureau .gl_block = virtio_gpu_gl_block, 121*50d8e25eSMarc-André Lureau }; 122*50d8e25eSMarc-André Lureau 123*50d8e25eSMarc-André Lureau bool 124*50d8e25eSMarc-André Lureau virtio_gpu_base_device_realize(DeviceState *qdev, 125*50d8e25eSMarc-André Lureau VirtIOHandleOutput ctrl_cb, 126*50d8e25eSMarc-André Lureau VirtIOHandleOutput cursor_cb, 127*50d8e25eSMarc-André Lureau Error **errp) 128*50d8e25eSMarc-André Lureau { 129*50d8e25eSMarc-André Lureau VirtIODevice *vdev = VIRTIO_DEVICE(qdev); 130*50d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); 131*50d8e25eSMarc-André Lureau Error *local_err = NULL; 132*50d8e25eSMarc-André Lureau int i; 133*50d8e25eSMarc-André Lureau 134*50d8e25eSMarc-André Lureau if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { 135*50d8e25eSMarc-André Lureau error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS); 136*50d8e25eSMarc-André Lureau return false; 137*50d8e25eSMarc-André Lureau } 138*50d8e25eSMarc-André Lureau 139*50d8e25eSMarc-André Lureau g->use_virgl_renderer = false; 140*50d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 141*50d8e25eSMarc-André Lureau error_setg(&g->migration_blocker, "virgl is not yet migratable"); 142*50d8e25eSMarc-André Lureau migrate_add_blocker(g->migration_blocker, &local_err); 143*50d8e25eSMarc-André Lureau if (local_err) { 144*50d8e25eSMarc-André Lureau error_propagate(errp, local_err); 145*50d8e25eSMarc-André Lureau error_free(g->migration_blocker); 146*50d8e25eSMarc-André Lureau return false; 147*50d8e25eSMarc-André Lureau } 148*50d8e25eSMarc-André Lureau } 149*50d8e25eSMarc-André Lureau 150*50d8e25eSMarc-André Lureau g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); 151*50d8e25eSMarc-André Lureau virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, 152*50d8e25eSMarc-André Lureau sizeof(struct virtio_gpu_config)); 153*50d8e25eSMarc-André Lureau 154*50d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 155*50d8e25eSMarc-André Lureau /* use larger control queue in 3d mode */ 156*50d8e25eSMarc-André Lureau virtio_add_queue(vdev, 256, ctrl_cb); 157*50d8e25eSMarc-André Lureau virtio_add_queue(vdev, 16, cursor_cb); 158*50d8e25eSMarc-André Lureau } else { 159*50d8e25eSMarc-André Lureau virtio_add_queue(vdev, 64, ctrl_cb); 160*50d8e25eSMarc-André Lureau virtio_add_queue(vdev, 16, cursor_cb); 161*50d8e25eSMarc-André Lureau } 162*50d8e25eSMarc-André Lureau 163*50d8e25eSMarc-André Lureau g->enabled_output_bitmask = 1; 164*50d8e25eSMarc-André Lureau 165*50d8e25eSMarc-André Lureau g->req_state[0].width = g->conf.xres; 166*50d8e25eSMarc-André Lureau g->req_state[0].height = g->conf.yres; 167*50d8e25eSMarc-André Lureau 168*50d8e25eSMarc-André Lureau for (i = 0; i < g->conf.max_outputs; i++) { 169*50d8e25eSMarc-André Lureau g->scanout[i].con = 170*50d8e25eSMarc-André Lureau graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); 171*50d8e25eSMarc-André Lureau if (i > 0) { 172*50d8e25eSMarc-André Lureau dpy_gfx_replace_surface(g->scanout[i].con, NULL); 173*50d8e25eSMarc-André Lureau } 174*50d8e25eSMarc-André Lureau } 175*50d8e25eSMarc-André Lureau 176*50d8e25eSMarc-André Lureau return true; 177*50d8e25eSMarc-André Lureau } 178*50d8e25eSMarc-André Lureau 179*50d8e25eSMarc-André Lureau static uint64_t 180*50d8e25eSMarc-André Lureau virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features, 181*50d8e25eSMarc-André Lureau Error **errp) 182*50d8e25eSMarc-André Lureau { 183*50d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); 184*50d8e25eSMarc-André Lureau 185*50d8e25eSMarc-André Lureau if (virtio_gpu_virgl_enabled(g->conf)) { 186*50d8e25eSMarc-André Lureau features |= (1 << VIRTIO_GPU_F_VIRGL); 187*50d8e25eSMarc-André Lureau } 188*50d8e25eSMarc-André Lureau if (virtio_gpu_edid_enabled(g->conf)) { 189*50d8e25eSMarc-André Lureau features |= (1 << VIRTIO_GPU_F_EDID); 190*50d8e25eSMarc-André Lureau } 191*50d8e25eSMarc-André Lureau 192*50d8e25eSMarc-André Lureau return features; 193*50d8e25eSMarc-André Lureau } 194*50d8e25eSMarc-André Lureau 195*50d8e25eSMarc-André Lureau static void 196*50d8e25eSMarc-André Lureau virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) 197*50d8e25eSMarc-André Lureau { 198*50d8e25eSMarc-André Lureau static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); 199*50d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); 200*50d8e25eSMarc-André Lureau 201*50d8e25eSMarc-André Lureau g->use_virgl_renderer = ((features & virgl) == virgl); 202*50d8e25eSMarc-André Lureau trace_virtio_gpu_features(g->use_virgl_renderer); 203*50d8e25eSMarc-André Lureau } 204*50d8e25eSMarc-André Lureau 205*50d8e25eSMarc-André Lureau static void 206*50d8e25eSMarc-André Lureau virtio_gpu_base_device_unrealize(DeviceState *qdev, Error **errp) 207*50d8e25eSMarc-André Lureau { 208*50d8e25eSMarc-André Lureau VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); 209*50d8e25eSMarc-André Lureau 210*50d8e25eSMarc-André Lureau if (g->migration_blocker) { 211*50d8e25eSMarc-André Lureau migrate_del_blocker(g->migration_blocker); 212*50d8e25eSMarc-André Lureau error_free(g->migration_blocker); 213*50d8e25eSMarc-André Lureau } 214*50d8e25eSMarc-André Lureau } 215*50d8e25eSMarc-André Lureau 216*50d8e25eSMarc-André Lureau static void 217*50d8e25eSMarc-André Lureau virtio_gpu_base_class_init(ObjectClass *klass, void *data) 218*50d8e25eSMarc-André Lureau { 219*50d8e25eSMarc-André Lureau DeviceClass *dc = DEVICE_CLASS(klass); 220*50d8e25eSMarc-André Lureau VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 221*50d8e25eSMarc-André Lureau 222*50d8e25eSMarc-André Lureau vdc->unrealize = virtio_gpu_base_device_unrealize; 223*50d8e25eSMarc-André Lureau vdc->get_features = virtio_gpu_base_get_features; 224*50d8e25eSMarc-André Lureau vdc->set_features = virtio_gpu_base_set_features; 225*50d8e25eSMarc-André Lureau 226*50d8e25eSMarc-André Lureau set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); 227*50d8e25eSMarc-André Lureau dc->hotpluggable = false; 228*50d8e25eSMarc-André Lureau } 229*50d8e25eSMarc-André Lureau 230*50d8e25eSMarc-André Lureau static const TypeInfo virtio_gpu_base_info = { 231*50d8e25eSMarc-André Lureau .name = TYPE_VIRTIO_GPU_BASE, 232*50d8e25eSMarc-André Lureau .parent = TYPE_VIRTIO_DEVICE, 233*50d8e25eSMarc-André Lureau .instance_size = sizeof(VirtIOGPUBase), 234*50d8e25eSMarc-André Lureau .class_size = sizeof(VirtIOGPUBaseClass), 235*50d8e25eSMarc-André Lureau .class_init = virtio_gpu_base_class_init, 236*50d8e25eSMarc-André Lureau .abstract = true 237*50d8e25eSMarc-André Lureau }; 238*50d8e25eSMarc-André Lureau 239*50d8e25eSMarc-André Lureau static void 240*50d8e25eSMarc-André Lureau virtio_register_types(void) 241*50d8e25eSMarc-André Lureau { 242*50d8e25eSMarc-André Lureau type_register_static(&virtio_gpu_base_info); 243*50d8e25eSMarc-André Lureau } 244*50d8e25eSMarc-André Lureau 245*50d8e25eSMarc-André Lureau type_init(virtio_register_types) 246*50d8e25eSMarc-André Lureau 247*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24); 248*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56); 249*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32); 250*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40); 251*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48); 252*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48); 253*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56); 254*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16); 255*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32); 256*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32); 257*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408); 258*50d8e25eSMarc-André Lureau 259*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72); 260*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72); 261*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96); 262*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24); 263*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32); 264*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32); 265*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32); 266*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40); 267*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32); 268*50d8e25eSMarc-André Lureau QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24); 269