]> git.proxmox.com Git - mirror_qemu.git/blame - hw/display/vhost-user-gpu.c
macfb: don't clear interrupts when writing to DAFB_RESET
[mirror_qemu.git] / hw / display / vhost-user-gpu.c
CommitLineData
267f6646
MAL
1/*
2 * vhost-user GPU Device
3 *
4 * Copyright Red Hat, Inc. 2018
5 *
6 * Authors:
7 * Marc-André Lureau <marcandre.lureau@redhat.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13#include "qemu/osdep.h"
5feed38c 14#include "qemu/error-report.h"
9cbda7b3 15#include "qemu/sockets.h"
a27bd6c7 16#include "hw/qdev-properties.h"
267f6646
MAL
17#include "hw/virtio/virtio-gpu.h"
18#include "chardev/char-fe.h"
19#include "qapi/error.h"
20#include "migration/blocker.h"
21
267f6646
MAL
22typedef enum VhostUserGpuRequest {
23 VHOST_USER_GPU_NONE = 0,
24 VHOST_USER_GPU_GET_PROTOCOL_FEATURES,
25 VHOST_USER_GPU_SET_PROTOCOL_FEATURES,
26 VHOST_USER_GPU_GET_DISPLAY_INFO,
27 VHOST_USER_GPU_CURSOR_POS,
28 VHOST_USER_GPU_CURSOR_POS_HIDE,
29 VHOST_USER_GPU_CURSOR_UPDATE,
30 VHOST_USER_GPU_SCANOUT,
31 VHOST_USER_GPU_UPDATE,
32 VHOST_USER_GPU_DMABUF_SCANOUT,
33 VHOST_USER_GPU_DMABUF_UPDATE,
31f137e3 34 VHOST_USER_GPU_GET_EDID,
d824da9d 35 VHOST_USER_GPU_DMABUF_SCANOUT2,
267f6646
MAL
36} VhostUserGpuRequest;
37
38typedef struct VhostUserGpuDisplayInfoReply {
39 struct virtio_gpu_resp_display_info info;
40} VhostUserGpuDisplayInfoReply;
41
42typedef struct VhostUserGpuCursorPos {
43 uint32_t scanout_id;
44 uint32_t x;
45 uint32_t y;
46} QEMU_PACKED VhostUserGpuCursorPos;
47
48typedef struct VhostUserGpuCursorUpdate {
49 VhostUserGpuCursorPos pos;
50 uint32_t hot_x;
51 uint32_t hot_y;
52 uint32_t data[64 * 64];
53} QEMU_PACKED VhostUserGpuCursorUpdate;
54
55typedef struct VhostUserGpuScanout {
56 uint32_t scanout_id;
57 uint32_t width;
58 uint32_t height;
59} QEMU_PACKED VhostUserGpuScanout;
60
61typedef struct VhostUserGpuUpdate {
62 uint32_t scanout_id;
63 uint32_t x;
64 uint32_t y;
65 uint32_t width;
66 uint32_t height;
67 uint8_t data[];
68} QEMU_PACKED VhostUserGpuUpdate;
69
70typedef struct VhostUserGpuDMABUFScanout {
71 uint32_t scanout_id;
72 uint32_t x;
73 uint32_t y;
74 uint32_t width;
75 uint32_t height;
76 uint32_t fd_width;
77 uint32_t fd_height;
78 uint32_t fd_stride;
79 uint32_t fd_flags;
80 int fd_drm_fourcc;
81} QEMU_PACKED VhostUserGpuDMABUFScanout;
82
d824da9d
EN
83typedef struct VhostUserGpuDMABUFScanout2 {
84 struct VhostUserGpuDMABUFScanout dmabuf_scanout;
85 uint64_t modifier;
86} QEMU_PACKED VhostUserGpuDMABUFScanout2;
87
31f137e3
EN
88typedef struct VhostUserGpuEdidRequest {
89 uint32_t scanout_id;
90} QEMU_PACKED VhostUserGpuEdidRequest;
91
267f6646
MAL
92typedef struct VhostUserGpuMsg {
93 uint32_t request; /* VhostUserGpuRequest */
94 uint32_t flags;
95 uint32_t size; /* the following payload size */
96 union {
97 VhostUserGpuCursorPos cursor_pos;
98 VhostUserGpuCursorUpdate cursor_update;
99 VhostUserGpuScanout scanout;
100 VhostUserGpuUpdate update;
101 VhostUserGpuDMABUFScanout dmabuf_scanout;
d824da9d 102 VhostUserGpuDMABUFScanout2 dmabuf_scanout2;
31f137e3
EN
103 VhostUserGpuEdidRequest edid_req;
104 struct virtio_gpu_resp_edid resp_edid;
267f6646
MAL
105 struct virtio_gpu_resp_display_info display_info;
106 uint64_t u64;
107 } payload;
108} QEMU_PACKED VhostUserGpuMsg;
109
110static VhostUserGpuMsg m __attribute__ ((unused));
111#define VHOST_USER_GPU_HDR_SIZE \
112 (sizeof(m.request) + sizeof(m.size) + sizeof(m.flags))
113
114#define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
115
31f137e3 116#define VHOST_USER_GPU_PROTOCOL_F_EDID 0
d824da9d 117#define VHOST_USER_GPU_PROTOCOL_F_DMABUF2 1
31f137e3 118
267f6646
MAL
119static void vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked);
120
121static void
122vhost_user_gpu_handle_cursor(VhostUserGPU *g, VhostUserGpuMsg *msg)
123{
124 VhostUserGpuCursorPos *pos = &msg->payload.cursor_pos;
125 struct virtio_gpu_scanout *s;
126
127 if (pos->scanout_id >= g->parent_obj.conf.max_outputs) {
128 return;
129 }
130 s = &g->parent_obj.scanout[pos->scanout_id];
131
132 if (msg->request == VHOST_USER_GPU_CURSOR_UPDATE) {
133 VhostUserGpuCursorUpdate *up = &msg->payload.cursor_update;
134 if (!s->current_cursor) {
135 s->current_cursor = cursor_alloc(64, 64);
136 }
137
138 s->current_cursor->hot_x = up->hot_x;
139 s->current_cursor->hot_y = up->hot_y;
140
141 memcpy(s->current_cursor->data, up->data,
142 64 * 64 * sizeof(uint32_t));
143
144 dpy_cursor_define(s->con, s->current_cursor);
145 }
146
147 dpy_mouse_set(s->con, pos->x, pos->y,
148 msg->request != VHOST_USER_GPU_CURSOR_POS_HIDE);
149}
150
151static void
152vhost_user_gpu_send_msg(VhostUserGPU *g, const VhostUserGpuMsg *msg)
153{
154 qemu_chr_fe_write(&g->vhost_chr, (uint8_t *)msg,
155 VHOST_USER_GPU_HDR_SIZE + msg->size);
156}
157
158static void
159vhost_user_gpu_unblock(VhostUserGPU *g)
160{
161 VhostUserGpuMsg msg = {
162 .request = VHOST_USER_GPU_DMABUF_UPDATE,
163 .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
164 };
165
166 vhost_user_gpu_send_msg(g, &msg);
167}
168
169static void
170vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
171{
172 QemuConsole *con = NULL;
173 struct virtio_gpu_scanout *s;
174
175 switch (msg->request) {
176 case VHOST_USER_GPU_GET_PROTOCOL_FEATURES: {
177 VhostUserGpuMsg reply = {
178 .request = msg->request,
179 .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
180 .size = sizeof(uint64_t),
31f137e3 181 .payload = {
d824da9d
EN
182 .u64 = (1 << VHOST_USER_GPU_PROTOCOL_F_EDID) |
183 (1 << VHOST_USER_GPU_PROTOCOL_F_DMABUF2)
31f137e3 184 }
267f6646
MAL
185 };
186
187 vhost_user_gpu_send_msg(g, &reply);
188 break;
189 }
190 case VHOST_USER_GPU_SET_PROTOCOL_FEATURES: {
191 break;
192 }
193 case VHOST_USER_GPU_GET_DISPLAY_INFO: {
194 struct virtio_gpu_resp_display_info display_info = { {} };
195 VhostUserGpuMsg reply = {
196 .request = msg->request,
197 .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
198 .size = sizeof(struct virtio_gpu_resp_display_info),
199 };
200
201 display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
202 virtio_gpu_base_fill_display_info(VIRTIO_GPU_BASE(g), &display_info);
203 memcpy(&reply.payload.display_info, &display_info,
204 sizeof(display_info));
205 vhost_user_gpu_send_msg(g, &reply);
206 break;
207 }
31f137e3
EN
208 case VHOST_USER_GPU_GET_EDID: {
209 VhostUserGpuEdidRequest *m = &msg->payload.edid_req;
210 struct virtio_gpu_resp_edid resp = { {} };
211 VhostUserGpuMsg reply = {
212 .request = msg->request,
213 .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
214 .size = sizeof(reply.payload.resp_edid),
215 };
216
217 if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
218 error_report("invalid scanout: %d", m->scanout_id);
219 break;
220 }
221
222 resp.hdr.type = VIRTIO_GPU_RESP_OK_EDID;
223 virtio_gpu_base_generate_edid(VIRTIO_GPU_BASE(g), m->scanout_id, &resp);
224 memcpy(&reply.payload.resp_edid, &resp, sizeof(resp));
225 vhost_user_gpu_send_msg(g, &reply);
226 break;
227 }
267f6646
MAL
228 case VHOST_USER_GPU_SCANOUT: {
229 VhostUserGpuScanout *m = &msg->payload.scanout;
230
231 if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
232 return;
233 }
234
235 g->parent_obj.enable = 1;
236 s = &g->parent_obj.scanout[m->scanout_id];
237 con = s->con;
238
ed8f3fe6
AO
239 if (m->width == 0) {
240 dpy_gfx_replace_surface(con, NULL);
267f6646
MAL
241 } else {
242 s->ds = qemu_create_displaysurface(m->width, m->height);
243 /* replace surface on next update */
244 }
245
246 break;
247 }
d824da9d 248 case VHOST_USER_GPU_DMABUF_SCANOUT2:
267f6646
MAL
249 case VHOST_USER_GPU_DMABUF_SCANOUT: {
250 VhostUserGpuDMABUFScanout *m = &msg->payload.dmabuf_scanout;
251 int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr);
252 QemuDmaBuf *dmabuf;
253
254 if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
255 error_report("invalid scanout: %d", m->scanout_id);
256 if (fd >= 0) {
257 close(fd);
258 }
259 break;
260 }
261
262 g->parent_obj.enable = 1;
263 con = g->parent_obj.scanout[m->scanout_id].con;
264 dmabuf = &g->dmabuf[m->scanout_id];
265 if (dmabuf->fd >= 0) {
266 close(dmabuf->fd);
267 dmabuf->fd = -1;
268 }
267f6646
MAL
269 dpy_gl_release_dmabuf(con, dmabuf);
270 if (fd == -1) {
271 dpy_gl_scanout_disable(con);
272 break;
273 }
274 *dmabuf = (QemuDmaBuf) {
275 .fd = fd,
276 .width = m->fd_width,
277 .height = m->fd_height,
278 .stride = m->fd_stride,
279 .fourcc = m->fd_drm_fourcc,
280 .y0_top = m->fd_flags & VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP,
281 };
d824da9d
EN
282 if (msg->request == VHOST_USER_GPU_DMABUF_SCANOUT2) {
283 VhostUserGpuDMABUFScanout2 *m2 = &msg->payload.dmabuf_scanout2;
284 dmabuf->modifier = m2->modifier;
285 }
286
267f6646
MAL
287 dpy_gl_scanout_dmabuf(con, dmabuf);
288 break;
289 }
290 case VHOST_USER_GPU_DMABUF_UPDATE: {
291 VhostUserGpuUpdate *m = &msg->payload.update;
292
293 if (m->scanout_id >= g->parent_obj.conf.max_outputs ||
294 !g->parent_obj.scanout[m->scanout_id].con) {
295 error_report("invalid scanout update: %d", m->scanout_id);
296 vhost_user_gpu_unblock(g);
297 break;
298 }
299
300 con = g->parent_obj.scanout[m->scanout_id].con;
301 if (!console_has_gl(con)) {
302 error_report("console doesn't support GL!");
303 vhost_user_gpu_unblock(g);
304 break;
305 }
267f6646 306 g->backend_blocked = true;
f6413cbf 307 dpy_gl_update(con, m->x, m->y, m->width, m->height);
267f6646
MAL
308 break;
309 }
310 case VHOST_USER_GPU_UPDATE: {
311 VhostUserGpuUpdate *m = &msg->payload.update;
312
313 if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
314 break;
315 }
316 s = &g->parent_obj.scanout[m->scanout_id];
317 con = s->con;
318 pixman_image_t *image =
319 pixman_image_create_bits(PIXMAN_x8r8g8b8,
320 m->width,
321 m->height,
322 (uint32_t *)m->data,
323 m->width * 4);
324
325 pixman_image_composite(PIXMAN_OP_SRC,
326 image, NULL, s->ds->image,
327 0, 0, 0, 0, m->x, m->y, m->width, m->height);
328
329 pixman_image_unref(image);
330 if (qemu_console_surface(con) != s->ds) {
331 dpy_gfx_replace_surface(con, s->ds);
332 } else {
333 dpy_gfx_update(con, m->x, m->y, m->width, m->height);
334 }
335 break;
336 }
337 default:
338 g_warning("unhandled message %d %d", msg->request, msg->size);
339 }
340
341 if (con && qemu_console_is_gl_blocked(con)) {
342 vhost_user_gpu_update_blocked(g, true);
343 }
344}
345
346static void
347vhost_user_gpu_chr_read(void *opaque)
348{
349 VhostUserGPU *g = opaque;
350 VhostUserGpuMsg *msg = NULL;
351 VhostUserGpuRequest request;
352 uint32_t size, flags;
353 int r;
354
355 r = qemu_chr_fe_read_all(&g->vhost_chr,
356 (uint8_t *)&request, sizeof(uint32_t));
357 if (r != sizeof(uint32_t)) {
358 error_report("failed to read msg header: %d, %d", r, errno);
359 goto end;
360 }
361
362 r = qemu_chr_fe_read_all(&g->vhost_chr,
363 (uint8_t *)&flags, sizeof(uint32_t));
364 if (r != sizeof(uint32_t)) {
365 error_report("failed to read msg flags");
366 goto end;
367 }
368
369 r = qemu_chr_fe_read_all(&g->vhost_chr,
370 (uint8_t *)&size, sizeof(uint32_t));
371 if (r != sizeof(uint32_t)) {
372 error_report("failed to read msg size");
373 goto end;
374 }
375
376 msg = g_malloc(VHOST_USER_GPU_HDR_SIZE + size);
267f6646
MAL
377
378 r = qemu_chr_fe_read_all(&g->vhost_chr,
379 (uint8_t *)&msg->payload, size);
380 if (r != size) {
381 error_report("failed to read msg payload %d != %d", r, size);
382 goto end;
383 }
384
385 msg->request = request;
386 msg->flags = size;
387 msg->size = size;
388
389 if (request == VHOST_USER_GPU_CURSOR_UPDATE ||
390 request == VHOST_USER_GPU_CURSOR_POS ||
391 request == VHOST_USER_GPU_CURSOR_POS_HIDE) {
392 vhost_user_gpu_handle_cursor(g, msg);
393 } else {
394 vhost_user_gpu_handle_display(g, msg);
395 }
396
397end:
398 g_free(msg);
399}
400
401static void
402vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked)
403{
404 qemu_set_fd_handler(g->vhost_gpu_fd,
405 blocked ? NULL : vhost_user_gpu_chr_read, NULL, g);
406}
407
408static void
3cddb8b9 409vhost_user_gpu_gl_flushed(VirtIOGPUBase *b)
267f6646
MAL
410{
411 VhostUserGPU *g = VHOST_USER_GPU(b);
412
413 if (g->backend_blocked) {
7d5b0d68 414 vhost_user_gpu_unblock(g);
267f6646
MAL
415 g->backend_blocked = false;
416 }
417
7d5b0d68 418 vhost_user_gpu_update_blocked(g, false);
267f6646
MAL
419}
420
421static bool
422vhost_user_gpu_do_set_socket(VhostUserGPU *g, Error **errp)
423{
424 Chardev *chr;
425 int sv[2];
426
9cbda7b3 427 if (qemu_socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
267f6646
MAL
428 error_setg_errno(errp, errno, "socketpair() failed");
429 return false;
430 }
431
432 chr = CHARDEV(object_new(TYPE_CHARDEV_SOCKET));
433 if (!chr || qemu_chr_add_client(chr, sv[0]) == -1) {
434 error_setg(errp, "Failed to make socket chardev");
435 goto err;
436 }
437 if (!qemu_chr_fe_init(&g->vhost_chr, chr, errp)) {
438 goto err;
439 }
440 if (vhost_user_gpu_set_socket(&g->vhost->dev, sv[1]) < 0) {
441 error_setg(errp, "Failed to set vhost-user-gpu socket");
442 qemu_chr_fe_deinit(&g->vhost_chr, false);
443 goto err;
444 }
445
446 g->vhost_gpu_fd = sv[0];
447 vhost_user_gpu_update_blocked(g, false);
448 close(sv[1]);
449 return true;
450
451err:
452 close(sv[0]);
453 close(sv[1]);
454 if (chr) {
455 object_unref(OBJECT(chr));
456 }
457 return false;
458}
459
460static void
461vhost_user_gpu_get_config(VirtIODevice *vdev, uint8_t *config_data)
462{
463 VhostUserGPU *g = VHOST_USER_GPU(vdev);
464 VirtIOGPUBase *b = VIRTIO_GPU_BASE(vdev);
465 struct virtio_gpu_config *vgconfig =
466 (struct virtio_gpu_config *)config_data;
50de5138 467 Error *local_err = NULL;
267f6646
MAL
468 int ret;
469
470 memset(config_data, 0, sizeof(struct virtio_gpu_config));
471
472 ret = vhost_dev_get_config(&g->vhost->dev,
50de5138
KW
473 config_data, sizeof(struct virtio_gpu_config),
474 &local_err);
267f6646 475 if (ret) {
50de5138 476 error_report_err(local_err);
267f6646
MAL
477 return;
478 }
479
480 /* those fields are managed by qemu */
481 vgconfig->num_scanouts = b->virtio_config.num_scanouts;
482 vgconfig->events_read = b->virtio_config.events_read;
483 vgconfig->events_clear = b->virtio_config.events_clear;
484}
485
486static void
487vhost_user_gpu_set_config(VirtIODevice *vdev,
488 const uint8_t *config_data)
489{
490 VhostUserGPU *g = VHOST_USER_GPU(vdev);
491 VirtIOGPUBase *b = VIRTIO_GPU_BASE(vdev);
492 const struct virtio_gpu_config *vgconfig =
493 (const struct virtio_gpu_config *)config_data;
494 int ret;
495
496 if (vgconfig->events_clear) {
497 b->virtio_config.events_read &= ~vgconfig->events_clear;
498 }
499
500 ret = vhost_dev_set_config(&g->vhost->dev, config_data,
501 0, sizeof(struct virtio_gpu_config),
f8ed3648 502 VHOST_SET_CONFIG_TYPE_FRONTEND);
267f6646
MAL
503 if (ret) {
504 error_report("vhost-user-gpu: set device config space failed");
505 return;
506 }
507}
508
509static void
510vhost_user_gpu_set_status(VirtIODevice *vdev, uint8_t val)
511{
512 VhostUserGPU *g = VHOST_USER_GPU(vdev);
513 Error *err = NULL;
514
515 if (val & VIRTIO_CONFIG_S_DRIVER_OK && vdev->vm_running) {
516 if (!vhost_user_gpu_do_set_socket(g, &err)) {
517 error_report_err(err);
518 return;
519 }
520 vhost_user_backend_start(g->vhost);
521 } else {
522 /* unblock any wait and stop processing */
523 if (g->vhost_gpu_fd != -1) {
524 vhost_user_gpu_update_blocked(g, true);
525 qemu_chr_fe_deinit(&g->vhost_chr, true);
526 g->vhost_gpu_fd = -1;
527 }
528 vhost_user_backend_stop(g->vhost);
529 }
530}
531
532static bool
533vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx)
534{
535 VhostUserGPU *g = VHOST_USER_GPU(vdev);
536
544f0278
CL
537 /*
538 * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1
7e8094f0 539 * as the macro of configure interrupt's IDX, If this driver does not
544f0278
CL
540 * support, the function will return
541 */
542
543 if (idx == VIRTIO_CONFIG_IRQ_IDX) {
544 return false;
545 }
267f6646
MAL
546 return vhost_virtqueue_pending(&g->vhost->dev, idx);
547}
548
549static void
550vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask)
551{
552 VhostUserGPU *g = VHOST_USER_GPU(vdev);
553
544f0278
CL
554 /*
555 * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1
7e8094f0 556 * as the macro of configure interrupt's IDX, If this driver does not
544f0278
CL
557 * support, the function will return
558 */
559
560 if (idx == VIRTIO_CONFIG_IRQ_IDX) {
561 return;
562 }
267f6646
MAL
563 vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask);
564}
565
566static void
567vhost_user_gpu_instance_init(Object *obj)
568{
569 VhostUserGPU *g = VHOST_USER_GPU(obj);
570
571 g->vhost = VHOST_USER_BACKEND(object_new(TYPE_VHOST_USER_BACKEND));
572 object_property_add_alias(obj, "chardev",
d2623129 573 OBJECT(g->vhost), "chardev");
267f6646
MAL
574}
575
576static void
577vhost_user_gpu_instance_finalize(Object *obj)
578{
579 VhostUserGPU *g = VHOST_USER_GPU(obj);
580
581 object_unref(OBJECT(g->vhost));
582}
583
584static void
585vhost_user_gpu_reset(VirtIODevice *vdev)
586{
587 VhostUserGPU *g = VHOST_USER_GPU(vdev);
588
589 virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev));
590
591 vhost_user_backend_stop(g->vhost);
592}
593
594static int
595vhost_user_gpu_config_change(struct vhost_dev *dev)
596{
597 error_report("vhost-user-gpu: unhandled backend config change");
598 return -1;
599}
600
601static const VhostDevConfigOps config_ops = {
602 .vhost_dev_config_notifier = vhost_user_gpu_config_change,
603};
604
605static void
606vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
607{
608 VhostUserGPU *g = VHOST_USER_GPU(qdev);
609 VirtIODevice *vdev = VIRTIO_DEVICE(g);
610
611 vhost_dev_set_config_notifier(&g->vhost->dev, &config_ops);
612 if (vhost_user_backend_dev_init(g->vhost, vdev, 2, errp) < 0) {
613 return;
614 }
615
ff64d44f
MAL
616 /* existing backend may send DMABUF, so let's add that requirement */
617 g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_DMABUF_ENABLED;
267f6646
MAL
618 if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_VIRGL)) {
619 g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED;
620 }
326a51f3
MAL
621 if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_EDID)) {
622 g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_EDID_ENABLED;
623 } else {
624 error_report("EDID requested but the backend doesn't support it.");
625 g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_EDID_ENABLED);
626 }
267f6646
MAL
627
628 if (!virtio_gpu_base_device_realize(qdev, NULL, NULL, errp)) {
629 return;
630 }
631
632 g->vhost_gpu_fd = -1;
633}
634
c255488d
JP
635static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev)
636{
637 VhostUserGPU *g = VHOST_USER_GPU(vdev);
638 return &g->vhost->dev;
639}
640
267f6646
MAL
641static Property vhost_user_gpu_properties[] = {
642 VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf),
643 DEFINE_PROP_END_OF_LIST(),
644};
645
646static void
647vhost_user_gpu_class_init(ObjectClass *klass, void *data)
648{
649 DeviceClass *dc = DEVICE_CLASS(klass);
650 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
651 VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass);
652
3cddb8b9 653 vgc->gl_flushed = vhost_user_gpu_gl_flushed;
267f6646
MAL
654
655 vdc->realize = vhost_user_gpu_device_realize;
656 vdc->reset = vhost_user_gpu_reset;
657 vdc->set_status = vhost_user_gpu_set_status;
658 vdc->guest_notifier_mask = vhost_user_gpu_guest_notifier_mask;
659 vdc->guest_notifier_pending = vhost_user_gpu_guest_notifier_pending;
660 vdc->get_config = vhost_user_gpu_get_config;
661 vdc->set_config = vhost_user_gpu_set_config;
c255488d 662 vdc->get_vhost = vhost_user_gpu_get_vhost;
267f6646 663
4f67d30b 664 device_class_set_props(dc, vhost_user_gpu_properties);
267f6646
MAL
665}
666
667static const TypeInfo vhost_user_gpu_info = {
668 .name = TYPE_VHOST_USER_GPU,
669 .parent = TYPE_VIRTIO_GPU_BASE,
670 .instance_size = sizeof(VhostUserGPU),
671 .instance_init = vhost_user_gpu_instance_init,
672 .instance_finalize = vhost_user_gpu_instance_finalize,
673 .class_init = vhost_user_gpu_class_init,
674};
561d0f45 675module_obj(TYPE_VHOST_USER_GPU);
24ce7aa7 676module_kconfig(VHOST_USER_GPU);
267f6646
MAL
677
678static void vhost_user_gpu_register_types(void)
679{
680 type_register_static(&vhost_user_gpu_info);
681}
682
683type_init(vhost_user_gpu_register_types)