vulkan: Add a vk_device_memory base struct
authorFaith Ekstrand <faith.ekstrand@collabora.com>
Mon, 20 Mar 2023 19:49:00 +0000 (14:49 -0500)
committerMarge Bot <emma+marge@anholt.net>
Fri, 31 Mar 2023 14:57:03 +0000 (14:57 +0000)
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 <lina@kiwitree.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22038>

src/vulkan/runtime/meson.build
src/vulkan/runtime/vk_device_memory.c [new file with mode: 0644]
src/vulkan/runtime/vk_device_memory.h [new file with mode: 0644]

index dac1038..3b15941 100644 (file)
@@ -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 (file)
index 0000000..6fc5c15
--- /dev/null
@@ -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 <vndk/hardware_buffer.h>
+#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 (file)
index 0000000..6e49017
--- /dev/null
@@ -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 */