Refactor VkMemoryAllocateInfo parsing

The VkMemoryAllocateInfo structure, when used for
external memory, can contain various structures in
its pNext pointer. Previously, VkMemoryAllocateInfo
is parsed by external memory subclass. This CL
changes that to have a single function which parses
the VkMemoryAllocateInfo, with all potential users
of the VkMemoryAllocateInfo using a new structure,
DeviceMemory::ParsedAllocationInfo, which contains
the result of the parsing, which makes the code much
more readable. It also makes is easier to check if
an unexpected pNext structure is used, because the
parsing only happens in a single function, as opposed
to being spread out across multiple class functions.

Bug: b/199306480
Change-Id: I88598a3c6f1f2533f40cf1e1e82405fccf0771d2
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/56868
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Commit-Queue: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
index 42a4664..e3c8229 100644
--- a/src/Vulkan/VkDeviceMemory.cpp
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -33,7 +33,7 @@
 public:
 	VkExternalMemoryHandleTypeFlagBits typeFlagBit;
 	size_t instanceSize;
-	void (*instanceInit)(void *external, const VkMemoryAllocateInfo *pAllocateInfo);
+	void (*instanceInit)(void *external, const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo);
 };
 
 // Template function that parses a |pAllocateInfo.pNext| chain to verify that
@@ -41,16 +41,16 @@
 // class T. On success, return true and sets |pTraits| accordingly. Otherwise
 // return false.
 template<typename T>
-static bool parseCreateInfo(const VkMemoryAllocateInfo *pAllocateInfo,
+static bool parseCreateInfo(const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo,
                             ExternalMemoryTraits *pTraits)
 {
-	if(T::SupportsAllocateInfo(pAllocateInfo))
+	if(T::SupportsAllocateInfo(extendedAllocationInfo))
 	{
 		pTraits->typeFlagBit = T::typeFlagBit;
 		pTraits->instanceSize = sizeof(T);
 		pTraits->instanceInit = [](void *external,
-		                           const VkMemoryAllocateInfo *pAllocateInfo) {
-			new(external) T(pAllocateInfo);
+		                           const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo) {
+			new(external) T(extendedAllocationInfo);
 		};
 		return true;
 	}
@@ -66,12 +66,12 @@
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0;
 
 	// Always return true as is used as a fallback in findTraits() below.
-	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 	{
 		return true;
 	}
 
-	DeviceMemoryHostExternalBase(const VkMemoryAllocateInfo *pAllocateInfo) {}
+	DeviceMemoryHostExternalBase(const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo) {}
 
 	VkResult allocate(size_t size, void **pBuffer) override
 	{
@@ -120,43 +120,31 @@
 
 		AllocateInfo() = default;
 
-		AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+		AllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 		{
-			const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
-			while(createInfo)
+			if(extendedAllocationInfo.importMemoryHostPointerInfo)
 			{
-				switch(createInfo->sType)
+				if((extendedAllocationInfo.importMemoryHostPointerInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT) &&
+				   (extendedAllocationInfo.importMemoryHostPointerInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT))
 				{
-				case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT:
-					{
-						const auto *importInfo = reinterpret_cast<const VkImportMemoryHostPointerInfoEXT *>(createInfo);
-
-						if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT && importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT)
-						{
-							UNSUPPORTED("importInfo->handleType");
-						}
-						hostPointer = importInfo->pHostPointer;
-						supported = true;
-					}
-					break;
-				default:
-					break;
+					UNSUPPORTED("extendedAllocationInfo.importMemoryHostPointerInfo->handleType");
 				}
-				createInfo = createInfo->pNext;
+				hostPointer = extendedAllocationInfo.importMemoryHostPointerInfo->pHostPointer;
+				supported = true;
 			}
 		}
 	};
 
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT | VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT);
 
-	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 	{
-		AllocateInfo info(pAllocateInfo);
+		AllocateInfo info(extendedAllocationInfo);
 		return info.supported;
 	}
 
-	explicit ExternalMemoryHost(const VkMemoryAllocateInfo *pAllocateInfo)
-	    : allocateInfo(pAllocateInfo)
+	explicit ExternalMemoryHost(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
+	    : allocateInfo(extendedAllocationInfo)
 	{
 	}
 
@@ -196,49 +184,25 @@
 	OpaqueFdAllocateInfo() = default;
 
 	// Parse the VkMemoryAllocateInfo.pNext chain to initialize an OpaqueFdAllocateInfo.
-	OpaqueFdAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	OpaqueFdAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 	{
-		const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
-		while(createInfo)
+		if(extendedAllocationInfo.importMemoryFdInfo)
 		{
-			switch(createInfo->sType)
+			if(extendedAllocationInfo.importMemoryFdInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
 			{
-			case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
-				{
-					const auto *importInfo = reinterpret_cast<const VkImportMemoryFdInfoKHR *>(createInfo);
-
-					if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
-					{
-						UNSUPPORTED("VkImportMemoryFdInfoKHR::handleType %d", int(importInfo->handleType));
-					}
-					importFd = true;
-					fd = importInfo->fd;
-				}
-				break;
-			case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
-				{
-					const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(createInfo);
-
-					if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
-					{
-						UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(exportInfo->handleTypes));
-					}
-					exportFd = true;
-				}
-				break;
-			case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
-				// This can safely be ignored, as the Vulkan spec mentions:
-				// "If the pNext chain includes a VkMemoryDedicatedAllocateInfo structure, then that structure
-				//  includes a handle of the sole buffer or image resource that the memory *can* be bound to."
-				break;
-			case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT:
-				// This will be handled at a later point within vk::findTraits() by
-				// ExternalMemoryHost::AllocateInfo()
-				break;
-			default:
-				WARN("VkMemoryAllocateInfo->pNext sType = %s", vk::Stringify(createInfo->sType).c_str());
+				UNSUPPORTED("VkImportMemoryFdInfoKHR::handleType %d", int(extendedAllocationInfo.importMemoryFdInfo->handleType));
 			}
-			createInfo = createInfo->pNext;
+			importFd = true;
+			fd = extendedAllocationInfo.importMemoryFdInfo->fd;
+		}
+
+		if(extendedAllocationInfo.exportMemoryAllocateInfo)
+		{
+			if(extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
+			{
+				UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes));
+			}
+			exportFd = true;
 		}
 	}
 };
@@ -266,35 +230,35 @@
 
 namespace vk {
 
-static void findTraits(const VkMemoryAllocateInfo *pAllocateInfo,
+static void findTraits(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo,
                        ExternalMemoryTraits *pTraits)
 {
 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-	if(parseCreateInfo<AHardwareBufferExternalMemory>(pAllocateInfo, pTraits))
+	if(parseCreateInfo<AHardwareBufferExternalMemory>(extendedAllocationInfo, pTraits))
 	{
 		return;
 	}
 #endif
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-	if(parseCreateInfo<OpaqueFdExternalMemory>(pAllocateInfo, pTraits))
+	if(parseCreateInfo<OpaqueFdExternalMemory>(extendedAllocationInfo, pTraits))
 	{
 		return;
 	}
 #endif
 #if VK_USE_PLATFORM_FUCHSIA
-	if(parseCreateInfo<zircon::VmoExternalMemory>(pAllocateInfo, pTraits))
+	if(parseCreateInfo<zircon::VmoExternalMemory>(extendedAllocationInfo, pTraits))
 	{
 		return;
 	}
 #endif
-	if(parseCreateInfo<ExternalMemoryHost>(pAllocateInfo, pTraits))
+	if(parseCreateInfo<ExternalMemoryHost>(extendedAllocationInfo, pTraits))
 	{
 		return;
 	}
-	parseCreateInfo<DeviceMemoryHostExternalBase>(pAllocateInfo, pTraits);
+	parseCreateInfo<DeviceMemoryHostExternalBase>(extendedAllocationInfo, pTraits);
 }
 
-DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, void *mem, Device *pDevice)
+DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, void *mem, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *pDevice)
     : size(pAllocateInfo->allocationSize)
     , memoryTypeIndex(pAllocateInfo->memoryTypeIndex)
     , device(pDevice)
@@ -302,8 +266,8 @@
 	ASSERT(size);
 
 	ExternalMemoryTraits traits;
-	findTraits(pAllocateInfo, &traits);
-	traits.instanceInit(mem, pAllocateInfo);
+	findTraits(extendedAllocationInfo, &traits);
+	traits.instanceInit(mem, extendedAllocationInfo);
 	external = reinterpret_cast<ExternalBase *>(mem);
 	external->setDevicePtr(device);
 }
@@ -324,11 +288,98 @@
 
 size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo *pAllocateInfo)
 {
+	ExtendedAllocationInfo extendedAllocationInfo;
+	ParseAllocationInfo(pAllocateInfo, &extendedAllocationInfo);
 	ExternalMemoryTraits traits;
-	findTraits(pAllocateInfo, &traits);
+	findTraits(extendedAllocationInfo, &traits);
 	return traits.instanceSize;
 }
 
+VkResult DeviceMemory::ParseAllocationInfo(const VkMemoryAllocateInfo *pAllocateInfo, DeviceMemory::ExtendedAllocationInfo *extendedAllocationInfo)
+{
+	const VkBaseInStructure *allocationInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
+	while(allocationInfo)
+	{
+		switch(allocationInfo->sType)
+		{
+		case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
+			// This can safely be ignored on most platforms, as the Vulkan spec mentions:
+			// "If the pNext chain includes a VkMemoryDedicatedAllocateInfo structure, then that structure
+			//  includes a handle of the sole buffer or image resource that the memory *can* be bound to."
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+			extendedAllocationInfo->dedicatedAllocateInfo = reinterpret_cast<const VkMemoryDedicatedAllocateInfo *>(allocationInfo);
+#endif
+			break;
+		case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO:
+			// This extension controls on which physical devices the memory gets allocated.
+			// SwiftShader only has a single physical device, so this extension does nothing in this case.
+			break;
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+		case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
+			extendedAllocationInfo->importMemoryFdInfo = reinterpret_cast<const VkImportMemoryFdInfoKHR *>(allocationInfo);
+			if(extendedAllocationInfo->importMemoryFdInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
+			{
+				UNSUPPORTED("extendedAllocationInfo->importMemoryFdInfo->handleType %u", extendedAllocationInfo->importMemoryFdInfo->handleType);
+				return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+			}
+			break;
+#endif  // SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+		case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
+			extendedAllocationInfo->exportMemoryAllocateInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(allocationInfo);
+			switch(extendedAllocationInfo->exportMemoryAllocateInfo->handleTypes)
+			{
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+			case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
+				break;
+#endif
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+			case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID:
+				break;
+#endif
+#if VK_USE_PLATFORM_FUCHSIA
+			case VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA:
+				break;
+#endif
+			default:
+				UNSUPPORTED("extendedAllocationInfo->exportMemoryAllocateInfo->handleTypes %u", extendedAllocationInfo->exportMemoryAllocateInfo->handleTypes);
+				return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+			}
+			break;
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+		case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID:
+			extendedAllocationInfo->importAndroidHardwareBufferInfo = reinterpret_cast<const VkImportAndroidHardwareBufferInfoANDROID *>(allocationInfo);
+			break;
+#endif  // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+		case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT:
+			extendedAllocationInfo->importMemoryHostPointerInfo = reinterpret_cast<const VkImportMemoryHostPointerInfoEXT *>(allocationInfo);
+			if((extendedAllocationInfo->importMemoryHostPointerInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT) &&
+			   (extendedAllocationInfo->importMemoryHostPointerInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT))
+			{
+				UNSUPPORTED("extendedAllocationInfo->importMemoryHostPointerInfo->handleType %u", extendedAllocationInfo->importMemoryHostPointerInfo->handleType);
+				return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+			}
+			break;
+#if VK_USE_PLATFORM_FUCHSIA
+		case VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA:
+			extendedAllocationInfo->importMemoryZirconHandleInfo = reinterpret_cast<const VkImportMemoryZirconHandleInfoFUCHSIA *>(allocationInfo);
+			if(extendedAllocationInfo->importMemoryZirconHandleInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+			{
+				UNSUPPORTED("extendedAllocationInfo->importMemoryZirconHandleInfo->handleType %u", extendedAllocationInfo->importMemoryZirconHandleInfo->handleType);
+				return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+			}
+			break;
+#endif  // VK_USE_PLATFORM_FUCHSIA
+		default:
+			LOG_TRAP("pAllocateInfo->pNext sType = %s", vk::Stringify(allocationInfo->sType).c_str());
+			break;
+		}
+
+		allocationInfo = allocationInfo->pNext;
+	}
+
+	return VK_SUCCESS;
+}
+
 VkResult DeviceMemory::allocate()
 {
 	if(size > MAX_MEMORY_ALLOCATION_SIZE)
@@ -387,7 +438,7 @@
 	VkExternalMemoryHandleTypeFlagBits handle_type_bit = external->getFlagBit();
 	if(!handle_type_bit)
 	{
-		// This device memory is not external and can accomodate
+		// This device memory is not external and can accommodate
 		// any image or buffer as well.
 		return true;
 	}
diff --git a/src/Vulkan/VkDeviceMemory.hpp b/src/Vulkan/VkDeviceMemory.hpp
index 8a66056..098494c 100644
--- a/src/Vulkan/VkDeviceMemory.hpp
+++ b/src/Vulkan/VkDeviceMemory.hpp
@@ -25,9 +25,26 @@
 class DeviceMemory : public Object<DeviceMemory, VkDeviceMemory>
 {
 public:
-	DeviceMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, Device *pDevice);
+	struct ExtendedAllocationInfo
+	{
+		const VkExportMemoryAllocateInfo *exportMemoryAllocateInfo = nullptr;
+		const VkImportMemoryHostPointerInfoEXT *importMemoryHostPointerInfo = nullptr;
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+		const VkImportMemoryFdInfoKHR *importMemoryFdInfo = nullptr;
+#endif
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+		const VkImportAndroidHardwareBufferInfoANDROID *importAndroidHardwareBufferInfo = nullptr;
+		const VkMemoryDedicatedAllocateInfo *dedicatedAllocateInfo = nullptr;
+#endif
+#if VK_USE_PLATFORM_FUCHSIA
+		const VkImportMemoryZirconHandleInfoFUCHSIA importMemoryZirconHandleInfo = nullptr;
+#endif
+	};
+
+	DeviceMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *pDevice);
 
 	static size_t ComputeRequiredAllocationSize(const VkMemoryAllocateInfo *pCreateInfo);
+	static VkResult ParseAllocationInfo(const VkMemoryAllocateInfo *pAllocateInfo, DeviceMemory::ExtendedAllocationInfo *extendedAllocationInfo);
 
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
 	VkResult exportFd(int *pFd) const;
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
index acdbf89..1eab778 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
@@ -164,53 +164,35 @@
 
 }  // namespace
 
-AHardwareBufferExternalMemory::AllocateInfo::AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+AHardwareBufferExternalMemory::AllocateInfo::AllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 {
-	const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
-	while(createInfo)
+	if(extendedAllocationInfo.importAndroidHardwareBufferInfo)
 	{
-		switch(createInfo->sType)
-		{
-		case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID:
-			{
-				const auto *importInfo = reinterpret_cast<const VkImportAndroidHardwareBufferInfoANDROID *>(createInfo);
-				importAhb = true;
-				ahb = importInfo->buffer;
-			}
-			break;
-		case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
-			{
-				const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(createInfo);
+		importAhb = true;
+		ahb = extendedAllocationInfo.importAndroidHardwareBufferInfo->buffer;
+	}
 
-				if(exportInfo->handleTypes == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
-				{
-					exportAhb = true;
-				}
-				else
-				{
-					UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(exportInfo->handleTypes));
-				}
-			}
-			break;
-		case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
-			{
-				const auto *dedicatedAllocateInfo = reinterpret_cast<const VkMemoryDedicatedAllocateInfo *>(createInfo);
-				dedicatedImageHandle = vk::Cast(dedicatedAllocateInfo->image);
-				dedicatedBufferHandle = vk::Cast(dedicatedAllocateInfo->buffer);
-			}
-			break;
-		default:
-			{
-				LOG_TRAP("VkMemoryAllocateInfo->pNext sType = %s", vk::Stringify(createInfo->sType).c_str());
-			}
-			break;
+	if(extendedAllocationInfo.exportMemoryAllocateInfo)
+	{
+		if(extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+		{
+			exportAhb = true;
 		}
-		createInfo = createInfo->pNext;
+		else
+		{
+			UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes));
+		}
+	}
+
+	if(extendedAllocationInfo.dedicatedAllocateInfo)
+	{
+		dedicatedImageHandle = vk::Cast(extendedAllocationInfo.dedicatedAllocateInfo->image);
+		dedicatedBufferHandle = vk::Cast(extendedAllocationInfo.dedicatedAllocateInfo->buffer);
 	}
 }
 
-AHardwareBufferExternalMemory::AHardwareBufferExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo)
-    : allocateInfo(pAllocateInfo)
+AHardwareBufferExternalMemory::AHardwareBufferExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
+    : allocateInfo(extendedAllocationInfo)
 {
 }
 
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
index df46548..aa9f989 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
@@ -26,8 +26,8 @@
 class AHardwareBufferExternalMemory : public vk::DeviceMemory::ExternalBase
 {
 public:
-	// Helper struct to parse the VkMemoryAllocateInfo.pNext chain and
-	// extract relevant information related to the handle type supported
+	// Helper struct to used the parse allocation info and extract
+	// relevant information related to the handle type supported
 	// by this DeviceMemory::ExternalBase subclass.
 	struct AllocateInfo
 	{
@@ -39,19 +39,19 @@
 
 		AllocateInfo() = default;
 
-		// Parse the VkMemoryAllocateInfo.pNext chain to initialize an AllocateInfo.
-		AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo);
+		// Used the parsed allocation info to initialize a AllocateInfo.
+		AllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo);
 	};
 
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
 
-	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 	{
-		AllocateInfo info(pAllocateInfo);
+		AllocateInfo info(extendedAllocationInfo);
 		return info.importAhb || info.exportAhb;
 	}
 
-	explicit AHardwareBufferExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo);
+	explicit AHardwareBufferExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo);
 	~AHardwareBufferExternalMemory();
 
 	VkResult allocate(size_t size, void **pBuffer) override;
diff --git a/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp b/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp
index 5b63707..5c2c8f3 100644
--- a/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp
@@ -35,61 +35,40 @@
 
 		AllocateInfo() = default;
 
-		// Parse the VkMemoryAllocateInfo->pNext chain to initialize a AllocateInfo.
-		AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+		// Used the parsed allocation info to initialize a AllocateInfo.
+		AllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 		{
-			const auto *extInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
-			while(extInfo)
+			if(extendedAllocationInfo.importMemoryZirconHandleInfo)
 			{
-				switch(extInfo->sType)
+				if(extendedAllocationInfo.importMemoryZirconHandleInfo->handleType != VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA)
 				{
-				case VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA:
-					{
-						const auto *importInfo = reinterpret_cast<const VkImportMemoryZirconHandleInfoFUCHSIA *>(extInfo);
-
-						if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA)
-						{
-							UNSUPPORTED("importInfo->handleType");
-						}
-						importHandle = true;
-						handle = importInfo->handle;
-					}
-					break;
-				case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
-					{
-						const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(extInfo);
-
-						if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA)
-						{
-							UNSUPPORTED("exportInfo->handleTypes");
-						}
-						exportHandle = true;
-					}
-					break;
-				case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
-					// This can safely be ignored, as the Vulkan spec mentions:
-					// "If the pNext chain includes a VkMemoryDedicatedAllocateInfo structure, then that structure
-					//  includes a handle of the sole buffer or image resource that the memory *can* be bound to."
-					break;
-
-				default:
-					WARN("VkMemoryAllocateInfo->pNext sType = %s", vk::Stringify(extInfo->sType).c_str());
+					UNSUPPORTED("extendedAllocationInfo.importMemoryZirconHandleInfo->handleType");
 				}
-				extInfo = extInfo->pNext;
+				importHandle = true;
+				handle = extendedAllocationInfo.importMemoryZirconHandleInfo->handle;
+			}
+
+			if(extendedAllocationInfo.exportMemoryAllocateInfo)
+			{
+				if(extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes != VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO)
+				{
+					UNSUPPORTED("extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes");
+				}
+				exportHandle = true;
 			}
 		}
 	};
 
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
 
-	static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool supportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 	{
-		AllocateInfo info(pAllocateInfo);
+		AllocateInfo info(extendedAllocationInfo);
 		return info.importHandle || info.exportHandle;
 	}
 
-	explicit VmoExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo)
-	    : allocateInfo(pAllocateInfo)
+	explicit VmoExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
+	    : allocateInfo(extendedAllocationInfo)
 	{
 	}
 
diff --git a/src/Vulkan/VkDeviceMemoryExternalLinux.hpp b/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
index af69b2f..462dd7c 100644
--- a/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
@@ -24,14 +24,14 @@
 public:
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
 
-	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 	{
-		OpaqueFdAllocateInfo info(pAllocateInfo);
+		OpaqueFdAllocateInfo info(extendedAllocationInfo);
 		return info.importFd || info.exportFd;
 	}
 
-	explicit OpaqueFdExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo)
-	    : allocateInfo(pAllocateInfo)
+	explicit OpaqueFdExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
+	    : allocateInfo(extendedAllocationInfo)
 	{
 	}
 
diff --git a/src/Vulkan/VkDeviceMemoryExternalMac.hpp b/src/Vulkan/VkDeviceMemoryExternalMac.hpp
index bcd06c5..4d35810 100644
--- a/src/Vulkan/VkDeviceMemoryExternalMac.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalMac.hpp
@@ -60,14 +60,14 @@
 public:
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
 
-	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 	{
-		OpaqueFdAllocateInfo info(pAllocateInfo);
+		OpaqueFdAllocateInfo info(extendedAllocationInfo);
 		return info.importFd || info.exportFd;
 	}
 
-	explicit OpaqueFdExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo)
-	    : allocateInfo(pAllocateInfo)
+	explicit OpaqueFdExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
+	    : allocateInfo(extendedAllocationInfo)
 	{
 	}
 
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index d948491..f2551d6 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -1025,91 +1025,14 @@
 	TRACE("(VkDevice device = %p, const VkMemoryAllocateInfo* pAllocateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkDeviceMemory* pMemory = %p)",
 	      device, pAllocateInfo, pAllocator, pMemory);
 
-	const VkBaseInStructure *allocationInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
-	while(allocationInfo)
+	vk::DeviceMemory::ExtendedAllocationInfo extendedAllocationInfo = {};
+	VkResult result = vk::DeviceMemory::ParseAllocationInfo(pAllocateInfo, &extendedAllocationInfo);
+	if(result != VK_SUCCESS)
 	{
-		switch(allocationInfo->sType)
-		{
-		case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
-			// This can safely be ignored, as the Vulkan spec mentions:
-			// "If the pNext chain includes a VkMemoryDedicatedAllocateInfo structure, then that structure
-			//  includes a handle of the sole buffer or image resource that the memory *can* be bound to."
-			break;
-		case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO:
-			// This extension controls on which physical devices the memory gets allocated.
-			// SwiftShader only has a single physical device, so this extension does nothing in this case.
-			break;
-#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-		case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
-			{
-				auto *importInfo = reinterpret_cast<const VkImportMemoryFdInfoKHR *>(allocationInfo);
-				if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
-				{
-					UNSUPPORTED("importInfo->handleType %u", importInfo->handleType);
-					return VK_ERROR_INVALID_EXTERNAL_HANDLE;
-				}
-			}
-			break;
-#endif  // SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-		case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
-			{
-				auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(allocationInfo);
-				switch(exportInfo->handleTypes)
-				{
-#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-				case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
-					break;
-#endif
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-				case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID:
-					break;
-#endif
-#if VK_USE_PLATFORM_FUCHSIA
-				case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA:
-					break;
-#endif
-				default:
-					UNSUPPORTED("exportInfo->handleTypes %u", exportInfo->handleTypes);
-					return VK_ERROR_INVALID_EXTERNAL_HANDLE;
-				}
-			}
-			break;
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-		case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID:
-			// Ignore
-			break;
-#endif  // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-		case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT:
-			{
-				auto *importInfo = reinterpret_cast<const VkImportMemoryHostPointerInfoEXT *>(allocationInfo);
-				if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT && importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT)
-				{
-					UNSUPPORTED("importInfo->handleType %u", importInfo->handleType);
-					return VK_ERROR_INVALID_EXTERNAL_HANDLE;
-				}
-			}
-			break;
-#if VK_USE_PLATFORM_FUCHSIA
-		case VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA:
-			{
-				auto *importInfo = reinterpret_cast<const VkImportMemoryZirconHandleInfoFUCHSIA *>(allocationInfo);
-				if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA)
-				{
-					UNSUPPORTED("importInfo->handleType %u", importInfo->handleType);
-					return VK_ERROR_INVALID_EXTERNAL_HANDLE;
-				}
-			}
-			break;
-#endif  // VK_USE_PLATFORM_FUCHSIA
-		default:
-			LOG_TRAP("pAllocateInfo->pNext sType = %s", vk::Stringify(allocationInfo->sType).c_str());
-			break;
-		}
-
-		allocationInfo = allocationInfo->pNext;
+		return result;
 	}
 
-	VkResult result = vk::DeviceMemory::Create(pAllocator, pAllocateInfo, pMemory, vk::Cast(device));
+	result = vk::DeviceMemory::Create(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, vk::Cast(device));
 	if(result != VK_SUCCESS)
 	{
 		return result;