Validate texture aspect on TextureView creation

Bug: dawn:439
Change-Id: Iba8c283e2f4551d9600410ff958d5a304a49ae2c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30724
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index 5e98cef..a246297 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -501,24 +501,8 @@
             return DAWN_VALIDATION_ERROR("mipLevel out of range");
         }
 
-        switch (textureCopy.aspect) {
-            case wgpu::TextureAspect::All:
-                break;
-            case wgpu::TextureAspect::DepthOnly:
-                if ((texture->GetFormat().aspects & Aspect::Depth) == 0) {
-                    return DAWN_VALIDATION_ERROR(
-                        "Texture does not have depth aspect for texture copy");
-                }
-                break;
-            case wgpu::TextureAspect::StencilOnly:
-                if ((texture->GetFormat().aspects & Aspect::Stencil) == 0) {
-                    return DAWN_VALIDATION_ERROR(
-                        "Texture does not have stencil aspect for texture copy");
-                }
-                break;
-            default:
-                UNREACHABLE();
-                break;
+        if (TryConvertAspect(texture->GetFormat(), textureCopy.aspect) == Aspect::None) {
+            return DAWN_VALIDATION_ERROR("Texture does not have selected aspect for texture copy.");
         }
 
         if (texture->GetSampleCount() > 1 || texture->GetFormat().HasDepthOrStencil()) {
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index c3ad9bf..c46ae88 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -271,8 +271,8 @@
         DAWN_TRY(ValidateTextureFormat(descriptor->format));
 
         DAWN_TRY(ValidateTextureAspect(descriptor->aspect));
-        if (descriptor->aspect != wgpu::TextureAspect::All) {
-            return DAWN_VALIDATION_ERROR("Texture aspect must be 'all'");
+        if (TryConvertAspect(texture->GetFormat(), descriptor->aspect) == Aspect::None) {
+            return DAWN_VALIDATION_ERROR("Texture does not have selected aspect for texture view.");
         }
 
         // TODO(jiawei.shao@intel.com): check stuff based on resource limits
@@ -358,15 +358,19 @@
     }
 
     Aspect ConvertAspect(const Format& format, wgpu::TextureAspect aspect) {
+        Aspect aspectMask = TryConvertAspect(format, aspect);
+        ASSERT(aspectMask != Aspect::None);
+        return aspectMask;
+    }
+
+    Aspect TryConvertAspect(const Format& format, wgpu::TextureAspect aspect) {
         switch (aspect) {
             case wgpu::TextureAspect::All:
                 return format.aspects;
             case wgpu::TextureAspect::DepthOnly:
-                ASSERT(format.aspects & Aspect::Depth);
-                return Aspect::Depth;
+                return format.aspects & Aspect::Depth;
             case wgpu::TextureAspect::StencilOnly:
-                ASSERT(format.aspects & Aspect::Stencil);
-                return Aspect::Stencil;
+                return format.aspects & Aspect::Stencil;
         }
     }
 
diff --git a/src/dawn_native/Texture.h b/src/dawn_native/Texture.h
index 11dd965..001f5d5 100644
--- a/src/dawn_native/Texture.h
+++ b/src/dawn_native/Texture.h
@@ -73,9 +73,19 @@
         wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Storage |
         wgpu::TextureUsage::OutputAttachment;
 
+    // Convert the TextureAspect to an Aspect mask for the format. ASSERTs if the aspect
+    // does not exist in the format.
+    // Also ASSERTs if "All" is selected and results in more than one aspect.
     Aspect ConvertSingleAspect(const Format& format, wgpu::TextureAspect aspect);
+
+    // Convert the TextureAspect to an Aspect mask for the format. ASSERTs if the aspect
+    // does not exist in the format.
     Aspect ConvertAspect(const Format& format, wgpu::TextureAspect aspect);
 
+    // Try to convert the TextureAspect to an Aspect mask for the format. May return
+    // Aspect::None.
+    Aspect TryConvertAspect(const Format& format, wgpu::TextureAspect aspect);
+
     struct SubresourceRange {
         uint32_t baseMipLevel;
         uint32_t levelCount;
diff --git a/src/tests/unittests/validation/TextureViewValidationTests.cpp b/src/tests/unittests/validation/TextureViewValidationTests.cpp
index c5c3242..b31439a 100644
--- a/src/tests/unittests/validation/TextureViewValidationTests.cpp
+++ b/src/tests/unittests/validation/TextureViewValidationTests.cpp
@@ -344,20 +344,43 @@
         ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
     }
 
-    // Test that only TextureAspect::All is supported
-    TEST_F(TextureViewValidationTest, AspectMustBeAll) {
+    // Test that the selected TextureAspects must exist in the texture format
+    TEST_F(TextureViewValidationTest, AspectMustExist) {
         wgpu::TextureDescriptor descriptor = {};
         descriptor.size = {1, 1, 1};
-        descriptor.format = wgpu::TextureFormat::Depth32Float;
         descriptor.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment;
-        wgpu::Texture texture = device.CreateTexture(&descriptor);
 
-        wgpu::TextureViewDescriptor viewDescriptor = {};
-        viewDescriptor.aspect = wgpu::TextureAspect::All;
-        texture.CreateView(&viewDescriptor);
+        // Can select: All and DepthOnly from Depth32Float, but not StencilOnly
+        {
+            descriptor.format = wgpu::TextureFormat::Depth32Float;
+            wgpu::Texture texture = device.CreateTexture(&descriptor);
 
-        viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly;
-        ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor));
+            wgpu::TextureViewDescriptor viewDescriptor = {};
+            viewDescriptor.aspect = wgpu::TextureAspect::All;
+            texture.CreateView(&viewDescriptor);
+
+            viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly;
+            texture.CreateView(&viewDescriptor);
+
+            viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly;
+            ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor));
+        }
+
+        // Can select: All, DepthOnly, and StencilOnly from Depth24PlusStencil8
+        {
+            descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
+            wgpu::Texture texture = device.CreateTexture(&descriptor);
+
+            wgpu::TextureViewDescriptor viewDescriptor = {};
+            viewDescriptor.aspect = wgpu::TextureAspect::All;
+            texture.CreateView(&viewDescriptor);
+
+            viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly;
+            texture.CreateView(&viewDescriptor);
+
+            viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly;
+            texture.CreateView(&viewDescriptor);
+        }
     }
 
 }  // anonymous namespace