hw/loongarch: Remove unimplemented extioi INT_encode mode
[qemu/ar7.git] / hw / display / virtio-gpu-udmabuf.c
blobc02ec6d37dc4b897d90a10f5f612d5c219b84f0d
1 /*
2 * Virtio GPU Device
4 * Copyright Red Hat, Inc. 2013-2014
6 * Authors:
7 * Dave Airlie <airlied@redhat.com>
8 * Gerd Hoffmann <kraxel@redhat.com>
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.
14 #include "qemu/osdep.h"
15 #include "qemu/error-report.h"
16 #include "qemu/units.h"
17 #include "qemu/iov.h"
18 #include "ui/console.h"
19 #include "hw/virtio/virtio-gpu.h"
20 #include "hw/virtio/virtio-gpu-pixman.h"
21 #include "trace.h"
22 #include "exec/ramblock.h"
23 #include "sysemu/hostmem.h"
24 #include <sys/ioctl.h>
25 #include <linux/memfd.h>
26 #include "qemu/memfd.h"
27 #include "standard-headers/linux/udmabuf.h"
29 static void virtio_gpu_create_udmabuf(struct virtio_gpu_simple_resource *res)
31 struct udmabuf_create_list *list;
32 RAMBlock *rb;
33 ram_addr_t offset;
34 int udmabuf, i;
36 udmabuf = udmabuf_fd();
37 if (udmabuf < 0) {
38 return;
41 list = g_malloc0(sizeof(struct udmabuf_create_list) +
42 sizeof(struct udmabuf_create_item) * res->iov_cnt);
44 for (i = 0; i < res->iov_cnt; i++) {
45 rcu_read_lock();
46 rb = qemu_ram_block_from_host(res->iov[i].iov_base, false, &offset);
47 rcu_read_unlock();
49 if (!rb || rb->fd < 0) {
50 g_free(list);
51 return;
54 list->list[i].memfd = rb->fd;
55 list->list[i].offset = offset;
56 list->list[i].size = res->iov[i].iov_len;
59 list->count = res->iov_cnt;
60 list->flags = UDMABUF_FLAGS_CLOEXEC;
62 res->dmabuf_fd = ioctl(udmabuf, UDMABUF_CREATE_LIST, list);
63 if (res->dmabuf_fd < 0) {
64 warn_report("%s: UDMABUF_CREATE_LIST: %s", __func__,
65 strerror(errno));
67 g_free(list);
70 static void virtio_gpu_remap_udmabuf(struct virtio_gpu_simple_resource *res)
72 res->remapped = mmap(NULL, res->blob_size, PROT_READ,
73 MAP_SHARED, res->dmabuf_fd, 0);
74 if (res->remapped == MAP_FAILED) {
75 warn_report("%s: dmabuf mmap failed: %s", __func__,
76 strerror(errno));
77 res->remapped = NULL;
81 static void virtio_gpu_destroy_udmabuf(struct virtio_gpu_simple_resource *res)
83 if (res->remapped) {
84 munmap(res->remapped, res->blob_size);
85 res->remapped = NULL;
87 if (res->dmabuf_fd >= 0) {
88 close(res->dmabuf_fd);
89 res->dmabuf_fd = -1;
93 static int find_memory_backend_type(Object *obj, void *opaque)
95 bool *memfd_backend = opaque;
96 int ret;
98 if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
99 HostMemoryBackend *backend = MEMORY_BACKEND(obj);
100 RAMBlock *rb = backend->mr.ram_block;
102 if (rb && rb->fd > 0) {
103 ret = fcntl(rb->fd, F_GET_SEALS);
104 if (ret > 0) {
105 *memfd_backend = true;
110 return 0;
113 bool virtio_gpu_have_udmabuf(void)
115 Object *memdev_root;
116 int udmabuf;
117 bool memfd_backend = false;
119 udmabuf = udmabuf_fd();
120 if (udmabuf < 0) {
121 return false;
124 memdev_root = object_resolve_path("/objects", NULL);
125 object_child_foreach(memdev_root, find_memory_backend_type, &memfd_backend);
127 return memfd_backend;
130 void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res)
132 void *pdata = NULL;
134 res->dmabuf_fd = -1;
135 if (res->iov_cnt == 1 &&
136 res->iov[0].iov_len < 4096) {
137 pdata = res->iov[0].iov_base;
138 } else {
139 virtio_gpu_create_udmabuf(res);
140 if (res->dmabuf_fd < 0) {
141 return;
143 virtio_gpu_remap_udmabuf(res);
144 if (!res->remapped) {
145 return;
147 pdata = res->remapped;
150 res->blob = pdata;
153 void virtio_gpu_fini_udmabuf(struct virtio_gpu_simple_resource *res)
155 if (res->remapped) {
156 virtio_gpu_destroy_udmabuf(res);
160 static void virtio_gpu_free_dmabuf(VirtIOGPU *g, VGPUDMABuf *dmabuf)
162 struct virtio_gpu_scanout *scanout;
164 scanout = &g->parent_obj.scanout[dmabuf->scanout_id];
165 dpy_gl_release_dmabuf(scanout->con, dmabuf->buf);
166 g_clear_pointer(&dmabuf->buf, qemu_dmabuf_free);
167 QTAILQ_REMOVE(&g->dmabuf.bufs, dmabuf, next);
168 g_free(dmabuf);
171 static VGPUDMABuf
172 *virtio_gpu_create_dmabuf(VirtIOGPU *g,
173 uint32_t scanout_id,
174 struct virtio_gpu_simple_resource *res,
175 struct virtio_gpu_framebuffer *fb,
176 struct virtio_gpu_rect *r)
178 VGPUDMABuf *dmabuf;
180 if (res->dmabuf_fd < 0) {
181 return NULL;
184 dmabuf = g_new0(VGPUDMABuf, 1);
185 dmabuf->buf = qemu_dmabuf_new(r->width, r->height, fb->stride,
186 r->x, r->y, fb->width, fb->height,
187 qemu_pixman_to_drm_format(fb->format),
188 0, res->dmabuf_fd, true, false);
189 dmabuf->scanout_id = scanout_id;
190 QTAILQ_INSERT_HEAD(&g->dmabuf.bufs, dmabuf, next);
192 return dmabuf;
195 int virtio_gpu_update_dmabuf(VirtIOGPU *g,
196 uint32_t scanout_id,
197 struct virtio_gpu_simple_resource *res,
198 struct virtio_gpu_framebuffer *fb,
199 struct virtio_gpu_rect *r)
201 struct virtio_gpu_scanout *scanout = &g->parent_obj.scanout[scanout_id];
202 VGPUDMABuf *new_primary, *old_primary = NULL;
203 uint32_t width, height;
205 new_primary = virtio_gpu_create_dmabuf(g, scanout_id, res, fb, r);
206 if (!new_primary) {
207 return -EINVAL;
210 if (g->dmabuf.primary[scanout_id]) {
211 old_primary = g->dmabuf.primary[scanout_id];
214 width = qemu_dmabuf_get_width(new_primary->buf);
215 height = qemu_dmabuf_get_height(new_primary->buf);
216 g->dmabuf.primary[scanout_id] = new_primary;
217 qemu_console_resize(scanout->con, width, height);
218 dpy_gl_scanout_dmabuf(scanout->con, new_primary->buf);
220 if (old_primary) {
221 virtio_gpu_free_dmabuf(g, old_primary);
224 return 0;