Handle more image properties from external device memory

Some external device memories really represent existing images
with requirements and not just memory blobs. For AHB, retrieve
planes offsets and row strides from the gralloc plane metadata.

Bug: b/171302758
Test: launch Cuttlefish w/ SwANGLE and open camera
Change-Id: I9af7aae9d19035cacd736b127b9d03cee4374fab
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/51048
Presubmit-Ready: Jason Macnak <natsu@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Jason Macnak <natsu@google.com>
Commit-Queue: Jason Macnak <natsu@google.com>
diff --git a/src/Vulkan/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
index 85e7806..5f3ac19 100644
--- a/src/Vulkan/VkDeviceMemory.cpp
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -339,11 +339,23 @@
 	return external && external->hasExternalImageProperties();
 }
 
-int DeviceMemory::externalImageRowPitchBytes() const
+int DeviceMemory::externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const
 {
 	if(external)
 	{
-		return external->externalImageRowPitchBytes();
+		return external->externalImageRowPitchBytes(aspect);
+	}
+
+	// This function should never be called on non-external memory.
+	ASSERT(false);
+	return -1;
+}
+
+VkDeviceSize DeviceMemory::externalImageMemoryOffset(VkImageAspectFlagBits aspect) const
+{
+	if(external)
+	{
+		return external->externalImageMemoryOffset(aspect);
 	}
 
 	// This function should never be called on non-external memory.
diff --git a/src/Vulkan/VkDeviceMemory.hpp b/src/Vulkan/VkDeviceMemory.hpp
index ed685d5..8a66056 100644
--- a/src/Vulkan/VkDeviceMemory.hpp
+++ b/src/Vulkan/VkDeviceMemory.hpp
@@ -58,7 +58,8 @@
 	class ExternalBase;
 
 	bool hasExternalImageProperties() const;
-	int externalImageRowPitchBytes() const;
+	int externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const;
+	VkDeviceSize externalImageMemoryOffset(VkImageAspectFlagBits aspect) const;
 
 private:
 	void *buffer = nullptr;
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
index 7463478..66737e8 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
@@ -23,39 +23,6 @@
 
 namespace {
 
-int GetBytesFromAHBFormat(uint32_t ahbFormat)
-{
-	switch(ahbFormat)
-	{
-		case AHARDWAREBUFFER_FORMAT_D16_UNORM:
-			return 2;
-		case AHARDWAREBUFFER_FORMAT_D24_UNORM:
-			return 3;
-		case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
-			return 4;
-		case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
-			return 4;
-		case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
-			return 8;
-		case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
-			return 2;
-		case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
-			return 4;
-		case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
-			return 4;
-		case AHARDWAREBUFFER_FORMAT_S8_UINT:
-			return 1;
-		default:
-			// TODO(b/165302991)
-			// - AHARDWAREBUFFER_FORMAT_BLOB
-			// - AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT
-			// - AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT
-			// - AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM
-			UNSUPPORTED("Requested bytes() for unsupported format %d", int(ahbFormat));
-			return -1;
-	}
-}
-
 uint32_t GetAHBFormatFromVkFormat(VkFormat format)
 {
 	switch(format)
@@ -385,12 +352,14 @@
 	// Empty rect, lock entire buffer.
 	ARect *rect = nullptr;
 
-	int ret = AHardwareBuffer_lock(ahb, usage, fence, rect, pBuffer);
+	int ret = AHardwareBuffer_lockPlanes(ahb, usage, fence, rect, &ahbPlanes);
 	if(ret != 0)
 	{
 		return VK_ERROR_OUT_OF_HOST_MEMORY;
 	}
 
+	*pBuffer = ahbPlanes.planes[0].data;
+
 	return VK_SUCCESS;
 }
 
@@ -486,9 +455,54 @@
 	return result;
 }
 
-int AHardwareBufferExternalMemory::externalImageRowPitchBytes() const
+int AHardwareBufferExternalMemory::externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const
 {
-	return GetBytesFromAHBFormat(ahbDesc.format) * ahbDesc.stride;
+	switch(ahbDesc.format)
+	{
+		case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
+			switch(aspect)
+			{
+				case VK_IMAGE_ASPECT_PLANE_0_BIT:
+					return static_cast<int>(ahbPlanes.planes[0].rowStride);
+				case VK_IMAGE_ASPECT_PLANE_1_BIT:
+					return static_cast<int>(ahbPlanes.planes[1].rowStride);
+				case VK_IMAGE_ASPECT_PLANE_2_BIT:
+					return static_cast<int>(ahbPlanes.planes[2].rowStride);
+				default:
+					UNSUPPORTED("Unsupported aspect %d for AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420", int(aspect));
+					return 0;
+			}
+			break;
+		default:
+			break;
+	}
+	return static_cast<int>(ahbPlanes.planes[0].rowStride);
+}
+
+VkDeviceSize AHardwareBufferExternalMemory::externalImageMemoryOffset(VkImageAspectFlagBits aspect) const
+{
+	switch(ahbDesc.format)
+	{
+		case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
+			switch(aspect)
+			{
+				case VK_IMAGE_ASPECT_PLANE_0_BIT:
+					return 0;
+				case VK_IMAGE_ASPECT_PLANE_1_BIT:
+					return reinterpret_cast<const char *>(ahbPlanes.planes[1].data) -
+					       reinterpret_cast<const char *>(ahbPlanes.planes[0].data);
+				case VK_IMAGE_ASPECT_PLANE_2_BIT:
+					return reinterpret_cast<const char *>(ahbPlanes.planes[2].data) -
+					       reinterpret_cast<const char *>(ahbPlanes.planes[0].data);
+				default:
+					UNSUPPORTED("Unsupported aspect %d for AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420", int(aspect));
+					return 0;
+			}
+			break;
+		default:
+			break;
+	}
+	return 0;
 }
 
 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
index 2e73240..6d25add 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
@@ -67,7 +67,8 @@
 	static VkResult GetAndroidHardwareBufferProperties(VkDevice &device, const AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties);
 
 	bool hasExternalImageProperties() const override final { return true; }
-	int externalImageRowPitchBytes() const override final;
+	int externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const override final;
+	VkDeviceSize externalImageMemoryOffset(VkImageAspectFlagBits aspect) const override final;
 
 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
 	bool isImport() const override
@@ -85,6 +86,7 @@
 
 	AHardwareBuffer *ahb = nullptr;
 	AHardwareBuffer_Desc ahbDesc = {};
+	AHardwareBuffer_Planes ahbPlanes = {};
 	vk::Device *device = nullptr;
 	AllocateInfo allocateInfo;
 };
diff --git a/src/Vulkan/VkDeviceMemoryExternalBase.hpp b/src/Vulkan/VkDeviceMemoryExternalBase.hpp
index 451ba3d..c8dc313 100644
--- a/src/Vulkan/VkDeviceMemoryExternalBase.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalBase.hpp
@@ -48,7 +48,8 @@
 	// Some external device memories, such as Android hardware buffers, represent
 	// specific images with requirements.
 	virtual bool hasExternalImageProperties() const { return false; }
-	virtual int externalImageRowPitchBytes() const { return 0; }
+	virtual int externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const { return 0; }
+	virtual VkDeviceSize externalImageMemoryOffset(VkImageAspectFlagBits aspect) const { return 0; }
 
 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
 	virtual bool isImport() const
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 897aae3..545a3e1 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -751,7 +751,7 @@
 {
 	if(deviceMemory && deviceMemory->hasExternalImageProperties())
 	{
-		return deviceMemory->externalImageRowPitchBytes();
+		return deviceMemory->externalImageRowPitchBytes(aspect);
 	}
 
 	// Depth and Stencil pitch should be computed separately
@@ -803,6 +803,11 @@
 
 VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect) const
 {
+	if(deviceMemory && deviceMemory->hasExternalImageProperties())
+	{
+		return deviceMemory->externalImageMemoryOffset(aspect);
+	}
+
 	switch(format)
 	{
 		case VK_FORMAT_D16_UNORM_S8_UINT: