qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

virtio-gpu-base.c (8535B)


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