xref: /qemu/hw/display/virtio-gpu-base.c (revision 50d8e25ea66db01f4214234803506dc1b28cb8d2)
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