Fix Depth+Stencil image copy

As long as both source and destination provide both depth+stencil,
it is allowed to copy both simultaneously. When this happens,
Image::copyTo() will simply perform the copy operations one aspect
after the other.

Bug: b/202987708
Tests: dEQP-VK.api.*.depth_stencil.*
Change-Id: I4e79c88595e708475c93f46aabbb8cf33ad5b835
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/58168
Commit-Queue: Alexis Hétu <sugoi@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index fea51cc..7adb5e3 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -356,6 +356,27 @@
 
 void Image::copyTo(Image *dstImage, const VkImageCopy &region) const
 {
+	static constexpr VkImageAspectFlags CombinedDepthStencilAspects =
+	    VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+	if((region.srcSubresource.aspectMask == CombinedDepthStencilAspects) &&
+	   (region.dstSubresource.aspectMask == CombinedDepthStencilAspects))
+	{
+		// Depth and stencil can be specified together, copy each separately
+		VkImageCopy singleAspectRegion = region;
+		singleAspectRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
+		singleAspectRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
+		copySingleAspectTo(dstImage, singleAspectRegion);
+		singleAspectRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
+		singleAspectRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
+		copySingleAspectTo(dstImage, singleAspectRegion);
+		return;
+	}
+
+	copySingleAspectTo(dstImage, region);
+}
+
+void Image::copySingleAspectTo(Image *dstImage, const VkImageCopy &region) const
+{
 	// Image copy does not perform any conversion, it simply copies memory from
 	// an image to another image that has the same number of bytes per pixel.
 
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index 5d2f88c..2c89be2 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -59,7 +59,7 @@
 	size_t getSizeInBytes(const VkImageSubresourceRange &subresourceRange) const;
 	void getSubresourceLayout(const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout) const;
 	void bind(DeviceMemory *pDeviceMemory, VkDeviceSize pMemoryOffset);
-	void copyTo(Image *dstImage, const VkImageCopy &pRegion) const;
+	void copyTo(Image *dstImage, const VkImageCopy &region) const;
 	void copyTo(Buffer *dstBuffer, const VkBufferImageCopy &region);
 	void copyFrom(Buffer *srcBuffer, const VkBufferImageCopy &region);
 
@@ -120,6 +120,7 @@
 
 private:
 	void copy(Buffer *buffer, const VkBufferImageCopy &region, bool bufferIsSource);
+	void copySingleAspectTo(Image *dstImage, const VkImageCopy &region) const;
 	VkDeviceSize getStorageSize(VkImageAspectFlags flags) const;
 	VkDeviceSize getMultiSampledLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
 	VkDeviceSize getLayerOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;