Add BindImageMemory2 support for swapchain images

This finishes our KHR_swapchain v70 implementation.

Test: dEQP-VK.wsi.*
Change-Id: I512e0c086db687ca7ffb8cd5e5375fa7a9d432cd
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/35929
Tested-by: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 189c684..aa4e68c 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -207,9 +207,15 @@
 	// Only 1.1 core version of this is supported. The extension has additional requirements
 	//{ VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME, VK_KHR_VARIABLE_POINTERS_SPEC_VERSION },
 #ifndef __ANDROID__
+	// We fully support the KHR_swapchain v70 additions, so just track the spec version.
 	{ VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_SPEC_VERSION },
 #else
-	{ VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME, VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION },
+	// We only support V7 of this extension. Missing functionality: in V8,
+	// it becomes possible to pass a VkNativeBufferANDROID structure to
+	// vkBindImageMemory2. Android's swapchain implementation does this in
+	// order to support passing VkBindImageMemorySwapchainInfoKHR
+	// (from KHR_swapchain v70) to vkBindImageMemory2.
+	{ VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME, 7 },
 #endif
 };
 
@@ -1104,6 +1110,9 @@
 		}
 		break;
 #endif
+		case VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR:
+			/* Do nothing. We don't actually need the swapchain handle yet; we'll do all the work in vkBindImageMemory2. */
+			break;
 		default:
 			// "the [driver] must skip over, without processing (other than reading the sType and pNext members) any structures in the chain with sType values not defined by [supported extenions]"
 			UNIMPLEMENTED("extensionCreateInfo->sType");   // TODO(b/119321052): UNIMPLEMENTED() should be used only for features that must still be implemented. Use a more informational macro here.
@@ -2137,12 +2146,35 @@
 
 	for(uint32_t i = 0; i < bindInfoCount; i++)
 	{
-		if(pBindInfos[i].pNext)
+		vk::DeviceMemory *memory = vk::Cast(pBindInfos[i].memory);
+		VkDeviceSize offset = pBindInfos[i].memoryOffset;
+
+		auto extInfo = reinterpret_cast<VkBaseInStructure const *>(pBindInfos[i].pNext);
+		while (extInfo)
 		{
-			UNIMPLEMENTED("pBindInfos[%d].pNext", i);
+			switch (extInfo->sType)
+			{
+			case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO:
+				/* Do nothing */
+				break;
+
+#ifndef __ANDROID__
+			case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR:
+				{
+					auto swapchainInfo = reinterpret_cast<VkBindImageMemorySwapchainInfoKHR const *>(extInfo);
+					memory = vk::Cast(swapchainInfo->swapchain)->getImage(swapchainInfo->imageIndex).getImageMemory();
+					offset = 0;
+				}
+				break;
+#endif
+
+			default:
+				break;
+			}
+			extInfo = extInfo->pNext;
 		}
 
-		vk::Cast(pBindInfos[i].image)->bind(vk::Cast(pBindInfos[i].memory), pBindInfos[i].memoryOffset);
+		vk::Cast(pBindInfos[i].image)->bind(memory, offset);
 	}
 
 	return VK_SUCCESS;
diff --git a/src/WSI/VkSurfaceKHR.hpp b/src/WSI/VkSurfaceKHR.hpp
index 48f25ce..0e833da 100644
--- a/src/WSI/VkSurfaceKHR.hpp
+++ b/src/WSI/VkSurfaceKHR.hpp
@@ -45,7 +45,7 @@
 	VkImage asVkImage() const;
 
 	const Image* getImage() const { return image; }
-	const DeviceMemory* getImageMemory() const { return imageMemory; }
+	DeviceMemory* getImageMemory() const { return imageMemory; }
 	bool isAvailable() const { return (imageStatus == AVAILABLE); }
 	bool exists() const { return (imageStatus != NONEXISTENT); }
 	void setStatus(PresentImageStatus status) { imageStatus = status; }
diff --git a/src/WSI/VkSwapchainKHR.hpp b/src/WSI/VkSwapchainKHR.hpp
index 3e6bf33..7a77ebb 100644
--- a/src/WSI/VkSwapchainKHR.hpp
+++ b/src/WSI/VkSwapchainKHR.hpp
@@ -47,6 +47,7 @@
 	VkResult getNextImage(uint64_t timeout, Semaphore* semaphore, Fence* fence, uint32_t* pImageIndex);
 
 	void present(uint32_t index);
+	PresentImage const &getImage(uint32_t imageIndex) { return images[imageIndex]; }
 
 private:
 	SurfaceKHR* surface = nullptr;