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