Add validations on the format of a resolve target

This patch adds the validations on the format of a resolve target
according to the latest updates in WebGPU SPEC. WebGPU SPEC only
supports the below texture formats being used as the resolve target
of a render pass encoder:
- R8Unorm
- RG8Unorm
- RGBA8Unorm
- RGBA8UnormSrgb
- BGRA8Unorm
- BGRA8UnormSrgb
- R16Float
- RG16Float
- RGBA16Float
- RGB10A2Unorm

BUG=dawn:1244
TEST=dawn_unittests

Change-Id: I16f9c3984f4ffb4641f4f43ecdb3cc76be6a562a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/81080
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Brandon Jones <bajones@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 33961bf..823e047 100644
--- a/src/dawn/native/CommandEncoder.cpp
+++ b/src/dawn/native/CommandEncoder.cpp
@@ -214,6 +214,10 @@
                 "The resolve target %s format (%s) does not match the color attachment %s format "
                 "(%s).",
                 resolveTarget, resolveTargetFormat, attachment, attachment->GetFormat().format);
+            DAWN_INVALID_IF(
+                !resolveTarget->GetFormat().supportsResolveTarget,
+                "The resolve target %s format (%s) does not support being used as resolve target.",
+                resolveTarget, resolveTargetFormat);
 
             return {};
         }
diff --git a/src/dawn/native/Format.cpp b/src/dawn/native/Format.cpp
index 403291d..bad5643 100644
--- a/src/dawn/native/Format.cpp
+++ b/src/dawn/native/Format.cpp
@@ -158,8 +158,8 @@
 
         auto AddColorFormat =
             [&AddFormat](wgpu::TextureFormat format, bool renderable, bool supportsStorageUsage,
-                         bool supportsMultisample, uint32_t byteSize, SampleTypeBit sampleTypes,
-                         uint8_t componentCount,
+                         bool supportsMultisample, bool supportsResolveTarget, uint32_t byteSize,
+                         SampleTypeBit sampleTypes, uint8_t componentCount,
                          wgpu::TextureFormat baseFormat = wgpu::TextureFormat::Undefined) {
                 Format internalFormat;
                 internalFormat.format = format;
@@ -168,6 +168,7 @@
                 internalFormat.isSupported = true;
                 internalFormat.supportsStorageUsage = supportsStorageUsage;
                 internalFormat.supportsMultisample = supportsMultisample;
+                internalFormat.supportsResolveTarget = supportsResolveTarget;
                 internalFormat.aspects = Aspect::Color;
                 internalFormat.componentCount = componentCount;
 
@@ -216,6 +217,7 @@
             internalFormat.isSupported = isSupported;
             internalFormat.supportsStorageUsage = false;
             internalFormat.supportsMultisample = true;
+            internalFormat.supportsResolveTarget = false;
             internalFormat.aspects = Aspect::Depth;
             internalFormat.componentCount = 1;
 
@@ -246,6 +248,7 @@
             internalFormat.isSupported = isSupported;
             internalFormat.supportsStorageUsage = false;
             internalFormat.supportsMultisample = true;
+            internalFormat.supportsResolveTarget = false;
             internalFormat.aspects = Aspect::Stencil;
             internalFormat.componentCount = 1;
             internalFormat.baseFormat = baseFormat;
@@ -278,6 +281,7 @@
                 internalFormat.isSupported = isSupported;
                 internalFormat.supportsStorageUsage = false;
                 internalFormat.supportsMultisample = false;
+                internalFormat.supportsResolveTarget = false;
                 internalFormat.aspects = Aspect::Color;
                 internalFormat.componentCount = componentCount;
 
@@ -311,6 +315,7 @@
                 internalFormat.isSupported = isSupported;
                 internalFormat.supportsStorageUsage = false;
                 internalFormat.supportsMultisample = supportsMultisample;
+                internalFormat.supportsResolveTarget = false;
                 internalFormat.aspects = aspects;
                 internalFormat.componentCount = componentCount;
 
@@ -332,51 +337,51 @@
 
         // clang-format off
         // 1 byte color formats
-        AddColorFormat(wgpu::TextureFormat::R8Unorm, true, false, true, 1, kAnyFloat, 1);
-        AddColorFormat(wgpu::TextureFormat::R8Snorm, false, false, true, 1, kAnyFloat, 1);
-        AddColorFormat(wgpu::TextureFormat::R8Uint, true, false, true, 1, SampleTypeBit::Uint, 1);
-        AddColorFormat(wgpu::TextureFormat::R8Sint, true, false, true, 1, SampleTypeBit::Sint, 1);
+        AddColorFormat(wgpu::TextureFormat::R8Unorm, true, false, true, true, 1, kAnyFloat, 1);
+        AddColorFormat(wgpu::TextureFormat::R8Snorm, false, false, true, false, 1, kAnyFloat, 1);
+        AddColorFormat(wgpu::TextureFormat::R8Uint, true, false, true, false, 1, SampleTypeBit::Uint, 1);
+        AddColorFormat(wgpu::TextureFormat::R8Sint, true, false, true, false, 1, SampleTypeBit::Sint, 1);
 
         // 2 bytes color formats
-        AddColorFormat(wgpu::TextureFormat::R16Uint, true, false, true, 2, SampleTypeBit::Uint, 1);
-        AddColorFormat(wgpu::TextureFormat::R16Sint, true, false, true, 2, SampleTypeBit::Sint, 1);
-        AddColorFormat(wgpu::TextureFormat::R16Float, true, false, true, 2, kAnyFloat, 1);
-        AddColorFormat(wgpu::TextureFormat::RG8Unorm, true, false, true, 2, kAnyFloat, 2);
-        AddColorFormat(wgpu::TextureFormat::RG8Snorm, false, false, true, 2, kAnyFloat, 2);
-        AddColorFormat(wgpu::TextureFormat::RG8Uint, true, false, true, 2, SampleTypeBit::Uint, 2);
-        AddColorFormat(wgpu::TextureFormat::RG8Sint, true, false, true, 2, SampleTypeBit::Sint, 2);
+        AddColorFormat(wgpu::TextureFormat::R16Uint, true, false, true, false, 2, SampleTypeBit::Uint, 1);
+        AddColorFormat(wgpu::TextureFormat::R16Sint, true, false, true, false, 2, SampleTypeBit::Sint, 1);
+        AddColorFormat(wgpu::TextureFormat::R16Float, true, false, true, true, 2, kAnyFloat, 1);
+        AddColorFormat(wgpu::TextureFormat::RG8Unorm, true, false, true, true, 2, kAnyFloat, 2);
+        AddColorFormat(wgpu::TextureFormat::RG8Snorm, false, false, true, false, 2, kAnyFloat, 2);
+        AddColorFormat(wgpu::TextureFormat::RG8Uint, true, false, true, false, 2, SampleTypeBit::Uint, 2);
+        AddColorFormat(wgpu::TextureFormat::RG8Sint, true, false, true, false, 2, SampleTypeBit::Sint, 2);
 
         // 4 bytes color formats
-        AddColorFormat(wgpu::TextureFormat::R32Uint, true, true, false, 4, SampleTypeBit::Uint, 1);
-        AddColorFormat(wgpu::TextureFormat::R32Sint, true, true, false, 4, SampleTypeBit::Sint, 1);
-        AddColorFormat(wgpu::TextureFormat::R32Float, true, true, true, 4, SampleTypeBit::UnfilterableFloat, 1);
-        AddColorFormat(wgpu::TextureFormat::RG16Uint, true, false, true, 4, SampleTypeBit::Uint, 2);
-        AddColorFormat(wgpu::TextureFormat::RG16Sint, true, false, true, 4, SampleTypeBit::Sint, 2);
-        AddColorFormat(wgpu::TextureFormat::RG16Float, true, false, true, 4, kAnyFloat, 2);
-        AddColorFormat(wgpu::TextureFormat::RGBA8Unorm, true, true, true, 4, kAnyFloat, 4);
-        AddColorFormat(wgpu::TextureFormat::RGBA8UnormSrgb, true, false, true, 4, kAnyFloat, 4, wgpu::TextureFormat::RGBA8Unorm);
-        AddColorFormat(wgpu::TextureFormat::RGBA8Snorm, false, true, true, 4, kAnyFloat, 4);
-        AddColorFormat(wgpu::TextureFormat::RGBA8Uint, true, true, true, 4, SampleTypeBit::Uint, 4);
-        AddColorFormat(wgpu::TextureFormat::RGBA8Sint, true, true, true, 4, SampleTypeBit::Sint, 4);
-        AddColorFormat(wgpu::TextureFormat::BGRA8Unorm, true, false, true, 4, kAnyFloat, 4);
-        AddColorFormat(wgpu::TextureFormat::BGRA8UnormSrgb, true, false, true, 4, kAnyFloat, 4, wgpu::TextureFormat::BGRA8Unorm);
-        AddColorFormat(wgpu::TextureFormat::RGB10A2Unorm, true, false, true, 4, kAnyFloat, 4);
+        AddColorFormat(wgpu::TextureFormat::R32Uint, true, true, false, false, 4, SampleTypeBit::Uint, 1);
+        AddColorFormat(wgpu::TextureFormat::R32Sint, true, true, false, false, 4, SampleTypeBit::Sint, 1);
+        AddColorFormat(wgpu::TextureFormat::R32Float, true, true, true, false, 4, SampleTypeBit::UnfilterableFloat, 1);
+        AddColorFormat(wgpu::TextureFormat::RG16Uint, true, false, true, false, 4, SampleTypeBit::Uint, 2);
+        AddColorFormat(wgpu::TextureFormat::RG16Sint, true, false, true, false, 4, SampleTypeBit::Sint, 2);
+        AddColorFormat(wgpu::TextureFormat::RG16Float, true, false, true, true, 4, kAnyFloat, 2);
+        AddColorFormat(wgpu::TextureFormat::RGBA8Unorm, true, true, true, true, 4, kAnyFloat, 4);
+        AddColorFormat(wgpu::TextureFormat::RGBA8UnormSrgb, true, false, true, true, 4, kAnyFloat, 4, wgpu::TextureFormat::RGBA8Unorm);
+        AddColorFormat(wgpu::TextureFormat::RGBA8Snorm, false, true, true, false, 4, kAnyFloat, 4);
+        AddColorFormat(wgpu::TextureFormat::RGBA8Uint, true, true, true, false, 4, SampleTypeBit::Uint, 4);
+        AddColorFormat(wgpu::TextureFormat::RGBA8Sint, true, true, true, false, 4, SampleTypeBit::Sint, 4);
+        AddColorFormat(wgpu::TextureFormat::BGRA8Unorm, true, false, true, true, 4, kAnyFloat, 4);
+        AddColorFormat(wgpu::TextureFormat::BGRA8UnormSrgb, true, false, true, true, 4, kAnyFloat, 4, wgpu::TextureFormat::BGRA8Unorm);
+        AddColorFormat(wgpu::TextureFormat::RGB10A2Unorm, true, false, true, true, 4, kAnyFloat, 4);
 
-        AddColorFormat(wgpu::TextureFormat::RG11B10Ufloat, false, false, true, 4, kAnyFloat, 3);
-        AddColorFormat(wgpu::TextureFormat::RGB9E5Ufloat, false, false, false, 4, kAnyFloat, 3);
+        AddColorFormat(wgpu::TextureFormat::RG11B10Ufloat, false, false, true, false, 4, kAnyFloat, 3);
+        AddColorFormat(wgpu::TextureFormat::RGB9E5Ufloat, false, false, false, false, 4, kAnyFloat, 3);
 
         // 8 bytes color formats
-        AddColorFormat(wgpu::TextureFormat::RG32Uint, true, true, false, 8, SampleTypeBit::Uint, 2);
-        AddColorFormat(wgpu::TextureFormat::RG32Sint, true, true, false, 8, SampleTypeBit::Sint, 2);
-        AddColorFormat(wgpu::TextureFormat::RG32Float, true, true, false, 8, SampleTypeBit::UnfilterableFloat, 2);
-        AddColorFormat(wgpu::TextureFormat::RGBA16Uint, true, true, true, 8, SampleTypeBit::Uint, 4);
-        AddColorFormat(wgpu::TextureFormat::RGBA16Sint, true, true, true, 8, SampleTypeBit::Sint, 4);
-        AddColorFormat(wgpu::TextureFormat::RGBA16Float, true, true, true, 8, kAnyFloat, 4);
+        AddColorFormat(wgpu::TextureFormat::RG32Uint, true, true, false, false, 8, SampleTypeBit::Uint, 2);
+        AddColorFormat(wgpu::TextureFormat::RG32Sint, true, true, false, false, 8, SampleTypeBit::Sint, 2);
+        AddColorFormat(wgpu::TextureFormat::RG32Float, true, true, false, false, 8, SampleTypeBit::UnfilterableFloat, 2);
+        AddColorFormat(wgpu::TextureFormat::RGBA16Uint, true, true, true, false, 8, SampleTypeBit::Uint, 4);
+        AddColorFormat(wgpu::TextureFormat::RGBA16Sint, true, true, true, false, 8, SampleTypeBit::Sint, 4);
+        AddColorFormat(wgpu::TextureFormat::RGBA16Float, true, true, true, true, 8, kAnyFloat, 4);
 
         // 16 bytes color formats
-        AddColorFormat(wgpu::TextureFormat::RGBA32Uint, true, true, false, 16, SampleTypeBit::Uint, 4);
-        AddColorFormat(wgpu::TextureFormat::RGBA32Sint, true, true, false, 16, SampleTypeBit::Sint, 4);
-        AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, false, 16, SampleTypeBit::UnfilterableFloat, 4);
+        AddColorFormat(wgpu::TextureFormat::RGBA32Uint, true, true, false, false, 16, SampleTypeBit::Uint, 4);
+        AddColorFormat(wgpu::TextureFormat::RGBA32Sint, true, true, false, false, 16, SampleTypeBit::Sint, 4);
+        AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, false, false, 16, SampleTypeBit::UnfilterableFloat, 4);
 
         // Depth-stencil formats
         // TODO(dawn:666): Implement the stencil8 format
diff --git a/src/dawn/native/Format.h b/src/dawn/native/Format.h
index 228913c..4417947 100644
--- a/src/dawn/native/Format.h
+++ b/src/dawn/native/Format.h
@@ -92,6 +92,7 @@
         bool isSupported;
         bool supportsStorageUsage;
         bool supportsMultisample;
+        bool supportsResolveTarget;
         Aspect aspects;
         // Only used for renderable color formats, number of color channels.
         uint8_t componentCount;
diff --git a/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp b/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
index 9af93f6..b687fed 100644
--- a/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
@@ -676,6 +676,30 @@
         }
     }
 
+    // Tests the texture format of the resolve target must support being used as resolve target.
+    TEST_F(MultisampledRenderPassDescriptorValidationTest, ResolveTargetFormat) {
+        for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
+            if (!utils::TextureFormatSupportsMultisampling(format) ||
+                !utils::TextureFormatSupportsRendering(format)) {
+                continue;
+            }
+
+            wgpu::Texture colorTexture =
+                CreateTexture(device, wgpu::TextureDimension::e2D, format, kSize, kSize,
+                              kArrayLayers, kLevelCount, kSampleCount);
+            wgpu::Texture resolveTarget = CreateTexture(device, wgpu::TextureDimension::e2D, format,
+                                                        kSize, kSize, kArrayLayers, kLevelCount, 1);
+
+            utils::ComboRenderPassDescriptor renderPass({colorTexture.CreateView()});
+            renderPass.cColorAttachments[0].resolveTarget = resolveTarget.CreateView();
+            if (utils::TextureFormatSupportsResolveTarget(format)) {
+                AssertBeginRenderPassSuccess(&renderPass);
+            } else {
+                AssertBeginRenderPassError(&renderPass);
+            }
+        }
+    }
+
     // Tests on the sample count of depth stencil attachment.
     TEST_F(MultisampledRenderPassDescriptorValidationTest, DepthStencilAttachmentSampleCount) {
         constexpr wgpu::TextureFormat kDepthStencilFormat =
diff --git a/src/dawn/utils/TextureUtils.cpp b/src/dawn/utils/TextureUtils.cpp
index 099cad2..0e816ff 100644
--- a/src/dawn/utils/TextureUtils.cpp
+++ b/src/dawn/utils/TextureUtils.cpp
@@ -153,6 +153,64 @@
         }
     }
 
+    bool TextureFormatSupportsRendering(wgpu::TextureFormat textureFormat) {
+        switch (textureFormat) {
+            case wgpu::TextureFormat::R8Unorm:
+            case wgpu::TextureFormat::R8Uint:
+            case wgpu::TextureFormat::R8Sint:
+            case wgpu::TextureFormat::RG8Unorm:
+            case wgpu::TextureFormat::RG8Uint:
+            case wgpu::TextureFormat::RG8Sint:
+            case wgpu::TextureFormat::RGBA8Unorm:
+            case wgpu::TextureFormat::RGBA8Uint:
+            case wgpu::TextureFormat::RGBA8Sint:
+            case wgpu::TextureFormat::BGRA8Unorm:
+            case wgpu::TextureFormat::BGRA8UnormSrgb:
+            case wgpu::TextureFormat::R16Uint:
+            case wgpu::TextureFormat::R16Sint:
+            case wgpu::TextureFormat::R16Float:
+            case wgpu::TextureFormat::RG16Uint:
+            case wgpu::TextureFormat::RG16Sint:
+            case wgpu::TextureFormat::RG16Float:
+            case wgpu::TextureFormat::RGBA16Uint:
+            case wgpu::TextureFormat::RGBA16Sint:
+            case wgpu::TextureFormat::RGBA16Float:
+            case wgpu::TextureFormat::R32Uint:
+            case wgpu::TextureFormat::R32Sint:
+            case wgpu::TextureFormat::R32Float:
+            case wgpu::TextureFormat::RG32Uint:
+            case wgpu::TextureFormat::RG32Sint:
+            case wgpu::TextureFormat::RG32Float:
+            case wgpu::TextureFormat::RGBA32Uint:
+            case wgpu::TextureFormat::RGBA32Sint:
+            case wgpu::TextureFormat::RGBA32Float:
+            case wgpu::TextureFormat::RGB10A2Unorm:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    bool TextureFormatSupportsResolveTarget(wgpu::TextureFormat textureFormat) {
+        switch (textureFormat) {
+            case wgpu::TextureFormat::R8Unorm:
+            case wgpu::TextureFormat::RG8Unorm:
+            case wgpu::TextureFormat::RGBA8Unorm:
+            case wgpu::TextureFormat::RGBA8UnormSrgb:
+            case wgpu::TextureFormat::BGRA8Unorm:
+            case wgpu::TextureFormat::BGRA8UnormSrgb:
+            case wgpu::TextureFormat::R16Float:
+            case wgpu::TextureFormat::RG16Float:
+            case wgpu::TextureFormat::RGBA16Float:
+            case wgpu::TextureFormat::RGB10A2Unorm:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
     uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat) {
         switch (textureFormat) {
             case wgpu::TextureFormat::R8Unorm:
diff --git a/src/dawn/utils/TextureUtils.h b/src/dawn/utils/TextureUtils.h
index b75903b..8472bc9 100644
--- a/src/dawn/utils/TextureUtils.h
+++ b/src/dawn/utils/TextureUtils.h
@@ -232,6 +232,8 @@
     bool IsDepthOnlyFormat(wgpu::TextureFormat textureFormat);
 
     bool TextureFormatSupportsMultisampling(wgpu::TextureFormat textureFormat);
+    bool TextureFormatSupportsResolveTarget(wgpu::TextureFormat textureFormat);
+    bool TextureFormatSupportsRendering(wgpu::TextureFormat textureFormat);
 
     uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat);
     uint32_t GetTextureFormatBlockWidth(wgpu::TextureFormat textureFormat);