Implement HostMappedForeignMemory DeviceMemory

From VK_EXT_external_memory_host, there is a type of VkDeviceMemory
that takes a pointer to host mapped foreign memory, where the
underlying memory is owned by the host, not the device.
This is used by ANGLE on Mac when creating a VkDeviceMemory given an
IOSurface.

Tests: dEQP-VK.*
Bug: chromium:1965434
Change-Id: I944a5d3cd23ad8b193f58981829a8847419a4b0d
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/39968
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Jonah Ryan-Davis <jonahr@google.com>
diff --git a/src/Vulkan/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
index c524570..6f3ad1c 100644
--- a/src/Vulkan/VkDeviceMemory.cpp
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -130,6 +130,79 @@
 
 }  // namespace vk
 
+// Host-allocated memory and host-mapped foreign memory
+class ExternalMemoryHost : public vk::DeviceMemory::ExternalBase
+{
+public:
+	struct AllocateInfo
+	{
+		bool supported = false;
+		void *hostPointer = nullptr;
+
+		AllocateInfo() = default;
+
+		AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+		{
+			const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
+			while(createInfo)
+			{
+				switch(createInfo->sType)
+				{
+					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;
+				}
+				createInfo = createInfo->pNext;
+			}
+		}
+	};
+
+	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)
+	{
+		AllocateInfo info(pAllocateInfo);
+		return info.supported;
+	}
+
+	explicit ExternalMemoryHost(const VkMemoryAllocateInfo *pAllocateInfo)
+	    : allocateInfo(pAllocateInfo)
+	{
+	}
+
+	VkResult allocate(size_t size, void **pBuffer) override
+	{
+		if(allocateInfo.supported)
+		{
+			*pBuffer = allocateInfo.hostPointer;
+			return VK_SUCCESS;
+		}
+		return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+	}
+
+	void deallocate(void *buffer, size_t size) override
+	{}
+
+	VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
+	{
+		return typeFlagBit;
+	}
+
+private:
+	AllocateInfo allocateInfo;
+};
+
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
 #	if defined(__linux__) || defined(__ANDROID__)
 #		include "VkDeviceMemoryExternalLinux.hpp"
@@ -163,6 +236,10 @@
 		return;
 	}
 #endif
+	if(parseCreateInfo<ExternalMemoryHost>(pAllocateInfo, pTraits))
+	{
+		return;
+	}
 	parseCreateInfo<DeviceMemoryHostExternalBase>(pAllocateInfo, pTraits);
 }
 
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index f293ca5..64ac9f8 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -381,6 +381,13 @@
 	    } },
 #endif
 
+	// VK_EXT_external_memory_host
+	{
+	    VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
+	    {
+	        MAKE_VULKAN_DEVICE_ENTRY(vkGetMemoryHostPointerPropertiesEXT),
+	    } },
+
 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
 	// VK_ANDROID_external_memory_android_hardware_buffer
 	{
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 5e55954..42d9a8c 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -428,6 +428,11 @@
 	pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
 }
 
+void PhysicalDevice::getProperties(VkPhysicalDeviceExternalMemoryHostPropertiesEXT *properties) const
+{
+	properties->minImportedHostPointerAlignment = REQUIRED_MEMORY_ALIGNMENT;
+}
+
 void PhysicalDevice::getProperties(VkPhysicalDeviceDriverPropertiesKHR *properties) const
 {
 	properties->driverID = VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR;
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp
index 6b13faa..0193c71 100644
--- a/src/Vulkan/VkPhysicalDevice.hpp
+++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -62,6 +62,7 @@
 	void getProperties(const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties) const;
 	void getProperties(const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties) const;
 	void getProperties(const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties) const;
+	void getProperties(VkPhysicalDeviceExternalMemoryHostPropertiesEXT *properties) const;
 	void getProperties(VkPhysicalDeviceDriverPropertiesKHR *properties) const;
 	void getProperties(VkPhysicalDeviceLineRasterizationPropertiesEXT *properties) const;
 	void getProperties(VkPhysicalDeviceProvokingVertexPropertiesEXT *properties) const;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 2baf038..92a123a 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -341,6 +341,9 @@
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
 	{ VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION },
 #endif
+
+	{ VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION },
+
 #if VK_USE_PLATFORM_FUCHSIA
 	{ VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION },
 #endif
@@ -952,6 +955,16 @@
 				// 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;
+			}
 			default:
 				WARN("pAllocateInfo->pNext sType = %s", vk::Stringify(allocationInfo->sType).c_str());
 				break;
@@ -1025,6 +1038,21 @@
 }
 #endif  // SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
 
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void *pHostPointer, VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties)
+{
+	TRACE("(VkDevice device = %p, VkExternalMemoryHandleTypeFlagBits handleType = %x, const void *pHostPointer = %p, VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties = %p)",
+	      device, handleType, pHostPointer, pMemoryHostPointerProperties);
+
+	if(handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT && handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT)
+	{
+		UNSUPPORTED("handleType %u", handleType);
+		return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+	}
+	pMemoryHostPointerProperties->memoryTypeBits = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+
+	return VK_SUCCESS;
+}
+
 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
 VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo, struct AHardwareBuffer **pBuffer)
 {
@@ -2855,9 +2883,11 @@
 				                             sizeof(deviceExtensionProperties) / sizeof(deviceExtensionProperties[0])));
 				break;
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT:
-				ASSERT(!HasExtensionProperty(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionProperties,
-				                             sizeof(deviceExtensionProperties) / sizeof(deviceExtensionProperties[0])));
-				break;
+			{
+				auto properties = reinterpret_cast<VkPhysicalDeviceExternalMemoryHostPropertiesEXT *>(extensionProperties);
+				vk::Cast(physicalDevice)->getProperties(properties);
+			}
+			break;
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR:
 			{
 				auto properties = reinterpret_cast<VkPhysicalDeviceDriverPropertiesKHR *>(extensionProperties);