lavapipe: Always use dma-buf for external memory when we can

This makes lavapipe act like other DRM drivers whenever we have udmabuf
and just make everything a dma-buf even if it doesn't strictly have to
be.  Without this we can end up in weird cases if the client asks to
allocate a memory object with multiple export types.  Before, if this
happened, we would allocate a memfd and then return that when the client
calls GetMemoryFd() even if they asked for a dma-buf.  In theory, we
could add additional plumbing to allow for using the memfd itself for
OPAQUE_FD and only wrap in a udmabuf if DMA_BUF is requested but this is
simpler and more in line with what hardware DRM drivers do.

Fixes: c1657de63c ("lavapipe: support VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT")
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/13798
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37067>
This commit is contained in:
Faith Ekstrand 2025-08-28 11:41:27 -04:00 committed by Marge Bot
parent 16cd5e0244
commit 31f0d0732e

View file

@ -307,6 +307,49 @@ assert_memhandle_type(VkExternalMemoryHandleTypeFlags types)
return types == 0;
}
static enum lvp_device_memory_type
lvp_device_memory_type_for_handle_types(const struct lvp_physical_device *pdevice,
VkExternalMemoryHandleTypeFlags types)
{
if (types == 0)
return LVP_DEVICE_MEMORY_TYPE_DEFAULT;
#ifdef PIPE_MEMORY_FD
if (types & (VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) {
assert(!(types & ~(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)));
#ifdef HAVE_LIBDRM
int dmabuf_bits = DRM_PRIME_CAP_EXPORT | DRM_PRIME_CAP_IMPORT;
if ((pdevice->pscreen->caps.dmabuf & dmabuf_bits) == dmabuf_bits) {
/* If we have full dma-buf support, everything is a dma-buf */
return LVP_DEVICE_MEMORY_TYPE_DMA_BUF;
}
if (types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
/* dma-buf is only supported for import so if we see dma-buf it has
* to come by itself.
*/
assert(types == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
return LVP_DEVICE_MEMORY_TYPE_DMA_BUF;
}
#endif
assert(types == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
return LVP_DEVICE_MEMORY_TYPE_OPAQUE_FD;
}
#endif
if (types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT) {
/* These can only be used for import so it's a single bit */
assert(util_bitcount(types) == 1);
return LVP_DEVICE_MEMORY_TYPE_USER_PTR;
}
UNREACHABLE("Unsupported import/export type");
}
static unsigned min_shader_cap(struct pipe_screen *pscreen,
mesa_shader_stage shader,
unsigned cap_offset)
@ -2006,8 +2049,9 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_AllocateMemory(
else if (mem->vk.import_handle_type) {
assert(import_info &&
import_info->handleType == mem->vk.import_handle_type);
const bool dmabuf = mem->vk.import_handle_type ==
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
const enum lvp_device_memory_type memory_type =
lvp_device_memory_type_for_handle_types(device->physical_device, mem->vk.import_handle_type);
const bool dmabuf = memory_type == LVP_DEVICE_MEMORY_TYPE_DMA_BUF;
uint64_t size;
if(!device->pscreen->import_memory_fd(device->pscreen, import_info->fd, &mem->pmem, &size, dmabuf)) {
error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
@ -2027,18 +2071,19 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_AllocateMemory(
mem->vk.size = size;
mem->map = device->pscreen->map_memory(device->pscreen, mem->pmem);
mem->memory_type = dmabuf ? LVP_DEVICE_MEMORY_TYPE_DMA_BUF : LVP_DEVICE_MEMORY_TYPE_OPAQUE_FD;
mem->memory_type = memory_type;
}
else if (mem->vk.export_handle_types) {
const bool dmabuf = mem->vk.export_handle_types ==
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
const enum lvp_device_memory_type memory_type =
lvp_device_memory_type_for_handle_types(device->physical_device, mem->vk.export_handle_types);
const bool dmabuf = memory_type == LVP_DEVICE_MEMORY_TYPE_DMA_BUF;
mem->pmem = device->pscreen->allocate_memory_fd(device->pscreen, pAllocateInfo->allocationSize, &mem->backed_fd, dmabuf);
if (!mem->pmem || mem->backed_fd < 0) {
goto fail;
}
mem->map = device->pscreen->map_memory(device->pscreen, mem->pmem);
mem->memory_type = dmabuf ? LVP_DEVICE_MEMORY_TYPE_DMA_BUF : LVP_DEVICE_MEMORY_TYPE_OPAQUE_FD;
mem->memory_type = memory_type;
/* XXX: this should be memset_s or memset_explicit but they are not supported */
if (mem_flags && mem_flags->flags & VK_MEMORY_ALLOCATE_ZERO_INITIALIZE_BIT_EXT)
memset(mem->map, 0, pAllocateInfo->allocationSize);