Improve validation errors for CreateExternalTexture

Also adds a label to ExternalTextureDescriptor to match the pattern of
all other descriptors.

Also adds missing validation that the planes must not be multisampled
(with a test) and fixes the validation unittests to not leak state from
one test to another (so they test exactly what they need to).

Bug: dawn:563
Change-Id: I88a4d7a859e67e5af85efd5ba16572c9014df6ad
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/65562
Reviewed-by: Brandon Jones <bajones@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/dawn.json b/dawn.json
index 1e92c03..3d2c0f7 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1154,6 +1154,7 @@
         "extensible": "in",
         "tags": ["dawn"],
         "members": [
+            {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
             {"name": "plane 0", "type": "texture view"},
             {"name": "format", "type": "texture format"}
         ]
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 30883f3..7077d6a 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -1287,7 +1287,8 @@
     ResultOrError<Ref<ExternalTextureBase>> DeviceBase::CreateExternalTexture(
         const ExternalTextureDescriptor* descriptor) {
         if (IsValidationEnabled()) {
-            DAWN_TRY(ValidateExternalTextureDescriptor(this, descriptor));
+            DAWN_TRY_CONTEXT(ValidateExternalTextureDescriptor(this, descriptor), "validating %s",
+                             descriptor);
         }
 
         return ExternalTextureBase::Create(this, descriptor);
diff --git a/src/dawn_native/ExternalTexture.cpp b/src/dawn_native/ExternalTexture.cpp
index d70b9b7..148e24d 100644
--- a/src/dawn_native/ExternalTexture.cpp
+++ b/src/dawn_native/ExternalTexture.cpp
@@ -30,23 +30,22 @@
                 "at least one of the passed texture views.");
         }
 
-        if ((textureView->GetTexture()->GetUsage() & wgpu::TextureUsage::TextureBinding) !=
-            wgpu::TextureUsage::TextureBinding) {
-            return DAWN_VALIDATION_ERROR(
-                "The external texture descriptor specifies a texture that was not created with "
-                "TextureUsage::TextureBinding.");
-        }
+        DAWN_INVALID_IF(
+            (textureView->GetTexture()->GetUsage() & wgpu::TextureUsage::TextureBinding) == 0,
+            "The external texture plane (%s) usage (%s) doesn't include the required usage (%s)",
+            textureView, textureView->GetTexture()->GetUsage(), wgpu::TextureUsage::TextureBinding);
 
-        if (textureView->GetDimension() != wgpu::TextureViewDimension::e2D) {
-            return DAWN_VALIDATION_ERROR(
-                "The external texture descriptor contains a texture view with a non-2D dimension.");
-        }
+        DAWN_INVALID_IF(textureView->GetDimension() != wgpu::TextureViewDimension::e2D,
+                        "The external texture plane (%s) dimension (%s) is not 2D.", textureView,
+                        textureView->GetDimension());
 
-        if (textureView->GetLevelCount() > 1) {
-            return DAWN_VALIDATION_ERROR(
-                "The external texture descriptor contains a texture view with a level count "
-                "greater than 1.");
-        }
+        DAWN_INVALID_IF(textureView->GetLevelCount() > 1,
+                        "The external texture plane (%s) mip level count (%u) is not 1.",
+                        textureView, textureView->GetLevelCount());
+
+        DAWN_INVALID_IF(textureView->GetTexture()->GetSampleCount() != 1,
+                        "The external texture plane (%s) sample count (%u) is not one.",
+                        textureView, textureView->GetTexture()->GetSampleCount());
 
         return {};
     }
@@ -66,11 +65,14 @@
             case wgpu::TextureFormat::RGBA8Unorm:
             case wgpu::TextureFormat::BGRA8Unorm:
             case wgpu::TextureFormat::RGBA16Float:
-                DAWN_TRY(ValidateExternalTexturePlane(descriptor->plane0, descriptor->format));
+                DAWN_TRY_CONTEXT(
+                    ValidateExternalTexturePlane(descriptor->plane0, descriptor->format),
+                    "validating plane0 against the external texture format (%s)",
+                    descriptor->format);
                 break;
             default:
-                return DAWN_VALIDATION_ERROR(
-                    "The external texture descriptor specifies an unsupported format.");
+                return DAWN_FORMAT_VALIDATION_ERROR(
+                    "Format (%s) is not a supported external texture format.", descriptor->format);
         }
 
         return {};
@@ -102,9 +104,8 @@
 
     MaybeError ExternalTextureBase::ValidateCanUseInSubmitNow() const {
         ASSERT(!IsError());
-        if (mState == ExternalTextureState::Destroyed) {
-            return DAWN_VALIDATION_ERROR("Destroyed external texture used in a submit");
-        }
+        DAWN_INVALID_IF(mState == ExternalTextureState::Destroyed,
+                        "Destroyed external texture %s is used in a submit.", this);
         return {};
     }
 
diff --git a/src/tests/unittests/validation/ExternalTextureTests.cpp b/src/tests/unittests/validation/ExternalTextureTests.cpp
index c484d5c..8e22c8f 100644
--- a/src/tests/unittests/validation/ExternalTextureTests.cpp
+++ b/src/tests/unittests/validation/ExternalTextureTests.cpp
@@ -54,37 +54,49 @@
     };
 
     TEST_F(ExternalTextureTest, CreateExternalTextureValidation) {
-        wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
-        wgpu::ExternalTextureDescriptor externalDesc;
-        externalDesc.format = kDefaultTextureFormat;
-
         // Creating an external texture from a 2D, single-subresource texture should succeed.
         {
+            wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
             wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
+
+            wgpu::ExternalTextureDescriptor externalDesc;
+            externalDesc.format = kDefaultTextureFormat;
             externalDesc.plane0 = texture.CreateView();
             device.CreateExternalTexture(&externalDesc);
         }
 
         // Creating an external texture with a mismatched texture view format should fail.
         {
+            wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
             textureDescriptor.format = wgpu::TextureFormat::RGBA8Uint;
             wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
+
+            wgpu::ExternalTextureDescriptor externalDesc;
+            externalDesc.format = kDefaultTextureFormat;
             externalDesc.plane0 = texture.CreateView();
             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
         }
 
         // Creating an external texture from a non-2D texture should fail.
         {
+            wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
             textureDescriptor.dimension = wgpu::TextureDimension::e3D;
             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
+
+            wgpu::ExternalTextureDescriptor externalDesc;
+            externalDesc.format = kDefaultTextureFormat;
             externalDesc.plane0 = internalTexture.CreateView();
             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
         }
 
         // Creating an external texture from a texture with mip count > 1 should fail.
         {
+            wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
             textureDescriptor.mipLevelCount = 2;
             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
+
+            wgpu::ExternalTextureDescriptor externalDesc;
+            externalDesc.format = kDefaultTextureFormat;
             externalDesc.plane0 = internalTexture.CreateView();
             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
         }
@@ -92,25 +104,45 @@
         // Creating an external texture from a texture without TextureUsage::TextureBinding should
         // fail.
         {
+            wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
             textureDescriptor.mipLevelCount = 2;
             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
+
+            wgpu::ExternalTextureDescriptor externalDesc;
+            externalDesc.format = kDefaultTextureFormat;
             externalDesc.plane0 = internalTexture.CreateView();
             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
         }
 
         // Creating an external texture with an unsupported format should fail.
         {
-            constexpr wgpu::TextureFormat kUnsupportedFormat = wgpu::TextureFormat::R8Uint;
-            textureDescriptor.format = kUnsupportedFormat;
+            wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
+            textureDescriptor.format = wgpu::TextureFormat::R8Uint;
             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
+
+            wgpu::ExternalTextureDescriptor externalDesc;
             externalDesc.plane0 = internalTexture.CreateView();
-            externalDesc.format = kUnsupportedFormat;
+            externalDesc.format = textureDescriptor.format;
+            ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
+        }
+
+        // Creating an external texture with an multisampled texture should fail.
+        {
+            wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
+            textureDescriptor.sampleCount = 4;
+            wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
+
+            wgpu::ExternalTextureDescriptor externalDesc;
+            externalDesc.format = kDefaultTextureFormat;
+            externalDesc.plane0 = internalTexture.CreateView();
             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
         }
 
         // Creating an external texture with an error texture view should fail.
         {
+            wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
+
             wgpu::TextureViewDescriptor errorViewDescriptor;
             errorViewDescriptor.format = kDefaultTextureFormat;
             errorViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
@@ -119,6 +151,8 @@
             ASSERT_DEVICE_ERROR(wgpu::TextureView errorTextureView =
                                     internalTexture.CreateView(&errorViewDescriptor));
 
+            wgpu::ExternalTextureDescriptor externalDesc;
+            externalDesc.format = kDefaultTextureFormat;
             externalDesc.plane0 = errorTextureView;
             externalDesc.format = kDefaultTextureFormat;
             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
@@ -321,4 +355,4 @@
             ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
         }
     }
-}  // namespace
\ No newline at end of file
+}  // namespace