Allow creating texture views from destroyed textures

Bug: dawn:1031
Change-Id: I3af52d5c53c4ccf2c30a4eccb9c50dfe2e822f25
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/60221
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index a5e91d2..2c43bc1 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -323,9 +323,6 @@
         // Parent texture should have been already validated.
         ASSERT(texture);
         ASSERT(!texture->IsError());
-        if (texture->GetTextureState() == TextureBase::TextureState::Destroyed) {
-            return DAWN_VALIDATION_ERROR("Destroyed texture used to create texture view");
-        }
 
         DAWN_TRY(ValidateTextureViewDimension(descriptor->dimension));
         if (descriptor->dimension == wgpu::TextureViewDimension::e1D) {
diff --git a/src/dawn_native/metal/TextureMTL.mm b/src/dawn_native/metal/TextureMTL.mm
index fbce964..bcc1652 100644
--- a/src/dawn_native/metal/TextureMTL.mm
+++ b/src/dawn_native/metal/TextureMTL.mm
@@ -660,6 +660,12 @@
 
     MaybeError TextureView::Initialize(const TextureViewDescriptor* descriptor) {
         Texture* texture = ToBackend(GetTexture());
+
+        // Texture could be destroyed by the time we make a view.
+        if (GetTexture()->GetTextureState() == Texture::TextureState::Destroyed) {
+            return {};
+        }
+
         id<MTLTexture> mtlTexture = texture->GetMTLTexture();
 
         if (!UsageNeedsTextureView(texture->GetInternalUsage())) {
diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp
index dc4cddf..f58030e 100644
--- a/src/dawn_native/opengl/TextureGL.cpp
+++ b/src/dawn_native/opengl/TextureGL.cpp
@@ -533,6 +533,11 @@
         mTarget = TargetForTextureViewDimension(descriptor->dimension, descriptor->arrayLayerCount,
                                                 texture->GetSampleCount());
 
+        // Texture could be destroyed by the time we make a view.
+        if (GetTexture()->GetTextureState() == Texture::TextureState::Destroyed) {
+            return;
+        }
+
         if (!UsageNeedsTextureView(texture->GetUsage())) {
             mHandle = 0;
         } else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 348861a..36c296e 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -1180,6 +1180,11 @@
             return {};
         }
 
+        // Texture could be destroyed by the time we make a view.
+        if (GetTexture()->GetTextureState() == Texture::TextureState::Destroyed) {
+            return {};
+        }
+
         Device* device = ToBackend(GetTexture()->GetDevice());
 
         VkImageViewCreateInfo createInfo;
diff --git a/src/tests/end2end/TextureViewTests.cpp b/src/tests/end2end/TextureViewTests.cpp
index afacd94..f38a4d9 100644
--- a/src/tests/end2end/TextureViewTests.cpp
+++ b/src/tests/end2end/TextureViewTests.cpp
@@ -679,6 +679,23 @@
     wgpu::TextureView view = texture.CreateView();
 }
 
+// Test that a texture view can be created from a destroyed texture without
+// backend errors.
+TEST_P(TextureViewTest, DestroyedTexture) {
+    wgpu::TextureDescriptor descriptor;
+    descriptor.size = {4, 4, 2};
+    descriptor.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::CopyDst;
+    descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
+
+    wgpu::Texture texture = device.CreateTexture(&descriptor);
+    texture.Destroy();
+
+    wgpu::TextureViewDescriptor viewDesc = {};
+    viewDesc.baseArrayLayer = 1;
+    viewDesc.arrayLayerCount = 1;
+    wgpu::TextureView view = texture.CreateView(&viewDesc);
+}
+
 DAWN_INSTANTIATE_TEST(TextureViewTest,
                       D3D12Backend(),
                       MetalBackend(),
diff --git a/src/tests/unittests/validation/TextureViewValidationTests.cpp b/src/tests/unittests/validation/TextureViewValidationTests.cpp
index e60ba91..7f633bf 100644
--- a/src/tests/unittests/validation/TextureViewValidationTests.cpp
+++ b/src/tests/unittests/validation/TextureViewValidationTests.cpp
@@ -510,13 +510,13 @@
         }
     }
 
-    // Test that it's invalid to create a texture view from a destroyed texture
+    // Test that it's valid to create a texture view from a destroyed texture
     TEST_F(TextureViewValidationTest, DestroyCreateTextureView) {
         wgpu::Texture texture = Create2DArrayTexture(device, 1);
         wgpu::TextureViewDescriptor descriptor =
             CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
         texture.Destroy();
-        ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
+        texture.CreateView(&descriptor);
     }
 
     // Test that the selected TextureAspects must exist in the texture format