Add validations on texture sample counts in B2T and T2B copies

This patch adds validations on the sample count of the textures used in
buffer-to-texture and texture-to-buffer copies. Vulkan SPEC requires the
textures used in vkCmdCopyBufferToImage and VkCmdCopyImageToBuffer must
have a sample count equal to VK_SAMPLE_COUNT_1_BIT.

BUG=dawn:56
TEST=dawn_unittests

Change-Id: I189923eee2d8734d5ae3b57aea1a55533e8d98b7
Reviewed-on: https://dawn-review.googlesource.com/c/5220
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index 7535d18..22f7fb8 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -133,6 +133,14 @@
             return {};
         }
 
+        MaybeError ValidateTextureSampleCountInCopyCommands(const TextureBase* texture) {
+            if (texture->GetSampleCount() > 1) {
+                return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
+            }
+
+            return {};
+        }
+
         MaybeError ComputeTextureCopyBufferSize(const Extent3D& copySize,
                                                 uint32_t rowPitch,
                                                 uint32_t imageHeight,
@@ -735,6 +743,9 @@
                     DAWN_TRY(GetDevice()->ValidateObject(copy->source.buffer.Get()));
                     DAWN_TRY(GetDevice()->ValidateObject(copy->destination.texture.Get()));
 
+                    DAWN_TRY(
+                        ValidateTextureSampleCountInCopyCommands(copy->destination.texture.Get()));
+
                     uint32_t bufferCopySize = 0;
                     DAWN_TRY(ValidateRowPitch(copy->destination.texture->GetFormat(),
                                               copy->copySize, copy->source.rowPitch));
@@ -763,6 +774,8 @@
                     DAWN_TRY(GetDevice()->ValidateObject(copy->source.texture.Get()));
                     DAWN_TRY(GetDevice()->ValidateObject(copy->destination.buffer.Get()));
 
+                    DAWN_TRY(ValidateTextureSampleCountInCopyCommands(copy->source.texture.Get()));
+
                     uint32_t bufferCopySize = 0;
                     DAWN_TRY(ValidateRowPitch(copy->source.texture->GetFormat(), copy->copySize,
                                               copy->destination.rowPitch));
diff --git a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
index d0696ac..a11731b 100644
--- a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
+++ b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
@@ -29,14 +29,14 @@
 
         dawn::Texture Create2DTexture(uint32_t width, uint32_t height, uint32_t mipLevelCount,
                                       uint32_t arrayLayerCount, dawn::TextureFormat format,
-                                      dawn::TextureUsageBit usage) {
+                                      dawn::TextureUsageBit usage, uint32_t sampleCount = 1) {
             dawn::TextureDescriptor descriptor;
             descriptor.dimension = dawn::TextureDimension::e2D;
             descriptor.size.width = width;
             descriptor.size.height = height;
             descriptor.size.depth = 1;
             descriptor.arrayLayerCount = arrayLayerCount;
-            descriptor.sampleCount = 1;
+            descriptor.sampleCount = sampleCount;
             descriptor.format = format;
             descriptor.mipLevelCount = mipLevelCount;
             descriptor.usage = usage;
@@ -409,6 +409,17 @@
     }
 }
 
+// Test multisampled textures cannot be used in B2T copies.
+TEST_F(CopyCommandTest_B2T, CopyToMultisampledTexture) {
+    uint32_t bufferSize = BufferSizeForTextureCopy(16, 16, 1);
+    dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
+    dawn::Texture destination = Create2DTexture(2, 2, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm,
+                                                dawn::TextureUsageBit::TransferDst, 4);
+
+    TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
+                {2, 2, 1});
+}
+
 class CopyCommandTest_T2B : public CopyCommandTest {
 };
 
@@ -612,3 +623,13 @@
                 256, 0, {1, 1, 1});
 }
 
+// Test multisampled textures cannot be used in T2B copies.
+TEST_F(CopyCommandTest_T2B, CopyFromMultisampledTexture) {
+    dawn::Texture source = Create2DTexture(2, 2, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm,
+                                           dawn::TextureUsageBit::TransferSrc, 4);
+    uint32_t bufferSize = BufferSizeForTextureCopy(16, 16, 1);
+    dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
+
+    TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
+                {2, 2, 1});
+}