panvk: implement AHB image deferred init and memory alloc

Implement as a layer on top, and can be resilient to core panvk changes
later. e.g. more and strict memory types, need dedicated info, etc.

Acked-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com>
Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36603>
This commit is contained in:
Yiwei Zhang 2025-08-06 09:20:49 +00:00 committed by Marge Bot
parent 33ab9d8320
commit 66bbd9eec8
2 changed files with 217 additions and 0 deletions

View file

@ -7,10 +7,12 @@
#include "panvk_device.h"
#include "vndk/hardware_buffer.h"
#include "vulkan/vk_android_native_buffer.h"
#include "vk_alloc.h"
#include "vk_android.h"
#include "vk_device_memory.h"
#include "vk_util.h"
bool
@ -87,6 +89,8 @@ panvk_android_create_deferred_image(VkDevice device,
/* prepare the deferred VkImageCreateInfo chain */
*create_info = *pCreateInfo;
create_info->pNext = NULL;
/* Assign resolved AHB external format */
create_info->format = deferred->base.vk.format;
create_info->tiling = deferred->base.vk.tiling =
VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) {
@ -176,6 +180,32 @@ panvk_android_get_image_mem_reqs(VkDevice dev_handle, VkImage img_handle,
return VK_SUCCESS;
}
static VkResult
panvk_android_get_buffer_mem_reqs(VkDevice dev_handle, VkBuffer buf_handle,
int dma_buf_fd,
VkMemoryRequirements *out_mem_reqs)
{
VK_FROM_HANDLE(vk_device, dev, dev_handle);
VkMemoryRequirements mem_reqs;
dev->dispatch_table.GetBufferMemoryRequirements(dev_handle, buf_handle,
&mem_reqs);
const uint32_t fd_mem_type_bits =
panvk_android_get_fd_mem_type_bits(dev_handle, dma_buf_fd);
if (!(mem_reqs.memoryTypeBits & fd_mem_type_bits)) {
return panvk_errorf(dev_handle, VK_ERROR_INVALID_EXTERNAL_HANDLE,
"No compatible mem type: buf req (%u), fd req (%u)",
mem_reqs.memoryTypeBits, fd_mem_type_bits);
}
mem_reqs.memoryTypeBits &= fd_mem_type_bits;
*out_mem_reqs = mem_reqs;
return VK_SUCCESS;
}
static VkResult
panvk_android_import_anb_memory(VkDevice dev_handle, VkImage img_handle,
const VkNativeBufferANDROID *anb,
@ -339,3 +369,169 @@ panvk_android_get_wsi_memory(struct panvk_device *dev,
return VK_SUCCESS;
}
static VkResult
panvk_android_ahb_image_init(struct AHardwareBuffer *ahb,
struct panvk_image *img)
{
VkResult result;
struct panvk_android_deferred_image *deferred =
container_of(img, struct panvk_android_deferred_image, base);
assert(deferred->create_info && !deferred->initialized);
VkImageDrmFormatModifierExplicitCreateInfoEXT mod_info;
VkSubresourceLayout layouts[PANVK_MAX_PLANES];
result =
vk_android_get_ahb_layout(ahb, &mod_info, layouts, PANVK_MAX_PLANES);
if (result != VK_SUCCESS)
return result;
__vk_append_struct(deferred->create_info, &mod_info);
VkExternalMemoryImageCreateInfo external_info = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
};
__vk_append_struct(deferred->create_info, &external_info);
result = panvk_image_init(img, deferred->create_info);
if (result != VK_SUCCESS)
return result;
deferred->initialized = true;
return VK_SUCCESS;
}
static VkResult
panvk_android_import_ahb_memory(VkDevice device,
const VkMemoryAllocateInfo *pAllocateInfo,
struct AHardwareBuffer *ahb,
const VkAllocationCallbacks *pAllocator,
VkDeviceMemory *pMemory)
{
VK_FROM_HANDLE(vk_device, dev, device);
const native_handle_t *handle = AHardwareBuffer_getNativeHandle(ahb);
assert(handle && handle->numFds > 0);
int dma_buf_fd = handle->data[0];
VkResult result;
VkImage img_handle = VK_NULL_HANDLE;
VkBuffer buf_handle = VK_NULL_HANDLE;
VkMemoryRequirements mem_reqs;
/* Fix allocationSize and memoryTypeIndex. */
const VkMemoryDedicatedAllocateInfo *dedicated_info = vk_find_struct_const(
pAllocateInfo->pNext, MEMORY_DEDICATED_ALLOCATE_INFO);
if (dedicated_info && dedicated_info->image != VK_NULL_HANDLE) {
img_handle = dedicated_info->image;
VK_FROM_HANDLE(panvk_image, img, img_handle);
result = panvk_android_ahb_image_init(ahb, img);
if (result == VK_SUCCESS) {
result = panvk_android_get_image_mem_reqs(device, img_handle,
dma_buf_fd, &mem_reqs);
}
} else if (dedicated_info && dedicated_info->buffer != VK_NULL_HANDLE) {
buf_handle = dedicated_info->buffer;
result = panvk_android_get_buffer_mem_reqs(device, buf_handle, dma_buf_fd,
&mem_reqs);
} else {
mem_reqs.size = pAllocateInfo->allocationSize;
mem_reqs.memoryTypeBits =
panvk_android_get_fd_mem_type_bits(device, dma_buf_fd);
result = mem_reqs.memoryTypeBits ? VK_SUCCESS
: VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
if (result != VK_SUCCESS)
return result;
/* Override to a compatible memory type if needed. */
uint32_t mem_type_index = pAllocateInfo->memoryTypeIndex;
if (!((1 << mem_type_index) & mem_reqs.memoryTypeBits))
mem_type_index = ffs(mem_reqs.memoryTypeBits) - 1;
int dup_fd = os_dupfd_cloexec(dma_buf_fd);
if (dup_fd < 0) {
return (errno == EMFILE) ? VK_ERROR_TOO_MANY_OBJECTS
: VK_ERROR_OUT_OF_HOST_MEMORY;
}
/* Always chain dedicated info for simplicity, since the spec allows both
* image and buffer to be VK_NULL_HANDLE.
*/
const VkMemoryDedicatedAllocateInfo local_dedicated_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
.image = img_handle,
.buffer = buf_handle,
};
const VkImportMemoryFdInfoKHR fd_info = {
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
.pNext = &local_dedicated_info,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
.fd = dup_fd,
};
const VkMemoryAllocateInfo alloc_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &fd_info,
.allocationSize = mem_reqs.size,
.memoryTypeIndex = mem_type_index,
};
result = dev->dispatch_table.AllocateMemory(device, &alloc_info, pAllocator,
pMemory);
if (result != VK_SUCCESS)
close(dup_fd);
return result;
}
bool
panvk_android_is_ahb_memory(const VkMemoryAllocateInfo *pAllocateInfo)
{
vk_foreach_struct_const(ext, pAllocateInfo->pNext) {
switch (ext->sType) {
case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID:
return true;
case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
return ((const VkExportMemoryAllocateInfo *)ext)->handleTypes ==
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
default:
break;
}
}
return false;
}
VkResult
panvk_android_allocate_ahb_memory(VkDevice device,
const VkMemoryAllocateInfo *pAllocateInfo,
const VkAllocationCallbacks *pAllocator,
VkDeviceMemory *pMemory)
{
struct AHardwareBuffer *ahb;
VkResult result;
const VkImportAndroidHardwareBufferInfoANDROID *ahb_info =
vk_find_struct_const(pAllocateInfo->pNext,
IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID);
if (ahb_info) {
ahb = ahb_info->buffer;
AHardwareBuffer_acquire(ahb);
} else {
ahb = vk_alloc_ahardware_buffer(pAllocateInfo);
if (!ahb)
return panvk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
result = panvk_android_import_ahb_memory(device, pAllocateInfo, ahb,
pAllocator, pMemory);
if (result != VK_SUCCESS) {
AHardwareBuffer_release(ahb);
return panvk_error(device, result);
}
VK_FROM_HANDLE(vk_device_memory, mem, *pMemory);
assert(!mem->ahardware_buffer);
mem->ahardware_buffer = ahb;
return VK_SUCCESS;
}

View file

@ -25,6 +25,12 @@ VkResult panvk_android_get_wsi_memory(struct panvk_device *dev,
const VkBindImageMemoryInfo *bind_info,
VkDeviceMemory *out_mem_handle);
bool panvk_android_is_ahb_memory(const VkMemoryAllocateInfo *pAllocateInfo);
VkResult panvk_android_allocate_ahb_memory(
VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory);
#else /* VK_USE_PLATFORM_ANDROID_KHR */
static inline bool
@ -50,6 +56,21 @@ panvk_android_get_wsi_memory(struct panvk_device *dev,
return VK_ERROR_FEATURE_NOT_PRESENT;
}
static inline bool
panvk_android_is_ahb_memory(const VkMemoryAllocateInfo *pAllocateInfo)
{
return false;
}
static inline VkResult
panvk_android_allocate_ahb_memory(VkDevice device,
const VkMemoryAllocateInfo *pAllocateInfo,
const VkAllocationCallbacks *pAllocator,
VkDeviceMemory *pMemory)
{
return VK_ERROR_FEATURE_NOT_PRESENT;
}
#endif /* VK_USE_PLATFORM_ANDROID_KHR */
#endif /* PANVK_ANDROID_H */