Format: Move the baseType to be per-aspect.

This also introduces a per-aspect supportedComponentTypes that exactly
mirrors baseType for now but will contain additional bits in the future
(like DepthComparison for depth textures).

It is also a step towards being able to create single-aspect view of
depth-stencil textures to sample either the depth or the stencil
component.

Bug: dawn:527

Change-Id: I3ab224d07c136c682cc2993b9a8599237d318130
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30103
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/BindGroup.cpp b/src/dawn_native/BindGroup.cpp
index 9de7fd0..db46993 100644
--- a/src/dawn_native/BindGroup.cpp
+++ b/src/dawn_native/BindGroup.cpp
@@ -36,7 +36,7 @@
                                          const uint64_t maxBindingSize) {
             if (entry.buffer == nullptr || entry.sampler != nullptr ||
                 entry.textureView != nullptr) {
-                return DAWN_VALIDATION_ERROR("expected buffer binding");
+                return DAWN_VALIDATION_ERROR("Expected buffer binding");
             }
             DAWN_TRY(device->ValidateObject(entry.buffer));
 
@@ -98,32 +98,41 @@
                                           const BindingInfo& bindingInfo) {
             if (entry.textureView == nullptr || entry.sampler != nullptr ||
                 entry.buffer != nullptr) {
-                return DAWN_VALIDATION_ERROR("expected texture binding");
+                return DAWN_VALIDATION_ERROR("Expected texture binding");
             }
             DAWN_TRY(device->ValidateObject(entry.textureView));
 
-            TextureBase* texture = entry.textureView->GetTexture();
+            TextureViewBase* view = entry.textureView;
 
+            Aspect aspect = view->GetAspects();
+            if (!HasOneBit(aspect)) {
+                return DAWN_VALIDATION_ERROR("Texture view must select a single aspect");
+            }
+
+            TextureBase* texture = view->GetTexture();
             if (!(texture->GetUsage() & requiredUsage)) {
-                return DAWN_VALIDATION_ERROR("texture binding usage mismatch");
+                return DAWN_VALIDATION_ERROR("Texture binding usage mismatch");
             }
 
             if (texture->IsMultisampledTexture() != multisampled) {
-                return DAWN_VALIDATION_ERROR("texture multisampling mismatch");
+                return DAWN_VALIDATION_ERROR("Texture multisampling mismatch");
             }
 
             switch (requiredUsage) {
                 case wgpu::TextureUsage::Sampled: {
-                    if (!texture->GetFormat().HasComponentType(
-                            Format::TextureComponentTypeToFormatType(
-                                bindingInfo.textureComponentType))) {
-                        return DAWN_VALIDATION_ERROR("texture component type usage mismatch");
+                    ComponentTypeBit supportedTypes =
+                        texture->GetFormat().GetAspectInfo(aspect).supportedComponentTypes;
+                    ComponentTypeBit requiredType =
+                        ToComponentTypeBit(bindingInfo.textureComponentType);
+
+                    if ((supportedTypes & requiredType) == 0) {
+                        return DAWN_VALIDATION_ERROR("Texture component type usage mismatch");
                     }
                     break;
                 }
                 case wgpu::TextureUsage::Storage: {
                     if (texture->GetFormat().format != bindingInfo.storageTextureFormat) {
-                        return DAWN_VALIDATION_ERROR("storage texture format mismatch");
+                        return DAWN_VALIDATION_ERROR("Storage texture format mismatch");
                     }
                     break;
                 }
@@ -133,7 +142,7 @@
             }
 
             if (entry.textureView->GetDimension() != bindingInfo.viewDimension) {
-                return DAWN_VALIDATION_ERROR("texture view dimension mismatch");
+                return DAWN_VALIDATION_ERROR("Texture view dimension mismatch");
             }
 
             return {};
@@ -144,7 +153,7 @@
                                           wgpu::BindingType bindingType) {
             if (entry.sampler == nullptr || entry.textureView != nullptr ||
                 entry.buffer != nullptr) {
-                return DAWN_VALIDATION_ERROR("expected sampler binding");
+                return DAWN_VALIDATION_ERROR("Expected sampler binding");
             }
             DAWN_TRY(device->ValidateObject(entry.sampler));
 
diff --git a/src/dawn_native/Format.cpp b/src/dawn_native/Format.cpp
index 0fbd808..5bf672c 100644
--- a/src/dawn_native/Format.cpp
+++ b/src/dawn_native/Format.cpp
@@ -24,44 +24,38 @@
 
     namespace {
 
-        static const AspectInfo kStencil8AspectInfo = {{1, 1, 1}};
-
+        static const AspectInfo kStencil8AspectInfo = {{1, 1, 1},
+                                                       wgpu::TextureComponentType::Uint,
+                                                       ComponentTypeBit::Uint};
     }
 
     // Format
 
-    // static
-    Format::Type Format::TextureComponentTypeToFormatType(
-        wgpu::TextureComponentType componentType) {
-        switch (componentType) {
+    ComponentTypeBit ToComponentTypeBit(wgpu::TextureComponentType type) {
+        switch (type) {
             case wgpu::TextureComponentType::Float:
             case wgpu::TextureComponentType::Sint:
             case wgpu::TextureComponentType::Uint:
+                // When the compiler complains that you need to add a case statement here, please
+                // also add a corresponding static assert below!
                 break;
         }
-        // Check that Type correctly mirrors TextureComponentType except for "Other".
-        static_assert(static_cast<Type>(wgpu::TextureComponentType::Float) == Type::Float, "");
-        static_assert(static_cast<Type>(wgpu::TextureComponentType::Sint) == Type::Sint, "");
-        static_assert(static_cast<Type>(wgpu::TextureComponentType::Uint) == Type::Uint, "");
-        return static_cast<Type>(componentType);
-    }
 
-    // static
-    wgpu::TextureComponentType Format::FormatTypeToTextureComponentType(Type type) {
-        switch (type) {
-            case Type::Float:
-            case Type::Sint:
-            case Type::Uint:
-                break;
-
-            case Type::Other:
-                UNREACHABLE();
-        }
-        // Check that Type correctly mirrors TextureComponentType except for "Other".
-        static_assert(static_cast<Type>(wgpu::TextureComponentType::Float) == Type::Float, "");
-        static_assert(static_cast<Type>(wgpu::TextureComponentType::Sint) == Type::Sint, "");
-        static_assert(static_cast<Type>(wgpu::TextureComponentType::Uint) == Type::Uint, "");
-        return static_cast<wgpu::TextureComponentType>(type);
+        // Check that ComponentTypeBit bits are in the same position / order as the respective
+        // wgpu::TextureComponentType value.
+        static_assert(ComponentTypeBit::Float ==
+                          static_cast<ComponentTypeBit>(
+                              1 << static_cast<uint32_t>(wgpu::TextureComponentType::Float)),
+                      "");
+        static_assert(ComponentTypeBit::Uint ==
+                          static_cast<ComponentTypeBit>(
+                              1 << static_cast<uint32_t>(wgpu::TextureComponentType::Uint)),
+                      "");
+        static_assert(ComponentTypeBit::Sint ==
+                          static_cast<ComponentTypeBit>(
+                              1 << static_cast<uint32_t>(wgpu::TextureComponentType::Sint)),
+                      "");
+        return static_cast<ComponentTypeBit>(1 << static_cast<uint32_t>(type));
     }
 
     bool Format::IsColor() const {
@@ -80,10 +74,6 @@
         return (aspects & (Aspect::Depth | Aspect::Stencil)) != 0;
     }
 
-    bool Format::HasComponentType(Type componentType) const {
-        return componentType == type;
-    }
-
     const AspectInfo& Format::GetAspectInfo(wgpu::TextureAspect aspect) const {
         return GetAspectInfo(ConvertAspect(*this, aspect));
     }
@@ -121,7 +111,7 @@
         FormatTable table;
         std::bitset<kKnownFormatCount> formatsSet;
 
-        using Type = Format::Type;
+        using Type = wgpu::TextureComponentType;
 
         auto AddFormat = [&table, &formatsSet](Format format) {
             size_t index = ComputeFormatIndex(format.format);
@@ -145,15 +135,16 @@
             internalFormat.isSupported = true;
             internalFormat.supportsStorageUsage = supportsStorageUsage;
             internalFormat.aspects = Aspect::Color;
-            internalFormat.type = type;
             internalFormat.firstAspect.block.byteSize = byteSize;
             internalFormat.firstAspect.block.width = 1;
             internalFormat.firstAspect.block.height = 1;
+            internalFormat.firstAspect.baseType = type;
+            internalFormat.firstAspect.supportedComponentTypes = ToComponentTypeBit(type);
             AddFormat(internalFormat);
         };
 
         auto AddDepthStencilFormat = [&AddFormat](wgpu::TextureFormat format, Aspect aspects,
-                                                  uint32_t byteSize) {
+                                                  uint32_t byteSize, bool isDepthSampleable) {
             Format internalFormat;
             internalFormat.format = format;
             internalFormat.isRenderable = true;
@@ -161,26 +152,15 @@
             internalFormat.isSupported = true;
             internalFormat.supportsStorageUsage = false;
             internalFormat.aspects = aspects;
-            internalFormat.type = Type::Other;
             internalFormat.firstAspect.block.byteSize = byteSize;
             internalFormat.firstAspect.block.width = 1;
             internalFormat.firstAspect.block.height = 1;
-            AddFormat(internalFormat);
-        };
-
-        auto AddDepthFormat = [&AddFormat](wgpu::TextureFormat format, uint32_t byteSize,
-                                           Type type) {
-            Format internalFormat;
-            internalFormat.format = format;
-            internalFormat.isRenderable = true;
-            internalFormat.isCompressed = false;
-            internalFormat.isSupported = true;
-            internalFormat.supportsStorageUsage = false;
-            internalFormat.aspects = Aspect::Depth;
-            internalFormat.type = type;
-            internalFormat.firstAspect.block.byteSize = byteSize;
-            internalFormat.firstAspect.block.width = 1;
-            internalFormat.firstAspect.block.height = 1;
+            internalFormat.firstAspect.baseType = wgpu::TextureComponentType::Float;
+            if (isDepthSampleable) {
+                internalFormat.firstAspect.supportedComponentTypes = ComponentTypeBit::Float;
+            } else {
+                internalFormat.firstAspect.supportedComponentTypes = ComponentTypeBit::None;
+            }
             AddFormat(internalFormat);
         };
 
@@ -193,10 +173,11 @@
             internalFormat.isSupported = isSupported;
             internalFormat.supportsStorageUsage = false;
             internalFormat.aspects = Aspect::Color;
-            internalFormat.type = Type::Float;
             internalFormat.firstAspect.block.byteSize = byteSize;
             internalFormat.firstAspect.block.width = width;
             internalFormat.firstAspect.block.height = height;
+            internalFormat.firstAspect.baseType = wgpu::TextureComponentType::Float;
+            internalFormat.firstAspect.supportedComponentTypes = ComponentTypeBit::Float;
             AddFormat(internalFormat);
         };
 
@@ -249,15 +230,13 @@
         AddColorFormat(wgpu::TextureFormat::RGBA32Sint, true, true, 16, Type::Sint);
         AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, 16, Type::Float);
 
-        // Depth only formats
-        AddDepthFormat(wgpu::TextureFormat::Depth32Float, 4, Type::Float);
-
-        // Packed depth/depth-stencil formats
-        AddDepthStencilFormat(wgpu::TextureFormat::Depth24Plus, Aspect::Depth, 4);
+        // Depth-stencil formats
+        AddDepthStencilFormat(wgpu::TextureFormat::Depth32Float, Aspect::Depth, 4, true);
+        AddDepthStencilFormat(wgpu::TextureFormat::Depth24Plus, Aspect::Depth, 4, false);
         // TODO(cwallez@chromium.org): It isn't clear if this format should be copyable
         // because its size isn't well defined, is it 4, 5 or 8?
         AddDepthStencilFormat(wgpu::TextureFormat::Depth24PlusStencil8,
-                              Aspect::Depth | Aspect::Stencil, 4);
+                              Aspect::Depth | Aspect::Stencil, 4, false);
 
         // BC compressed formats
         bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC);
diff --git a/src/dawn_native/Format.h b/src/dawn_native/Format.h
index 3052f67..392254e 100644
--- a/src/dawn_native/Format.h
+++ b/src/dawn_native/Format.h
@@ -28,6 +28,17 @@
     enum class Aspect : uint8_t;
     class DeviceBase;
 
+    // This mirrors wgpu::TextureComponentType as a bitmask instead.
+    enum class ComponentTypeBit : uint8_t {
+        None = 0x0,
+        Float = 0x1,
+        Sint = 0x2,
+        Uint = 0x4,
+    };
+
+    // Converts an wgpu::TextureComponentType to its bitmask representation.
+    ComponentTypeBit ToComponentTypeBit(wgpu::TextureComponentType type);
+
     struct TexelBlockInfo {
         uint32_t byteSize;
         uint32_t width;
@@ -36,6 +47,8 @@
 
     struct AspectInfo {
         TexelBlockInfo block;
+        wgpu::TextureComponentType baseType;
+        ComponentTypeBit supportedComponentTypes;
     };
 
     // The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the
@@ -47,30 +60,18 @@
 
     // A wgpu::TextureFormat along with all the information about it necessary for validation.
     struct Format {
-        enum class Type {
-            Float,
-            Sint,
-            Uint,
-            Other,
-        };
-
         wgpu::TextureFormat format;
         bool isRenderable;
         bool isCompressed;
         // A format can be known but not supported because it is part of a disabled extension.
         bool isSupported;
         bool supportsStorageUsage;
-        Type type;
         Aspect aspects;
 
-        static Type TextureComponentTypeToFormatType(wgpu::TextureComponentType componentType);
-        static wgpu::TextureComponentType FormatTypeToTextureComponentType(Type type);
-
         bool IsColor() const;
         bool HasDepth() const;
         bool HasStencil() const;
         bool HasDepthOrStencil() const;
-        bool HasComponentType(Type componentType) const;
 
         const AspectInfo& GetAspectInfo(wgpu::TextureAspect aspect) const;
         const AspectInfo& GetAspectInfo(Aspect aspect) const;
@@ -96,4 +97,13 @@
 
 }  // namespace dawn_native
 
+namespace wgpu {
+
+    template <>
+    struct IsDawnBitmask<dawn_native::ComponentTypeBit> {
+        static constexpr bool enable = true;
+    };
+
+}  // namespace wgpu
+
 #endif  // DAWNNATIVE_FORMAT_H_
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index 8d267b6..c00990f 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -163,7 +163,7 @@
                 return DAWN_VALIDATION_ERROR("Color format must be color renderable");
             }
             if (fragmentWritten &&
-                fragmentOutputBaseType != Format::FormatTypeToTextureComponentType(format->type)) {
+                fragmentOutputBaseType != format->GetAspectInfo(Aspect::Color).baseType) {
                 return DAWN_VALIDATION_ERROR(
                     "Color format must match the fragment stage output type");
             }
diff --git a/src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp b/src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp
index be30ab2..12216f5 100644
--- a/src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp
+++ b/src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp
@@ -63,12 +63,12 @@
 
             // RESOLVE_MODE_AVERAGE is only valid for non-integer formats.
             // TODO: Investigate and determine how integer format resolves should work in WebGPU.
-            switch (resolveDestination->GetFormat().type) {
-                case Format::Type::Sint:
-                case Format::Type::Uint:
+            switch (resolveDestination->GetFormat().GetAspectInfo(Aspect::Color).baseType) {
+                case wgpu::TextureComponentType::Sint:
+                case wgpu::TextureComponentType::Uint:
                     resolveParameters.ResolveMode = D3D12_RESOLVE_MODE_MAX;
                     break;
-                default:
+                case wgpu::TextureComponentType::Float:
                     resolveParameters.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE;
                     break;
             }
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 141ae67..f75f854 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -928,21 +928,27 @@
                 if (attachmentInfo->loadOp == wgpu::LoadOp::Clear) {
                     gl.ColorMaski(i, true, true, true, true);
 
-                    const Format& attachmentFormat = attachmentInfo->view->GetFormat();
-                    if (attachmentFormat.HasComponentType(Format::Type::Float)) {
-                        const std::array<float, 4> appliedClearColor =
-                            ConvertToFloatColor(attachmentInfo->clearColor);
-                        gl.ClearBufferfv(GL_COLOR, i, appliedClearColor.data());
-                    } else if (attachmentFormat.HasComponentType(Format::Type::Uint)) {
-                        const std::array<uint32_t, 4> appliedClearColor =
-                            ConvertToUnsignedIntegerColor(attachmentInfo->clearColor);
-                        gl.ClearBufferuiv(GL_COLOR, i, appliedClearColor.data());
-                    } else if (attachmentFormat.HasComponentType(Format::Type::Sint)) {
-                        const std::array<int32_t, 4> appliedClearColor =
-                            ConvertToSignedIntegerColor(attachmentInfo->clearColor);
-                        gl.ClearBufferiv(GL_COLOR, i, appliedClearColor.data());
-                    } else {
-                        UNREACHABLE();
+                    wgpu::TextureComponentType baseType =
+                        attachmentInfo->view->GetFormat().GetAspectInfo(Aspect::Color).baseType;
+                    switch (baseType) {
+                        case wgpu::TextureComponentType::Float: {
+                            const std::array<float, 4> appliedClearColor =
+                                ConvertToFloatColor(attachmentInfo->clearColor);
+                            gl.ClearBufferfv(GL_COLOR, i, appliedClearColor.data());
+                            break;
+                        }
+                        case wgpu::TextureComponentType::Uint: {
+                            const std::array<uint32_t, 4> appliedClearColor =
+                                ConvertToUnsignedIntegerColor(attachmentInfo->clearColor);
+                            gl.ClearBufferuiv(GL_COLOR, i, appliedClearColor.data());
+                            break;
+                        }
+                        case wgpu::TextureComponentType::Sint: {
+                            const std::array<int32_t, 4> appliedClearColor =
+                                ConvertToSignedIntegerColor(attachmentInfo->clearColor);
+                            gl.ClearBufferiv(GL_COLOR, i, appliedClearColor.data());
+                            break;
+                        }
                     }
                 }
 
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 73a2f97..2138f98 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -308,29 +308,33 @@
 
                     attachments[attachmentCount] = view->GetHandle();
 
-                    const Format& attachmentFormat = view->GetFormat();
-                    if (attachmentFormat.HasComponentType(Format::Type::Float)) {
-                        const std::array<float, 4> appliedClearColor =
-                            ConvertToFloatColor(attachmentInfo.clearColor);
-                        for (uint32_t i = 0; i < 4; ++i) {
-                            clearValues[attachmentCount].color.float32[i] = appliedClearColor[i];
+                    switch (view->GetFormat().GetAspectInfo(Aspect::Color).baseType) {
+                        case wgpu::TextureComponentType::Float: {
+                            const std::array<float, 4> appliedClearColor =
+                                ConvertToFloatColor(attachmentInfo.clearColor);
+                            for (uint32_t i = 0; i < 4; ++i) {
+                                clearValues[attachmentCount].color.float32[i] =
+                                    appliedClearColor[i];
+                            }
+                            break;
                         }
-                    } else if (attachmentFormat.HasComponentType(Format::Type::Uint)) {
-                        const std::array<uint32_t, 4> appliedClearColor =
-                            ConvertToUnsignedIntegerColor(attachmentInfo.clearColor);
-                        for (uint32_t i = 0; i < 4; ++i) {
-                            clearValues[attachmentCount].color.uint32[i] = appliedClearColor[i];
+                        case wgpu::TextureComponentType::Uint: {
+                            const std::array<uint32_t, 4> appliedClearColor =
+                                ConvertToUnsignedIntegerColor(attachmentInfo.clearColor);
+                            for (uint32_t i = 0; i < 4; ++i) {
+                                clearValues[attachmentCount].color.uint32[i] = appliedClearColor[i];
+                            }
+                            break;
                         }
-                    } else if (attachmentFormat.HasComponentType(Format::Type::Sint)) {
-                        const std::array<int32_t, 4> appliedClearColor =
-                            ConvertToSignedIntegerColor(attachmentInfo.clearColor);
-                        for (uint32_t i = 0; i < 4; ++i) {
-                            clearValues[attachmentCount].color.int32[i] = appliedClearColor[i];
+                        case wgpu::TextureComponentType::Sint: {
+                            const std::array<int32_t, 4> appliedClearColor =
+                                ConvertToSignedIntegerColor(attachmentInfo.clearColor);
+                            for (uint32_t i = 0; i < 4; ++i) {
+                                clearValues[attachmentCount].color.int32[i] = appliedClearColor[i];
+                            }
+                            break;
                         }
-                    } else {
-                        UNREACHABLE();
                     }
-
                     attachmentCount++;
                 }
 
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 882866d..5c0bff9 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -1039,28 +1039,25 @@
                 } else {
                     ASSERT(aspects == Aspect::Color);
                     VkClearColorValue clearColorValue;
-                    switch (GetFormat().type) {
-                        case Format::Type::Float:
+                    switch (GetFormat().GetAspectInfo(Aspect::Color).baseType) {
+                        case wgpu::TextureComponentType::Float:
                             clearColorValue.float32[0] = fClearColor;
                             clearColorValue.float32[1] = fClearColor;
                             clearColorValue.float32[2] = fClearColor;
                             clearColorValue.float32[3] = fClearColor;
                             break;
-                        case Format::Type::Sint:
+                        case wgpu::TextureComponentType::Sint:
                             clearColorValue.int32[0] = sClearColor;
                             clearColorValue.int32[1] = sClearColor;
                             clearColorValue.int32[2] = sClearColor;
                             clearColorValue.int32[3] = sClearColor;
                             break;
-                        case Format::Type::Uint:
+                        case wgpu::TextureComponentType::Uint:
                             clearColorValue.uint32[0] = uClearColor;
                             clearColorValue.uint32[1] = uClearColor;
                             clearColorValue.uint32[2] = uClearColor;
                             clearColorValue.uint32[3] = uClearColor;
                             break;
-
-                        case Format::Type::Other:
-                            UNREACHABLE();
                     }
                     device->fn.CmdClearColorImage(recordingContext->commandBuffer, GetHandle(),
                                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
diff --git a/src/tests/unittests/validation/BindGroupValidationTests.cpp b/src/tests/unittests/validation/BindGroupValidationTests.cpp
index 1460851..d1f9cec 100644
--- a/src/tests/unittests/validation/BindGroupValidationTests.cpp
+++ b/src/tests/unittests/validation/BindGroupValidationTests.cpp
@@ -309,6 +309,42 @@
     ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, uintTextureView}}));
 }
 
+// Test which depth-stencil formats are allowed to be sampled.
+// This is a regression test for a change in dawn_native mistakenly allowing the depth24plus formats
+// to be sampled without proper backend support.
+TEST_F(BindGroupValidationTest, SamplingDepthTexture) {
+    wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(
+        device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture}});
+
+    wgpu::TextureDescriptor desc;
+    desc.size = {1, 1, 1};
+    desc.usage = wgpu::TextureUsage::Sampled;
+
+    // Depth32Float is allowed to be sampled.
+    {
+        desc.format = wgpu::TextureFormat::Depth32Float;
+        wgpu::Texture texture = device.CreateTexture(&desc);
+
+        utils::MakeBindGroup(device, layout, {{0, texture.CreateView()}});
+    }
+
+    // Depth24Plus is not allowed to be sampled.
+    {
+        desc.format = wgpu::TextureFormat::Depth24Plus;
+        wgpu::Texture texture = device.CreateTexture(&desc);
+
+        ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, texture.CreateView()}}));
+    }
+
+    // Depth24PlusStencil8 is not allowed to be sampled.
+    {
+        desc.format = wgpu::TextureFormat::Depth24PlusStencil8;
+        wgpu::Texture texture = device.CreateTexture(&desc);
+
+        ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, texture.CreateView()}}));
+    }
+}
+
 // Check that a texture must have the correct dimension
 TEST_F(BindGroupValidationTest, TextureDimension) {
     wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(