llvmpipe: refactor dmabuf and opaque fd handling

This change:
1. add new helpers to handle dmabuf alloc/import/free
2. use FREE to match with alloc macro
3. simplify opaque fd code path

Reviewed-by: Christian Gmeiner <cgmeiner@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38074>
This commit is contained in:
Yiwei Zhang 2025-10-27 01:25:35 -07:00 committed by Marge Bot
parent 4d0fbd1c67
commit e8f66ef197

View file

@ -1383,64 +1383,104 @@ llvmpipe_free_memory(struct pipe_screen *pscreen,
#if defined(HAVE_LIBDRM) && defined(HAVE_LINUX_UDMABUF_H)
static void*
llvmpipe_resource_alloc_udmabuf(struct llvmpipe_screen *screen,
struct llvmpipe_memory_allocation *alloc,
size_t size)
static void
llvmpipe_dmabuf_free(struct llvmpipe_memory_allocation *alloc)
{
assert(alloc->cpu_addr != NULL && alloc->fd >= 0);
munmap(alloc->cpu_addr, alloc->size);
close(alloc->fd);
if (alloc->mem_fd >= 0)
close(alloc->mem_fd);
}
static bool
llvmpipe_dmabuf_import(int fd, struct llvmpipe_memory_allocation *alloc)
{
const off_t size = lseek(fd, 0, SEEK_END);
if (size < 0)
return false;
lseek(fd, 0, SEEK_SET);
void *cpu_addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (cpu_addr == MAP_FAILED)
return false;
*alloc = (struct llvmpipe_memory_allocation){
.fd = fd,
.offset = 0,
.cpu_addr = cpu_addr,
.size = size,
.type = LLVMPIPE_MEMORY_FD_TYPE_DMA_BUF,
.mem_fd = -1,
};
return true;
}
static bool
llvmpipe_dmabuf_alloc(struct llvmpipe_screen *screen,
size_t size,
struct llvmpipe_memory_allocation *alloc)
{
int mem_fd = -1;
int dmabuf_fd = -1;
if (screen->udmabuf_fd != -1) {
uint64_t alignment;
if (!os_get_page_size(&alignment))
alignment = 256;
size = align(size, alignment);
if (screen->udmabuf_fd < 0)
return false;
mem_fd = memfd_create("lp_dma_buf", MFD_ALLOW_SEALING);
if (mem_fd == -1)
goto fail;
uint64_t alignment;
if (!os_get_page_size(&alignment))
alignment = 256;
int res = ftruncate(mem_fd, size);
if (res == -1)
goto fail;
size = align(size, alignment);
/* udmabuf create requires that the memfd have
* have the F_SEAL_SHRINK seal added and must not
* have the F_SEAL_WRITE seal added */
if (fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK) < 0)
goto fail;
mem_fd = memfd_create("lp_dma_buf", MFD_ALLOW_SEALING);
if (mem_fd < 0)
goto fail;
struct udmabuf_create create = {
.memfd = mem_fd,
.flags = UDMABUF_FLAGS_CLOEXEC,
.offset = 0,
.size = size
};
if (ftruncate(mem_fd, size) < 0)
goto fail;
dmabuf_fd = ioctl(screen->udmabuf_fd, UDMABUF_CREATE, &create);
if (dmabuf_fd < 0)
goto fail;
/* udmabuf create requires that the memfd have have the F_SEAL_SHRINK seal
* added and must not have the F_SEAL_WRITE seal added
*/
if (fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK) < 0)
goto fail;
struct pipe_memory_allocation *data =
mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, mem_fd, 0);
if (data == MAP_FAILED)
goto fail;
struct udmabuf_create create = {
.memfd = mem_fd,
.flags = UDMABUF_FLAGS_CLOEXEC,
.offset = 0,
.size = size
};
alloc->mem_fd = mem_fd;
alloc->fd = dmabuf_fd;
alloc->size = size;
return data;
}
dmabuf_fd = ioctl(screen->udmabuf_fd, UDMABUF_CREATE, &create);
if (dmabuf_fd < 0)
goto fail;
void *cpu_addr =
mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, mem_fd, 0);
if (cpu_addr == MAP_FAILED)
goto fail;
*alloc = (struct llvmpipe_memory_allocation){
.fd = dmabuf_fd,
.offset = 0,
.cpu_addr = cpu_addr,
.size = size,
.type = LLVMPIPE_MEMORY_FD_TYPE_DMA_BUF,
.mem_fd = mem_fd,
};
return true;
fail:
if (dmabuf_fd >= 0)
close(dmabuf_fd);
if (mem_fd != -1)
if (mem_fd >= 0)
close(mem_fd);
/* If we don't have access to the udmabuf device
* or something else fails we return NULL */
return NULL;
return false;
}
#endif
@ -1448,56 +1488,53 @@ fail:
static struct pipe_memory_allocation *
llvmpipe_allocate_memory_fd(struct pipe_screen *pscreen,
uint64_t size,
int *fd,
int *out_fd,
bool dmabuf)
{
struct llvmpipe_memory_allocation *alloc = CALLOC_STRUCT(llvmpipe_memory_allocation);
if (!alloc)
goto fail;
return NULL;
alloc->mem_fd = -1;
alloc->fd = -1;
int fd = -1;
#if defined(HAVE_LIBDRM) && defined(HAVE_LINUX_UDMABUF_H)
if (dmabuf) {
struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
alloc->type = LLVMPIPE_MEMORY_FD_TYPE_DMA_BUF;
alloc->cpu_addr = llvmpipe_resource_alloc_udmabuf(screen, alloc, size);
if (!llvmpipe_dmabuf_alloc(screen, size, alloc))
goto fail;
if (alloc->cpu_addr) {
*fd = os_dupfd_cloexec(alloc->fd);
if (*fd < 0) {
close(alloc->mem_fd);
close(alloc->fd);
FREE(alloc);
goto fail;
}
fd = os_dupfd_cloexec(alloc->fd);
if (fd < 0) {
llvmpipe_dmabuf_free(alloc);
goto fail;
}
} else
#endif
{
alloc->type = LLVMPIPE_MEMORY_FD_TYPE_OPAQUE;
uint64_t alignment;
if (!os_get_page_size(&alignment))
alignment = 256;
alloc->cpu_addr = os_malloc_aligned_fd(size, alignment, fd,
uint64_t alignment = 256;
os_get_page_size(&alignment);
alloc->cpu_addr = os_malloc_aligned_fd(size, alignment, &fd,
"llvmpipe memory fd", driver_id);
if (!alloc->cpu_addr)
goto fail;
alloc->fd = -1;
alloc->type = LLVMPIPE_MEMORY_FD_TYPE_OPAQUE;
}
if(alloc && !alloc->cpu_addr) {
free(alloc);
alloc = NULL;
}
*out_fd = fd;
return (struct pipe_memory_allocation*)alloc;
fail:
return (struct pipe_memory_allocation*)alloc;
FREE(alloc);
return NULL;
}
static bool
llvmpipe_import_memory_fd(struct pipe_screen *screen,
int fd,
struct pipe_memory_allocation **ptr,
uint64_t *size,
struct pipe_memory_allocation **out_ptr,
uint64_t *out_size,
bool dmabuf)
{
struct llvmpipe_memory_allocation *alloc = CALLOC_STRUCT(llvmpipe_memory_allocation);
@ -1508,52 +1545,31 @@ llvmpipe_import_memory_fd(struct pipe_screen *screen,
alloc->fd = -1;
#if defined(HAVE_LIBDRM) && defined(HAVE_LINUX_UDMABUF_H)
if (dmabuf) {
off_t mmap_size = lseek(fd, 0, SEEK_END);
if (mmap_size < 0) {
free(alloc);
*ptr = NULL;
return false;
int dup_fd = os_dupfd_cloexec(fd);
if (dup_fd < 0)
goto fail;
if (!llvmpipe_dmabuf_import(dup_fd, alloc)) {
close(dup_fd);
goto fail;
}
lseek(fd, 0, SEEK_SET);
void *cpu_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (cpu_addr == MAP_FAILED) {
free(alloc);
*ptr = NULL;
return false;
}
alloc->type = LLVMPIPE_MEMORY_FD_TYPE_DMA_BUF;
alloc->cpu_addr = cpu_addr;
alloc->size = mmap_size;
alloc->fd = os_dupfd_cloexec(fd);
if (alloc->fd < 0) {
munmap(alloc->cpu_addr, alloc->size);
free(alloc);
*ptr = NULL;
return false;
}
*ptr = (struct pipe_memory_allocation*)alloc;
*size = mmap_size;
return true;
} else
#endif
{
bool ret = os_import_memory_fd(fd, (void**)&alloc->cpu_addr, size, driver_id);
if (!ret) {
free(alloc);
*ptr = NULL;
return false;
} else {
*ptr = (struct pipe_memory_allocation*)alloc;
}
if (!os_import_memory_fd(fd, &alloc->cpu_addr, &alloc->size, driver_id))
goto fail;
alloc->fd = -1;
alloc->type = LLVMPIPE_MEMORY_FD_TYPE_OPAQUE;
return ret;
}
*out_ptr = (struct pipe_memory_allocation*)alloc;
*out_size = alloc->size;
return true;
fail:
FREE(alloc);
return false;
}
@ -1567,15 +1583,11 @@ llvmpipe_free_memory_fd(struct pipe_screen *screen,
}
#if defined(HAVE_LIBDRM) && defined(HAVE_LINUX_UDMABUF_H)
else {
munmap(alloc->cpu_addr, alloc->size);
if (alloc->fd >= 0)
close(alloc->fd);
if (alloc->mem_fd >= 0)
close(alloc->mem_fd);
llvmpipe_dmabuf_free(alloc);
}
#endif
free(alloc);
FREE(alloc);
}
#endif