mirror of
				https://github.com/qemu/qemu.git
				synced 2025-10-31 20:44:16 +00:00 
			
		
		
		
	 8e3b0cbb72
			
		
	
	
		8e3b0cbb72
		
	
	
	
	
		
			
			Replace the global variables with inlined helper functions. getpagesize() is very likely annotated with a "const" function attribute (at least with glibc), and thus optimization should apply even better. This avoids the need for a constructor initialization too. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20220323155743.1585078-12-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
		
			
				
	
	
		
			326 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Virtio vhost-user GPU Device
 | |
|  *
 | |
|  * DRM helpers
 | |
|  *
 | |
|  * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | |
|  * See the COPYING file in the top-level directory.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "vugbm.h"
 | |
| 
 | |
| static bool
 | |
| mem_alloc_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     buf->mmap = g_malloc(buf->width * buf->height * 4);
 | |
|     buf->stride = buf->width * 4;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| static void
 | |
| mem_free_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     g_free(buf->mmap);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| mem_map_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     return buf->mmap != NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| mem_unmap_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| mem_device_destroy(struct vugbm_device *dev)
 | |
| {
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_MEMFD
 | |
| struct udmabuf_create {
 | |
|         uint32_t memfd;
 | |
|         uint32_t flags;
 | |
|         uint64_t offset;
 | |
|         uint64_t size;
 | |
| };
 | |
| 
 | |
| #define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create)
 | |
| 
 | |
| static size_t
 | |
| udmabuf_get_size(struct vugbm_buffer *buf)
 | |
| {
 | |
|     return ROUND_UP(buf->width * buf->height * 4, qemu_real_host_page_size());
 | |
| }
 | |
| 
 | |
| static bool
 | |
| udmabuf_alloc_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     int ret;
 | |
| 
 | |
|     buf->memfd = memfd_create("udmabuf-bo", MFD_ALLOW_SEALING);
 | |
|     if (buf->memfd < 0) {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     ret = ftruncate(buf->memfd, udmabuf_get_size(buf));
 | |
|     if (ret < 0) {
 | |
|         close(buf->memfd);
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     ret = fcntl(buf->memfd, F_ADD_SEALS, F_SEAL_SHRINK);
 | |
|     if (ret < 0) {
 | |
|         close(buf->memfd);
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     buf->stride = buf->width * 4;
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| static void
 | |
| udmabuf_free_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     close(buf->memfd);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| udmabuf_map_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     buf->mmap = mmap(NULL, udmabuf_get_size(buf),
 | |
|                      PROT_READ | PROT_WRITE, MAP_SHARED, buf->memfd, 0);
 | |
|     if (buf->mmap == MAP_FAILED) {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| udmabuf_get_fd(struct vugbm_buffer *buf, int *fd)
 | |
| {
 | |
|     struct udmabuf_create create = {
 | |
|         .memfd = buf->memfd,
 | |
|         .offset = 0,
 | |
|         .size = udmabuf_get_size(buf),
 | |
|     };
 | |
| 
 | |
|     *fd = ioctl(buf->dev->fd, UDMABUF_CREATE, &create);
 | |
| 
 | |
|     return *fd >= 0;
 | |
| }
 | |
| 
 | |
| static void
 | |
| udmabuf_unmap_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     munmap(buf->mmap, udmabuf_get_size(buf));
 | |
| }
 | |
| 
 | |
| static void
 | |
| udmabuf_device_destroy(struct vugbm_device *dev)
 | |
| {
 | |
|     close(dev->fd);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef CONFIG_GBM
 | |
| static bool
 | |
| alloc_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     struct gbm_device *dev = buf->dev->dev;
 | |
| 
 | |
|     assert(!buf->bo);
 | |
| 
 | |
|     buf->bo = gbm_bo_create(dev, buf->width, buf->height,
 | |
|                             buf->format,
 | |
|                             GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
 | |
| 
 | |
|     if (buf->bo) {
 | |
|         buf->stride = gbm_bo_get_stride(buf->bo);
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| static void
 | |
| free_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     gbm_bo_destroy(buf->bo);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| map_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     uint32_t stride;
 | |
| 
 | |
|     buf->mmap = gbm_bo_map(buf->bo, 0, 0, buf->width, buf->height,
 | |
|                            GBM_BO_TRANSFER_READ_WRITE, &stride,
 | |
|                            &buf->mmap_data);
 | |
| 
 | |
|     assert(stride == buf->stride);
 | |
| 
 | |
|     return buf->mmap != NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| unmap_bo(struct vugbm_buffer *buf)
 | |
| {
 | |
|     gbm_bo_unmap(buf->bo, buf->mmap_data);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| get_fd(struct vugbm_buffer *buf, int *fd)
 | |
| {
 | |
|     *fd = gbm_bo_get_fd(buf->bo);
 | |
| 
 | |
|     return *fd >= 0;
 | |
| }
 | |
| 
 | |
| static void
 | |
| device_destroy(struct vugbm_device *dev)
 | |
| {
 | |
|     gbm_device_destroy(dev->dev);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void
 | |
| vugbm_device_destroy(struct vugbm_device *dev)
 | |
| {
 | |
|     if (!dev->inited) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     dev->device_destroy(dev);
 | |
| }
 | |
| 
 | |
| void
 | |
| vugbm_device_init(struct vugbm_device *dev, int fd)
 | |
| {
 | |
|     assert(!dev->inited);
 | |
| 
 | |
| #ifdef CONFIG_GBM
 | |
|     if (fd >= 0) {
 | |
|         dev->dev = gbm_create_device(fd);
 | |
|     }
 | |
|     if (dev->dev != NULL) {
 | |
|         dev->fd = fd;
 | |
|         dev->alloc_bo = alloc_bo;
 | |
|         dev->free_bo = free_bo;
 | |
|         dev->get_fd = get_fd;
 | |
|         dev->map_bo = map_bo;
 | |
|         dev->unmap_bo = unmap_bo;
 | |
|         dev->device_destroy = device_destroy;
 | |
|         dev->inited = true;
 | |
|     }
 | |
| #endif
 | |
| #ifdef CONFIG_MEMFD
 | |
|     if (!dev->inited && g_file_test("/dev/udmabuf", G_FILE_TEST_EXISTS)) {
 | |
|         dev->fd = open("/dev/udmabuf", O_RDWR);
 | |
|         if (dev->fd >= 0) {
 | |
|             g_debug("Using experimental udmabuf backend");
 | |
|             dev->alloc_bo = udmabuf_alloc_bo;
 | |
|             dev->free_bo = udmabuf_free_bo;
 | |
|             dev->get_fd = udmabuf_get_fd;
 | |
|             dev->map_bo = udmabuf_map_bo;
 | |
|             dev->unmap_bo = udmabuf_unmap_bo;
 | |
|             dev->device_destroy = udmabuf_device_destroy;
 | |
|             dev->inited = true;
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
|     if (!dev->inited) {
 | |
|         g_debug("Using mem fallback");
 | |
|         dev->alloc_bo = mem_alloc_bo;
 | |
|         dev->free_bo = mem_free_bo;
 | |
|         dev->map_bo = mem_map_bo;
 | |
|         dev->unmap_bo = mem_unmap_bo;
 | |
|         dev->device_destroy = mem_device_destroy;
 | |
|         dev->inited = true;
 | |
|     }
 | |
|     assert(dev->inited);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| vugbm_buffer_map(struct vugbm_buffer *buf)
 | |
| {
 | |
|     struct vugbm_device *dev = buf->dev;
 | |
| 
 | |
|     return dev->map_bo(buf);
 | |
| }
 | |
| 
 | |
| static void
 | |
| vugbm_buffer_unmap(struct vugbm_buffer *buf)
 | |
| {
 | |
|     struct vugbm_device *dev = buf->dev;
 | |
| 
 | |
|     dev->unmap_bo(buf);
 | |
| }
 | |
| 
 | |
| bool
 | |
| vugbm_buffer_can_get_dmabuf_fd(struct vugbm_buffer *buffer)
 | |
| {
 | |
|     if (!buffer->dev->get_fd) {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| vugbm_buffer_get_dmabuf_fd(struct vugbm_buffer *buffer, int *fd)
 | |
| {
 | |
|     if (!vugbm_buffer_can_get_dmabuf_fd(buffer) ||
 | |
|         !buffer->dev->get_fd(buffer, fd)) {
 | |
|         g_warning("Failed to get dmabuf");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (*fd < 0) {
 | |
|         g_warning("error: dmabuf_fd < 0");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| vugbm_buffer_create(struct vugbm_buffer *buffer, struct vugbm_device *dev,
 | |
|                     uint32_t width, uint32_t height)
 | |
| {
 | |
|     buffer->dev = dev;
 | |
|     buffer->width = width;
 | |
|     buffer->height = height;
 | |
|     buffer->format = GBM_FORMAT_XRGB8888;
 | |
|     buffer->stride = 0; /* modified during alloc */
 | |
|     if (!dev->alloc_bo(buffer)) {
 | |
|         g_warning("alloc_bo failed");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (!vugbm_buffer_map(buffer)) {
 | |
|         g_warning("map_bo failed");
 | |
|         goto err;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| 
 | |
| err:
 | |
|     dev->free_bo(buffer);
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| void
 | |
| vugbm_buffer_destroy(struct vugbm_buffer *buffer)
 | |
| {
 | |
|     struct vugbm_device *dev = buffer->dev;
 | |
| 
 | |
|     vugbm_buffer_unmap(buffer);
 | |
|     dev->free_bo(buffer);
 | |
| }
 |