MAINTAINERS: add Kevin Wolf as storage daemon maintainer
[qemu/kevin.git] / contrib / vhost-user-gpu / vugbm.c
blobf5304ada2f1be5fe8f9e3e02821e92585b172183
1 /*
2 * Virtio vhost-user GPU Device
4 * DRM helpers
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 */
10 #include "qemu/osdep.h"
11 #include "vugbm.h"
13 static bool
14 mem_alloc_bo(struct vugbm_buffer *buf)
16 buf->mmap = g_malloc(buf->width * buf->height * 4);
17 buf->stride = buf->width * 4;
18 return true;
21 static void
22 mem_free_bo(struct vugbm_buffer *buf)
24 g_free(buf->mmap);
27 static bool
28 mem_map_bo(struct vugbm_buffer *buf)
30 return buf->mmap != NULL;
33 static void
34 mem_unmap_bo(struct vugbm_buffer *buf)
38 static void
39 mem_device_destroy(struct vugbm_device *dev)
43 #ifdef CONFIG_MEMFD
44 struct udmabuf_create {
45 uint32_t memfd;
46 uint32_t flags;
47 uint64_t offset;
48 uint64_t size;
51 #define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create)
53 static size_t
54 udmabuf_get_size(struct vugbm_buffer *buf)
56 return ROUND_UP(buf->width * buf->height * 4, qemu_real_host_page_size);
59 static bool
60 udmabuf_alloc_bo(struct vugbm_buffer *buf)
62 int ret;
64 buf->memfd = memfd_create("udmabuf-bo", MFD_ALLOW_SEALING);
65 if (buf->memfd < 0) {
66 return false;
69 ret = ftruncate(buf->memfd, udmabuf_get_size(buf));
70 if (ret < 0) {
71 close(buf->memfd);
72 return false;
75 ret = fcntl(buf->memfd, F_ADD_SEALS, F_SEAL_SHRINK);
76 if (ret < 0) {
77 close(buf->memfd);
78 return false;
81 buf->stride = buf->width * 4;
83 return true;
86 static void
87 udmabuf_free_bo(struct vugbm_buffer *buf)
89 close(buf->memfd);
92 static bool
93 udmabuf_map_bo(struct vugbm_buffer *buf)
95 buf->mmap = mmap(NULL, udmabuf_get_size(buf),
96 PROT_READ | PROT_WRITE, MAP_SHARED, buf->memfd, 0);
97 if (buf->mmap == MAP_FAILED) {
98 return false;
101 return true;
104 static bool
105 udmabuf_get_fd(struct vugbm_buffer *buf, int *fd)
107 struct udmabuf_create create = {
108 .memfd = buf->memfd,
109 .offset = 0,
110 .size = udmabuf_get_size(buf),
113 *fd = ioctl(buf->dev->fd, UDMABUF_CREATE, &create);
115 return *fd >= 0;
118 static void
119 udmabuf_unmap_bo(struct vugbm_buffer *buf)
121 munmap(buf->mmap, udmabuf_get_size(buf));
124 static void
125 udmabuf_device_destroy(struct vugbm_device *dev)
127 close(dev->fd);
129 #endif
131 #ifdef CONFIG_GBM
132 static bool
133 alloc_bo(struct vugbm_buffer *buf)
135 struct gbm_device *dev = buf->dev->dev;
137 assert(!buf->bo);
139 buf->bo = gbm_bo_create(dev, buf->width, buf->height,
140 buf->format,
141 GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
143 if (buf->bo) {
144 buf->stride = gbm_bo_get_stride(buf->bo);
145 return true;
148 return false;
151 static void
152 free_bo(struct vugbm_buffer *buf)
154 gbm_bo_destroy(buf->bo);
157 static bool
158 map_bo(struct vugbm_buffer *buf)
160 uint32_t stride;
162 buf->mmap = gbm_bo_map(buf->bo, 0, 0, buf->width, buf->height,
163 GBM_BO_TRANSFER_READ_WRITE, &stride,
164 &buf->mmap_data);
166 assert(stride == buf->stride);
168 return buf->mmap != NULL;
171 static void
172 unmap_bo(struct vugbm_buffer *buf)
174 gbm_bo_unmap(buf->bo, buf->mmap_data);
177 static bool
178 get_fd(struct vugbm_buffer *buf, int *fd)
180 *fd = gbm_bo_get_fd(buf->bo);
182 return *fd >= 0;
185 static void
186 device_destroy(struct vugbm_device *dev)
188 gbm_device_destroy(dev->dev);
190 #endif
192 void
193 vugbm_device_destroy(struct vugbm_device *dev)
195 if (!dev->inited) {
196 return;
199 dev->device_destroy(dev);
202 bool
203 vugbm_device_init(struct vugbm_device *dev, int fd)
205 dev->fd = fd;
207 #ifdef CONFIG_GBM
208 dev->dev = gbm_create_device(fd);
209 #endif
211 if (0) {
212 /* nothing */
214 #ifdef CONFIG_GBM
215 else if (dev->dev != NULL) {
216 dev->alloc_bo = alloc_bo;
217 dev->free_bo = free_bo;
218 dev->get_fd = get_fd;
219 dev->map_bo = map_bo;
220 dev->unmap_bo = unmap_bo;
221 dev->device_destroy = device_destroy;
223 #endif
224 #ifdef CONFIG_MEMFD
225 else if (g_file_test("/dev/udmabuf", G_FILE_TEST_EXISTS)) {
226 dev->fd = open("/dev/udmabuf", O_RDWR);
227 if (dev->fd < 0) {
228 return false;
230 g_debug("Using experimental udmabuf backend");
231 dev->alloc_bo = udmabuf_alloc_bo;
232 dev->free_bo = udmabuf_free_bo;
233 dev->get_fd = udmabuf_get_fd;
234 dev->map_bo = udmabuf_map_bo;
235 dev->unmap_bo = udmabuf_unmap_bo;
236 dev->device_destroy = udmabuf_device_destroy;
238 #endif
239 else {
240 g_debug("Using mem fallback");
241 dev->alloc_bo = mem_alloc_bo;
242 dev->free_bo = mem_free_bo;
243 dev->map_bo = mem_map_bo;
244 dev->unmap_bo = mem_unmap_bo;
245 dev->device_destroy = mem_device_destroy;
246 return false;
249 dev->inited = true;
250 return true;
253 static bool
254 vugbm_buffer_map(struct vugbm_buffer *buf)
256 struct vugbm_device *dev = buf->dev;
258 return dev->map_bo(buf);
261 static void
262 vugbm_buffer_unmap(struct vugbm_buffer *buf)
264 struct vugbm_device *dev = buf->dev;
266 dev->unmap_bo(buf);
269 bool
270 vugbm_buffer_can_get_dmabuf_fd(struct vugbm_buffer *buffer)
272 if (!buffer->dev->get_fd) {
273 return false;
276 return true;
279 bool
280 vugbm_buffer_get_dmabuf_fd(struct vugbm_buffer *buffer, int *fd)
282 if (!vugbm_buffer_can_get_dmabuf_fd(buffer) ||
283 !buffer->dev->get_fd(buffer, fd)) {
284 g_warning("Failed to get dmabuf");
285 return false;
288 if (*fd < 0) {
289 g_warning("error: dmabuf_fd < 0");
290 return false;
293 return true;
296 bool
297 vugbm_buffer_create(struct vugbm_buffer *buffer, struct vugbm_device *dev,
298 uint32_t width, uint32_t height)
300 buffer->dev = dev;
301 buffer->width = width;
302 buffer->height = height;
303 buffer->format = GBM_FORMAT_XRGB8888;
304 buffer->stride = 0; /* modified during alloc */
305 if (!dev->alloc_bo(buffer)) {
306 g_warning("alloc_bo failed");
307 return false;
310 if (!vugbm_buffer_map(buffer)) {
311 g_warning("map_bo failed");
312 goto err;
315 return true;
317 err:
318 dev->free_bo(buffer);
319 return false;
322 void
323 vugbm_buffer_destroy(struct vugbm_buffer *buffer)
325 struct vugbm_device *dev = buffer->dev;
327 vugbm_buffer_unmap(buffer);
328 dev->free_bo(buffer);