diff --git a/src/panfrost/vulkan/panvk_android.c b/src/panfrost/vulkan/panvk_android.c index 66a7cb5e929..712d9b2f624 100644 --- a/src/panfrost/vulkan/panvk_android.c +++ b/src/panfrost/vulkan/panvk_android.c @@ -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; +} diff --git a/src/panfrost/vulkan/panvk_android.h b/src/panfrost/vulkan/panvk_android.h index 27875454c1d..c7edc1ae5a4 100644 --- a/src/panfrost/vulkan/panvk_android.h +++ b/src/panfrost/vulkan/panvk_android.h @@ -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 */