From c0cc508cd0b5357313ceb3f0fa54b76f510dd5cf Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Mon, 20 Mar 2023 14:49:00 -0500 Subject: [PATCH] vulkan: Add a vk_device_memory base struct This lets us provide a vk_device_memory_range helper similar to what's provided for buffers for dealing with VK_WHOLE_SIZE. We can also handle flags and some annoyance around Android hardware buffer import. Reviewed-by: Lina Versace Part-of: --- src/vulkan/runtime/meson.build | 2 + src/vulkan/runtime/vk_device_memory.c | 200 ++++++++++++++++++++++++++++++++++ src/vulkan/runtime/vk_device_memory.h | 87 +++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 src/vulkan/runtime/vk_device_memory.c create mode 100644 src/vulkan/runtime/vk_device_memory.h diff --git a/src/vulkan/runtime/meson.build b/src/vulkan/runtime/meson.build index dac1038..3b15941 100644 --- a/src/vulkan/runtime/meson.build +++ b/src/vulkan/runtime/meson.build @@ -50,6 +50,8 @@ vulkan_runtime_files = files( 'vk_descriptor_update_template.h', 'vk_device.c', 'vk_device.h', + 'vk_device_memory.c', + 'vk_device_memory.h', 'vk_fence.c', 'vk_fence.h', 'vk_framebuffer.c', diff --git a/src/vulkan/runtime/vk_device_memory.c b/src/vulkan/runtime/vk_device_memory.c new file mode 100644 index 0000000..6fc5c15 --- /dev/null +++ b/src/vulkan/runtime/vk_device_memory.c @@ -0,0 +1,200 @@ +/* + * Copyright © 2023 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_device_memory.h" + +#include "vk_android.h" +#include "vk_common_entrypoints.h" +#include "vk_util.h" + +#if defined(ANDROID) && ANDROID_API_LEVEL >= 26 +#include +#endif + +void * +vk_device_memory_create(struct vk_device *device, + const VkMemoryAllocateInfo *pAllocateInfo, + const VkAllocationCallbacks *alloc, + size_t size) +{ + struct vk_device_memory *mem = + vk_object_zalloc(device, alloc, size, VK_OBJECT_TYPE_DEVICE_MEMORY); + if (mem == NULL) + return NULL; + + assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO); + assert(pAllocateInfo->allocationSize > 0); + + mem->size = pAllocateInfo->allocationSize; + mem->memory_type_index = pAllocateInfo->memoryTypeIndex; + + vk_foreach_struct_const(ext, pAllocateInfo->pNext) { + switch (ext->sType) { + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: { + const VkExportMemoryAllocateInfo *export_info = (void *)ext; + mem->export_handle_types = export_info->handleTypes; + break; + } + + case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID: { +#if defined(ANDROID) && ANDROID_API_LEVEL >= 26 + const VkImportAndroidHardwareBufferInfoANDROID *ahb_info = (void *)ext; + + assert(mem->import_handle_type == 0); + mem->import_handle_type = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + /* From the Vulkan 1.3.242 spec: + * + * "If the vkAllocateMemory command succeeds, the implementation + * must acquire a reference to the imported hardware buffer, which + * it must release when the device memory object is freed. If the + * command fails, the implementation must not retain a + * reference." + * + * We assume that if the driver fails to create its memory object, + * it will call vk_device_memory_destroy which will delete our + * reference. + */ + AHardwareBuffer_acquire(ahb_info->buffer); + mem->ahardware_buffer = ahb_info->buffer; + break; +#else + unreachable("AHardwareBuffer import requires Android >= 26"); +#endif /* ANDROID_API_LEVEL >= 26 */ + } + + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR: { + const VkImportMemoryFdInfoKHR *fd_info = (void *)ext; + if (fd_info->handleType) { + assert(fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT || + fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT); + assert(mem->import_handle_type == 0); + mem->import_handle_type = fd_info->handleType; + } + break; + } + + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: { + const VkImportMemoryHostPointerInfoEXT *host_ptr_info = (void *)ext; + if (host_ptr_info->handleType) { + assert(host_ptr_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT || + host_ptr_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT); + + assert(mem->import_handle_type == 0); + mem->import_handle_type = host_ptr_info->handleType; + mem->host_ptr = host_ptr_info->pHostPointer; + } + break; + } + + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR: { +#ifdef VK_USE_PLATFORM_WIN32_KHR + const VkImportMemoryWin32HandleInfoKHR *w32h_info = (void *)ext; + if (w32h_info->handleType) { + assert(w32h_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT || + w32h_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT || + w32h_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT || + w32h_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT || + w32h_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT || + w32h_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT); + assert(mem->import_handle_type == 0); + mem->import_handle_type = w32h_info->handleType; + } + break; +#else + unreachable("Win32 platform support disabled"); +#endif + } + + case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO: { + const VkMemoryAllocateFlagsInfo *flags_info = (void *)ext; + mem->alloc_flags = flags_info->flags; + break; + } + + default: + break; + } + } + +#if defined(ANDROID) && ANDROID_API_LEVEL >= 26 + if ((mem->export_handle_types & + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) && + mem->ahardware_buffer == NULL) { + /* If we need to be able to export an Android hardware buffer but none + * is provided as an import, create a new one. + */ + mem->ahardware_buffer = vk_alloc_ahardware_buffer(pAllocateInfo); + if (mem->ahardware_buffer == NULL) { + vk_device_memory_destroy(device, alloc, mem); + return NULL; + } + } +#endif + + return mem; +} + +void +vk_device_memory_destroy(struct vk_device *device, + const VkAllocationCallbacks *alloc, + struct vk_device_memory *mem) +{ +#if defined(ANDROID) && ANDROID_API_LEVEL >= 26 + if (mem->ahardware_buffer) + AHardwareBuffer_release(mem->ahardware_buffer); +#endif /* ANDROID_API_LEVEL >= 26 */ + + vk_object_free(device, alloc, mem); +} + +#if defined(ANDROID) && ANDROID_API_LEVEL >= 26 +VkResult +vk_common_GetMemoryAndroidHardwareBufferANDROID( + VkDevice _device, + const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo, + struct AHardwareBuffer **pBuffer) +{ + VK_FROM_HANDLE(vk_device_memory, mem, pInfo->memory); + + /* Some quotes from Vulkan spec: + * + * "If the device memory was created by importing an Android hardware + * buffer, vkGetMemoryAndroidHardwareBufferANDROID must return that same + * Android hardware buffer object." + * + * "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID + * must have been included in VkExportMemoryAllocateInfo::handleTypes + * when memory was created." + */ + if (mem->ahardware_buffer) { + *pBuffer = mem->ahardware_buffer; + /* Increase refcount. */ + AHardwareBuffer_acquire(*pBuffer); + return VK_SUCCESS; + } + + return VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR; +} +#endif diff --git a/src/vulkan/runtime/vk_device_memory.h b/src/vulkan/runtime/vk_device_memory.h new file mode 100644 index 0000000..6e49017 --- /dev/null +++ b/src/vulkan/runtime/vk_device_memory.h @@ -0,0 +1,87 @@ +/* + * Copyright © 2023 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef VK_DEVICE_MEMORY_H +#define VK_DEVICE_MEMORY_H + +#include "vk_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct AHardwareBuffer; + +struct vk_device_memory { + struct vk_object_base base; + + /* VkMemoryAllocateFlagsInfo::flags */ + VkMemoryAllocateFlags alloc_flags; + + /* VkMemoryAllocateInfo::allocationSize */ + VkDeviceSize size; + + /* VkMemoryAllocateInfo::memoryTypeIndex */ + uint32_t memory_type_index; + + /* Import handle type (if any) */ + VkExternalMemoryHandleTypeFlags import_handle_type; + + /* VkExportMemoryAllocateInfo::handleTypes */ + VkExternalMemoryHandleTypeFlags export_handle_types; + + /* VkImportMemoryHostPointerInfoEXT::pHostPointer */ + void *host_ptr; + + /* VkImportAndroidHardwareBufferInfoANDROID::buffer */ + struct AHardwareBuffer *ahardware_buffer; +}; +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_device_memory, base, VkDeviceMemory, + VK_OBJECT_TYPE_DEVICE_MEMORY); + +void *vk_device_memory_create(struct vk_device *device, + const VkMemoryAllocateInfo *pAllocateInfo, + const VkAllocationCallbacks *alloc, + size_t size); +void vk_device_memory_destroy(struct vk_device *device, + const VkAllocationCallbacks *alloc, + struct vk_device_memory *mem); + +static inline uint64_t +vk_device_memory_range(const struct vk_device_memory *mem, + uint64_t offset, uint64_t range) +{ + assert(offset <= mem->size); + if (range == VK_WHOLE_SIZE) { + return mem->size - offset; + } else { + assert(range + offset >= range); + assert(range + offset <= mem->size); + return range; + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* VK_DEVICE_MEMORY_H */ -- 2.7.4