Add Device.CreateErrorExternalTexture()

Creating GPUExternalTexture from destroyed device should return
an error external texture instead of a valid one. Adding this API
for such usage.

Bug: 1336713, 1338182
Change-Id: Ie7d13811a9c1e8890ba91045c88af63f3fb09687
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94534
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/dawn.json b/dawn.json
index 095bcfc..9c3f328 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1023,6 +1023,11 @@
                 ]
             },
             {
+                "name": "create error external texture",
+                "returns": "external texture",
+                "tags": ["dawn"]
+            },
+            {
                 "name": "create pipeline layout",
                 "returns": "pipeline layout",
                 "args": [
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index ab133bd..f0a216d 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -1222,6 +1222,10 @@
     return BufferBase::MakeError(this, &desc);
 }
 
+ExternalTextureBase* DeviceBase::APICreateErrorExternalTexture() {
+    return ExternalTextureBase::MakeError(this);
+}
+
 // Other Device API methods
 
 // Returns true if future ticking is needed.
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index dc14e15..e9fab16 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -264,6 +264,8 @@
     // For Dawn Wire
     BufferBase* APICreateErrorBuffer();
 
+    ExternalTextureBase* APICreateErrorExternalTexture();
+
     QueueBase* APIGetQueue();
 
     bool APIGetLimits(SupportedLimits* limits) const;
diff --git a/src/dawn/native/ExternalTexture.cpp b/src/dawn/native/ExternalTexture.cpp
index 978fb9e..a23faa7 100644
--- a/src/dawn/native/ExternalTexture.cpp
+++ b/src/dawn/native/ExternalTexture.cpp
@@ -123,8 +123,9 @@
     TrackInDevice();
 }
 
+// Error external texture cannot be used in bind group.
 ExternalTextureBase::ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag)
-    : ApiObjectBase(device, tag) {}
+    : ApiObjectBase(device, tag), mState(ExternalTextureState::Destroyed) {}
 
 ExternalTextureBase::~ExternalTextureBase() = default;
 
diff --git a/src/dawn/tests/unittests/validation/ExternalTextureTests.cpp b/src/dawn/tests/unittests/validation/ExternalTextureTests.cpp
index 5f70dd7..246ce5b 100644
--- a/src/dawn/tests/unittests/validation/ExternalTextureTests.cpp
+++ b/src/dawn/tests/unittests/validation/ExternalTextureTests.cpp
@@ -541,4 +541,28 @@
     }
 }
 
+// Ensure that bind group validation catches error external textures.
+TEST_F(ExternalTextureTest, UseErrorExternalTextureInBindGroup) {
+    // Control case should succeed.
+    {
+        wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();
+        wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
+
+        wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor();
+        externalDesc.plane0 = texture.CreateView();
+        wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
+        wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
+            device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
+        utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
+    }
+
+    // Bind group creation should fail when an error external texture is present.
+    {
+        wgpu::ExternalTexture errorExternalTexture = device.CreateErrorExternalTexture();
+        wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
+            device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
+        ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl, {{0, errorExternalTexture}}));
+    }
+}
+
 }  // namespace