Fix copying of multisample images

Multisample images can be copied to other multisample images with the
same number of samples, without undergoing multisample resolve.

We were using the Blitter::copy() code path both for vkCmdCopyImage and
attachment resolve operations at the end of subpasses, leading to
resolve operations happening on copy commands. They are now detangled
and copy() is able to handle multiple samples the same way as 3D
slices.

Bug: b/159210008
Change-Id: I4c285ca7ca58e9f8c6cf7bd942041e038b042cb9
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/46129
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 7fb2182..ddb594c 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -322,28 +322,9 @@
 
 	Format srcFormat = getFormat(srcAspect);
 	Format dstFormat = dstImage->getFormat(dstAspect);
-
-	if((samples > VK_SAMPLE_COUNT_1_BIT) && (imageType == VK_IMAGE_TYPE_2D) && !format.isUnnormalizedInteger())
-	{
-		// Requires multisampling resolve
-		VkImageBlit blitRegion;
-		blitRegion.srcSubresource = region.srcSubresource;
-		blitRegion.srcOffsets[0] = region.srcOffset;
-		blitRegion.srcOffsets[1].x = blitRegion.srcOffsets[0].x + region.extent.width;
-		blitRegion.srcOffsets[1].y = blitRegion.srcOffsets[0].y + region.extent.height;
-		blitRegion.srcOffsets[1].z = blitRegion.srcOffsets[0].z + region.extent.depth;
-
-		blitRegion.dstSubresource = region.dstSubresource;
-		blitRegion.dstOffsets[0] = region.dstOffset;
-		blitRegion.dstOffsets[1].x = blitRegion.dstOffsets[0].x + region.extent.width;
-		blitRegion.dstOffsets[1].y = blitRegion.dstOffsets[0].y + region.extent.height;
-		blitRegion.dstOffsets[1].z = blitRegion.dstOffsets[0].z + region.extent.depth;
-
-		return device->getBlitter()->blit(this, dstImage, blitRegion, VK_FILTER_NEAREST);
-	}
-
 	int bytesPerBlock = srcFormat.bytesPerBlock();
 	ASSERT(bytesPerBlock == dstFormat.bytesPerBlock());
+	ASSERT(samples == dstImage->samples);
 
 	const uint8_t *srcMem = static_cast<const uint8_t *>(getTexelPointer(region.srcOffset, { region.srcSubresource.aspectMask, region.srcSubresource.mipLevel, region.srcSubresource.baseArrayLayer }));
 	uint8_t *dstMem = static_cast<uint8_t *>(dstImage->getTexelPointer(region.dstOffset, { region.dstSubresource.aspectMask, region.dstSubresource.mipLevel, region.dstSubresource.baseArrayLayer }));
@@ -357,7 +338,11 @@
 	VkExtent3D dstExtent = dstImage->getMipLevelExtent(dstAspect, region.dstSubresource.mipLevel);
 	VkExtent3D copyExtent = imageExtentInBlocks(region.extent, srcAspect);
 
-	bool isSingleSlice = (copyExtent.depth == 1);
+	// Multisample images are currently implemented similar to 3D images by storing one sample per slice.
+	// TODO(b/160600347): Store samples consecutively.
+	uint32_t sliceCount = copyExtent.depth * samples;
+
+	bool isSingleSlice = (sliceCount == 1);
 	bool isSingleLine = (copyExtent.height == 1) && isSingleSlice;
 	// In order to copy multiple lines using a single memcpy call, we
 	// have to make sure that we need to copy the entire line and that
@@ -397,7 +382,7 @@
 	}
 	else if(isEntireSlice)  // Copy multiple slices
 	{
-		size_t copySize = copyExtent.depth * srcSlicePitchBytes;
+		size_t copySize = sliceCount * srcSlicePitchBytes;
 		ASSERT((srcMem + copySize) < end());
 		ASSERT((dstMem + copySize) < dstImage->end());
 		memcpy(dstMem, srcMem, copySize);
@@ -406,7 +391,7 @@
 	{
 		size_t copySize = copyExtent.height * srcRowPitchBytes;
 
-		for(uint32_t z = 0; z < copyExtent.depth; z++, dstMem += dstSlicePitchBytes, srcMem += srcSlicePitchBytes)
+		for(uint32_t z = 0; z < sliceCount; z++, dstMem += dstSlicePitchBytes, srcMem += srcSlicePitchBytes)
 		{
 			ASSERT((srcMem + copySize) < end());
 			ASSERT((dstMem + copySize) < dstImage->end());
@@ -417,7 +402,7 @@
 	{
 		size_t copySize = copyExtent.width * bytesPerBlock;
 
-		for(uint32_t z = 0; z < copyExtent.depth; z++, dstMem += dstSlicePitchBytes, srcMem += srcSlicePitchBytes)
+		for(uint32_t z = 0; z < sliceCount; z++, dstMem += dstSlicePitchBytes, srcMem += srcSlicePitchBytes)
 		{
 			const uint8_t *srcSlice = srcMem;
 			uint8_t *dstSlice = dstMem;
@@ -458,6 +443,7 @@
 	int bytesPerBlock = copyFormat.bytesPerBlock();
 	int bufferRowPitchBytes = bufferExtent.width * bytesPerBlock;
 	int bufferSlicePitchBytes = bufferExtent.height * bufferRowPitchBytes;
+	ASSERT(samples == 1);
 
 	uint8_t *bufferMemory = static_cast<uint8_t *>(buffer->getOffsetPointer(region.bufferOffset));
 	uint8_t *imageMemory = static_cast<uint8_t *>(getTexelPointer(region.imageOffset, { region.imageSubresource.aspectMask, region.imageSubresource.mipLevel, region.imageSubresource.baseArrayLayer }));
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index a351ab2..e8a6cad 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -181,7 +181,7 @@
 		UNIMPLEMENTED("b/148242443: levelCount != 1");  // FIXME(b/148242443)
 	}
 
-	VkImageCopy region;
+	VkImageResolve region;
 	region.srcSubresource = {
 		subresourceRange.aspectMask,
 		subresourceRange.baseMipLevel,
@@ -199,7 +199,7 @@
 	region.extent = image->getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask),
 	                                         subresourceRange.baseMipLevel);
 
-	image->copyTo(resolveAttachment->image, region);
+	image->resolveTo(resolveAttachment->image, region);
 }
 
 void ImageView::resolve(ImageView *resolveAttachment)
@@ -209,7 +209,7 @@
 		UNIMPLEMENTED("b/148242443: levelCount != 1");  // FIXME(b/148242443)
 	}
 
-	VkImageCopy region;
+	VkImageResolve region;
 	region.srcSubresource = {
 		subresourceRange.aspectMask,
 		subresourceRange.baseMipLevel,
@@ -227,7 +227,7 @@
 	region.extent = image->getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask),
 	                                         subresourceRange.baseMipLevel);
 
-	image->copyTo(resolveAttachment->image, region);
+	image->resolveTo(resolveAttachment->image, region);
 }
 
 void ImageView::resolveWithLayerMask(ImageView *resolveAttachment, uint32_t layerMask)