Add a usage parameter to TextureView creation.

This allows views to use a subset of usages from the source texture's
usages and use formats that may not be compatible with all of the
source textures usages.

Roll third_party/gpuweb/ 2dc56f297..010f5c9dd (5 commits):
https://github.com/gpuweb/gpuweb/compare/2dc56f29788a...010f5c9ddfd2

Bug: 363903526
Change-Id: I4d59907a976063b01a992776a20eeeaf326856ad
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/206115
Commit-Queue: Geoff Lang <geofflang@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/DEPS b/DEPS
index 3f9ce3b..af420a1 100644
--- a/DEPS
+++ b/DEPS
@@ -375,7 +375,7 @@
     'condition': 'dawn_node',
   },
   'third_party/gpuweb': {
-    'url': '{github_git}/gpuweb/gpuweb.git@2dc56f29788a2b8087ef0de87379c0b40a6f2dd5',
+    'url': '{github_git}/gpuweb/gpuweb.git@010f5c9ddfd21bc963025979d08eb7489058c1c7',
     'condition': 'dawn_node',
   },
 
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 8d20970..063eefa 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -4625,7 +4625,8 @@
             {"name": "mip level count", "type": "uint32_t", "default": "WGPU_MIP_LEVEL_COUNT_UNDEFINED"},
             {"name": "base array layer", "type": "uint32_t", "default": "0"},
             {"name": "array layer count", "type": "uint32_t", "default": "WGPU_ARRAY_LAYER_COUNT_UNDEFINED"},
-            {"name": "aspect", "type": "texture aspect", "default": "all"}
+            {"name": "aspect", "type": "texture aspect", "default": "all"},
+            {"name": "usage", "type": "texture usage", "default": "none"}
         ]
     },
     "texture view": {
diff --git a/src/dawn/native/BindGroup.cpp b/src/dawn/native/BindGroup.cpp
index b397bf4..c6438e9 100644
--- a/src/dawn/native/BindGroup.cpp
+++ b/src/dawn/native/BindGroup.cpp
@@ -166,7 +166,7 @@
             static_cast<SharedTextureMemoryContents*>(texture->GetSharedResourceMemoryContents())
                 ->GetExternalFormatSupportedSampleTypes();
     }
-    DAWN_TRY(ValidateCanUseAs(texture, wgpu::TextureUsage::TextureBinding, mode));
+    DAWN_TRY(ValidateCanUseAs(view, wgpu::TextureUsage::TextureBinding, mode));
 
     DAWN_INVALID_IF(texture->IsMultisampledTexture() != layout.multisampled,
                     "Sample count (%u) of %s doesn't match expectation (multisampled: %d).",
@@ -210,7 +210,7 @@
     TextureViewBase* view = entry.textureView;
     TextureBase* texture = view->GetTexture();
 
-    DAWN_TRY(ValidateCanUseAs(texture, wgpu::TextureUsage::StorageBinding, mode));
+    DAWN_TRY(ValidateCanUseAs(view, wgpu::TextureUsage::StorageBinding, mode));
 
     DAWN_ASSERT(!texture->IsMultisampledTexture());
 
diff --git a/src/dawn/native/CommandEncoder.cpp b/src/dawn/native/CommandEncoder.cpp
index 0cb5762..27f8be5 100644
--- a/src/dawn/native/CommandEncoder.cpp
+++ b/src/dawn/native/CommandEncoder.cpp
@@ -386,8 +386,8 @@
     const TextureViewBase* resolveTarget = colorAttachment.resolveTarget;
     const TextureViewBase* attachment = colorAttachment.view;
     DAWN_TRY(device->ValidateObject(colorAttachment.resolveTarget));
-    DAWN_TRY(ValidateCanUseAs(colorAttachment.resolveTarget->GetTexture(),
-                              wgpu::TextureUsage::RenderAttachment, usageValidationMode));
+    DAWN_TRY(ValidateCanUseAs(colorAttachment.resolveTarget, wgpu::TextureUsage::RenderAttachment,
+                              usageValidationMode));
 
     DAWN_INVALID_IF(!attachment->GetTexture()->IsMultisampledTexture(),
                     "Cannot set %s as a resolve target when the color attachment %s has a sample "
@@ -503,12 +503,12 @@
                 !colorAttachment.resolveTarget->IsError());
     DAWN_ASSERT(colorAttachment.view->GetFormat().supportsResolveTarget);
 
-    DAWN_INVALID_IF((colorAttachment.resolveTarget->GetTexture()->GetUsage() &
-                     wgpu::TextureUsage::TextureBinding) == 0,
-                    "Resolve target %s was not created with %s usage, which is required for "
-                    "%s.",
-                    colorAttachment.resolveTarget, wgpu::TextureUsage::TextureBinding,
-                    wgpu::LoadOp::ExpandResolveTexture);
+    DAWN_INVALID_IF(
+        (colorAttachment.resolveTarget->GetUsage() & wgpu::TextureUsage::TextureBinding) == 0,
+        "Resolve target %s was not created with %s usage, which is required for "
+        "%s.",
+        colorAttachment.resolveTarget, wgpu::TextureUsage::TextureBinding,
+        wgpu::LoadOp::ExpandResolveTexture);
 
     // TODO(42240662): multiplanar textures are not supported as resolve target.
     // The RenderPassValidationState currently rejects such usage.
@@ -529,8 +529,8 @@
     }
 
     DAWN_TRY(device->ValidateObject(attachment));
-    DAWN_TRY(ValidateCanUseAs(attachment->GetTexture(), wgpu::TextureUsage::RenderAttachment,
-                              usageValidationMode));
+    DAWN_TRY(
+        ValidateCanUseAs(attachment, wgpu::TextureUsage::RenderAttachment, usageValidationMode));
 
     UnpackedPtr<RenderPassColorAttachment> unpacked;
     DAWN_TRY_ASSIGN(unpacked, ValidateAndUnpack(&colorAttachment));
@@ -558,16 +558,16 @@
     DAWN_TRY(ValidateStoreOp(colorAttachment.storeOp));
     DAWN_INVALID_IF(colorAttachment.loadOp == wgpu::LoadOp::Undefined, "loadOp must be set.");
     DAWN_INVALID_IF(colorAttachment.storeOp == wgpu::StoreOp::Undefined, "storeOp must be set.");
-    if (attachment->GetTexture()->GetUsage() & wgpu::TextureUsage::TransientAttachment) {
+    if (attachment->GetUsage() & wgpu::TextureUsage::TransientAttachment) {
         DAWN_INVALID_IF(colorAttachment.loadOp != wgpu::LoadOp::Clear &&
                             colorAttachment.loadOp != wgpu::LoadOp::ExpandResolveTexture,
                         "The color attachment %s has the load op set to %s while its usage (%s) "
                         "has the transient attachment bit set.",
-                        attachment, colorAttachment.loadOp, attachment->GetTexture()->GetUsage());
+                        attachment, colorAttachment.loadOp, attachment->GetUsage());
         DAWN_INVALID_IF(colorAttachment.storeOp != wgpu::StoreOp::Discard,
                         "The color attachment %s has the store op set to %s while its usage (%s) "
                         "has the transient attachment bit set.",
-                        attachment, wgpu::StoreOp::Store, attachment->GetTexture()->GetUsage());
+                        attachment, wgpu::StoreOp::Store, attachment->GetUsage());
     }
 
     const dawn::native::Color& clearValue = colorAttachment.clearValue;
@@ -612,8 +612,8 @@
 
     TextureViewBase* attachment = depthStencilAttachment->view;
     DAWN_TRY(device->ValidateObject(attachment));
-    DAWN_TRY(ValidateCanUseAs(attachment->GetTexture(), wgpu::TextureUsage::RenderAttachment,
-                              usageValidationMode));
+    DAWN_TRY(
+        ValidateCanUseAs(attachment, wgpu::TextureUsage::RenderAttachment, usageValidationMode));
 
     // DS attachments must encompass all aspects of the texture, so we first check that this is
     // true, which means that in the rest of the function we can assume that the view's format is
@@ -712,8 +712,8 @@
 
         // Validate the attachment can be used as a storage attachment.
         DAWN_TRY(device->ValidateObject(attachment.storage));
-        DAWN_TRY(ValidateCanUseAs(attachment.storage->GetTexture(),
-                                  wgpu::TextureUsage::StorageAttachment, usageValidationMode));
+        DAWN_TRY(ValidateCanUseAs(attachment.storage, wgpu::TextureUsage::StorageAttachment,
+                                  usageValidationMode));
         DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment.storage));
 
         // Validate the load/storeOp and the clearValue.
diff --git a/src/dawn/native/CommandValidation.cpp b/src/dawn/native/CommandValidation.cpp
index 7bd537a..ccdc97bc 100644
--- a/src/dawn/native/CommandValidation.cpp
+++ b/src/dawn/native/CommandValidation.cpp
@@ -648,6 +648,25 @@
     return {};
 }
 
+MaybeError ValidateCanUseAs(const TextureViewBase* textureView,
+                            wgpu::TextureUsage usage,
+                            UsageValidationMode mode) {
+    DAWN_ASSERT(wgpu::HasZeroOrOneBits(usage));
+    DAWN_ASSERT(IsSubset(usage, kTextureViewOnlyUsages));
+    switch (mode) {
+        case UsageValidationMode::Default:
+            DAWN_INVALID_IF(!(textureView->GetUsage() & usage), "%s usage (%s) doesn't include %s.",
+                            textureView, textureView->GetUsage(), usage);
+            break;
+        case UsageValidationMode::Internal:
+            DAWN_INVALID_IF(!(textureView->GetInternalUsage() & usage),
+                            "%s internal usage (%s) doesn't include %s.", textureView,
+                            textureView->GetInternalUsage(), usage);
+            break;
+    }
+    return {};
+}
+
 MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage) {
     DAWN_ASSERT(wgpu::HasZeroOrOneBits(usage));
     DAWN_INVALID_IF(!(buffer->GetUsage() & usage), "%s usage (%s) doesn't include %s.", buffer,
diff --git a/src/dawn/native/CommandValidation.h b/src/dawn/native/CommandValidation.h
index 36e737f..f9c2dbd 100644
--- a/src/dawn/native/CommandValidation.h
+++ b/src/dawn/native/CommandValidation.h
@@ -110,7 +110,10 @@
                                                     const ImageCopyTexture& dst,
                                                     const Extent3D& copySize);
 
-MaybeError ValidateCanUseAs(const TextureBase* texture,
+MaybeError ValidateCanUseAs(const TextureBase* textureView,
+                            wgpu::TextureUsage usage,
+                            UsageValidationMode mode);
+MaybeError ValidateCanUseAs(const TextureViewBase* textureView,
                             wgpu::TextureUsage usage,
                             UsageValidationMode mode);
 MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage);
diff --git a/src/dawn/native/ExternalTexture.cpp b/src/dawn/native/ExternalTexture.cpp
index 7249bc5..d916af5 100644
--- a/src/dawn/native/ExternalTexture.cpp
+++ b/src/dawn/native/ExternalTexture.cpp
@@ -42,9 +42,9 @@
 
 MaybeError ValidateExternalTexturePlane(const TextureViewBase* textureView) {
     DAWN_INVALID_IF(
-        (textureView->GetTexture()->GetUsage() & wgpu::TextureUsage::TextureBinding) == 0,
+        (textureView->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);
+        textureView, textureView->GetUsage(), wgpu::TextureUsage::TextureBinding);
 
     DAWN_INVALID_IF(textureView->GetDimension() != wgpu::TextureViewDimension::e2D,
                     "The external texture plane (%s) dimension (%s) is not 2D.", textureView,
diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp
index 8d929f5..2138d65 100644
--- a/src/dawn/native/Texture.cpp
+++ b/src/dawn/native/Texture.cpp
@@ -347,7 +347,7 @@
 }
 
 MaybeError ValidateTextureUsage(const DeviceBase* device,
-                                const TextureDescriptor* descriptor,
+                                wgpu::TextureDimension textureDimension,
                                 wgpu::TextureUsage usage,
                                 const Format* format,
                                 std::optional<wgpu::TextureUsage> allowedSharedTextureMemoryUsage) {
@@ -369,11 +369,11 @@
         "format (%s).",
         usage, wgpu::TextureUsage::RenderAttachment, format->format);
 
-    DAWN_INVALID_IF(descriptor->dimension == wgpu::TextureDimension::e1D &&
+    DAWN_INVALID_IF(textureDimension == wgpu::TextureDimension::e1D &&
                         (usage & wgpu::TextureUsage::RenderAttachment),
                     "The texture usage (%s) includes %s, which is incompatible with the texture "
                     "dimension (%s).",
-                    usage, wgpu::TextureUsage::RenderAttachment, descriptor->dimension);
+                    usage, wgpu::TextureUsage::RenderAttachment, textureDimension);
 
     DAWN_INVALID_IF(
         !format->supportsStorageUsage && (usage & wgpu::TextureUsage::StorageBinding),
@@ -427,6 +427,27 @@
     return {};
 }
 
+wgpu::TextureUsage GetTextureViewUsage(wgpu::TextureUsage sourceTextureUsage,
+                                       wgpu::TextureUsage requestedViewUsage) {
+    // If a view's requested usage is None, inherit usage from the source texture.
+    return (requestedViewUsage != wgpu::TextureUsage::None) ? requestedViewUsage
+                                                            : sourceTextureUsage;
+}
+
+MaybeError ValidateTextureViewUsage(const DeviceBase* device,
+                                    const TextureBase* texture,
+                                    wgpu::TextureUsage usage,
+                                    const Format* format) {
+    wgpu::TextureUsage inheritedUsage = GetTextureViewUsage(texture->GetUsage(), usage);
+    DAWN_INVALID_IF(!IsSubset(inheritedUsage, texture->GetUsage()),
+                    "The texture view usage (%s) is not a subset of the texture usage (%s).",
+                    inheritedUsage, texture->GetUsage());
+
+    DAWN_TRY(ValidateTextureUsage(device, texture->GetDimension(), inheritedUsage, format, {}));
+
+    return {};
+}
+
 // We need to add an internal RenderAttachment usage to some textures that has CopyDst usage as we
 // apply a workaround that writes to them with a render pipeline.
 bool CopyDstNeedsInternalRenderAttachmentUsage(const DeviceBase* device, const Format& format) {
@@ -516,6 +537,49 @@
     }
 }
 
+wgpu::TextureUsage AddInternalUsages(const DeviceBase* device,
+                                     wgpu::TextureUsage usage,
+                                     const Format& format,
+                                     uint32_t sampleCount,
+                                     uint32_t mipLevelCount,
+                                     uint32_t arrayLayerCount) {
+    wgpu::TextureUsage internalUsage = usage;
+
+    // dawn:1569: If a texture with multiple array layers or mip levels is specified as a
+    // texture attachment when this toggle is active, it needs to be given CopySrc | CopyDst usage
+    // internally.
+    bool applyAlwaysResolveIntoZeroLevelAndLayerToggle =
+        device->IsToggleEnabled(Toggle::AlwaysResolveIntoZeroLevelAndLayer) &&
+        (arrayLayerCount > 1 || mipLevelCount > 1) &&
+        (internalUsage & wgpu::TextureUsage::RenderAttachment);
+    if (applyAlwaysResolveIntoZeroLevelAndLayerToggle) {
+        internalUsage |= wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
+    }
+
+    if (internalUsage & wgpu::TextureUsage::CopyDst) {
+        if (CopyDstNeedsInternalRenderAttachmentUsage(device, format)) {
+            internalUsage |= wgpu::TextureUsage::RenderAttachment;
+        }
+    }
+    if (internalUsage & wgpu::TextureUsage::CopySrc) {
+        if (CopySrcNeedsInternalTextureBindingUsage(device, format)) {
+            internalUsage |= wgpu::TextureUsage::TextureBinding;
+        }
+    }
+    if (internalUsage & wgpu::TextureUsage::StorageBinding) {
+        internalUsage |= kReadOnlyStorageTexture | kWriteOnlyStorageTexture;
+    }
+
+    bool supportsMSAAPartialResolve = device->HasFeature(Feature::DawnPartialLoadResolveTexture) &&
+                                      sampleCount > 1 &&
+                                      (usage & wgpu::TextureUsage::RenderAttachment);
+    if (supportsMSAAPartialResolve) {
+        internalUsage |= wgpu::TextureUsage::TextureBinding;
+    }
+
+    return internalUsage;
+}
+
 }  // anonymous namespace
 
 MaybeError ValidateTextureDescriptor(
@@ -563,7 +627,7 @@
             "validating viewFormats[%u]", i);
     }
 
-    DAWN_TRY(ValidateTextureUsage(device, *descriptor, usage, format,
+    DAWN_TRY(ValidateTextureUsage(device, descriptor->dimension, usage, format,
                                   std::move(allowedSharedTextureMemoryUsage)));
     DAWN_TRY(ValidateTextureDimension(descriptor->dimension));
     if (device->IsCompatibilityMode()) {
@@ -618,6 +682,8 @@
     const Format* viewFormat;
     DAWN_TRY_ASSIGN(viewFormat, device->GetInternalFormat(descriptor->format));
 
+    DAWN_TRY(ValidateTextureViewUsage(device, texture, descriptor->usage, viewFormat));
+
     const auto aspect = SelectFormatAspects(format, descriptor->aspect);
     DAWN_INVALID_IF(aspect == Aspect::None,
                     "Texture format (%s) does not have the texture view's selected aspect (%s).",
@@ -782,37 +848,8 @@
     }
     GetObjectTrackingList()->Track(this);
 
-    // dawn:1569: If a texture with multiple array layers or mip levels is specified as a
-    // texture attachment when this toggle is active, it needs to be given CopySrc | CopyDst usage
-    // internally.
-    bool applyAlwaysResolveIntoZeroLevelAndLayerToggle =
-        device->IsToggleEnabled(Toggle::AlwaysResolveIntoZeroLevelAndLayer) &&
-        (GetArrayLayers() > 1 || GetNumMipLevels() > 1) &&
-        (GetInternalUsage() & wgpu::TextureUsage::RenderAttachment);
-    if (applyAlwaysResolveIntoZeroLevelAndLayerToggle) {
-        AddInternalUsage(wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst);
-    }
-
-    if (mInternalUsage & wgpu::TextureUsage::CopyDst) {
-        if (CopyDstNeedsInternalRenderAttachmentUsage(device, *mFormat)) {
-            AddInternalUsage(wgpu::TextureUsage::RenderAttachment);
-        }
-    }
-    if (mInternalUsage & wgpu::TextureUsage::CopySrc) {
-        if (CopySrcNeedsInternalTextureBindingUsage(device, *mFormat)) {
-            AddInternalUsage(wgpu::TextureUsage::TextureBinding);
-        }
-    }
-    if (mInternalUsage & wgpu::TextureUsage::StorageBinding) {
-        AddInternalUsage(kReadOnlyStorageTexture | kWriteOnlyStorageTexture);
-    }
-
-    bool supportsMSAAPartialResolve = device->HasFeature(Feature::DawnPartialLoadResolveTexture) &&
-                                      GetSampleCount() > 1 &&
-                                      (GetUsage() & wgpu::TextureUsage::RenderAttachment);
-    if (supportsMSAAPartialResolve) {
-        AddInternalUsage(wgpu::TextureUsage::TextureBinding);
-    }
+    mInternalUsage = AddInternalUsages(device, mInternalUsage, *mFormat, GetSampleCount(),
+                                       GetNumMipLevels(), GetArrayLayers());
 }
 
 TextureBase::~TextureBase() = default;
@@ -1304,7 +1341,15 @@
       mDimension(descriptor->dimension),
       mRange({ConvertViewAspect(*mFormat, descriptor->aspect),
               {descriptor->baseArrayLayer, descriptor->arrayLayerCount},
-              {descriptor->baseMipLevel, descriptor->mipLevelCount}}) {
+              {descriptor->baseMipLevel, descriptor->mipLevelCount}}),
+      mUsage(GetTextureViewUsage(texture->GetUsage(), descriptor->usage)),
+      mInternalUsage(
+          AddInternalUsages(GetDevice(),
+                            GetTextureViewUsage(texture->GetInternalUsage(), descriptor->usage),
+                            *mFormat,
+                            texture->GetSampleCount(),
+                            texture->GetNumMipLevels(),
+                            texture->GetArrayLayers())) {
     GetObjectTrackingList()->Track(this);
 }
 
@@ -1396,6 +1441,16 @@
     return GetTexture()->GetMipLevelSingleSubresourceVirtualSize(GetBaseMipLevel(), GetAspects());
 }
 
+wgpu::TextureUsage TextureViewBase::GetUsage() const {
+    DAWN_ASSERT(!IsError());
+    return mUsage;
+}
+
+wgpu::TextureUsage TextureViewBase::GetInternalUsage() const {
+    DAWN_ASSERT(!IsError());
+    return mInternalUsage;
+}
+
 ApiObjectList* TextureViewBase::GetObjectTrackingList() {
     if (mTexture != nullptr) {
         return mTexture->GetViewTrackingList();
diff --git a/src/dawn/native/Texture.h b/src/dawn/native/Texture.h
index caad0e2..e43602c 100644
--- a/src/dawn/native/Texture.h
+++ b/src/dawn/native/Texture.h
@@ -79,6 +79,11 @@
     wgpu::TextureUsage::TextureBinding | kReadOnlyStorageTexture |
     wgpu::TextureUsage::StorageBinding | kWriteOnlyStorageTexture;
 
+// Usages that are used to validate operations that act on texture views.
+static constexpr wgpu::TextureUsage kTextureViewOnlyUsages =
+    kShaderTextureUsages | kResolveTextureLoadAndStoreUsages |
+    wgpu::TextureUsage::TransientAttachment | wgpu::TextureUsage::StorageAttachment;
+
 class TextureBase : public SharedResource {
   public:
     enum class ClearValue { Zero, NonZero };
@@ -243,6 +248,12 @@
     // Returns the size of the texture's subresource at this view's base mip level and aspect.
     Extent3D GetSingleSubresourceVirtualSize() const;
 
+    // |GetUsage| returns the usage with which the texture view was created using the base WebGPU
+    // API. The dawn-internal-usages extension may add additional usages. |GetInternalUsage|
+    // returns the union of base usage and the usages added by the extension.
+    wgpu::TextureUsage GetUsage() const;
+    wgpu::TextureUsage GetInternalUsage() const;
+
   protected:
     void DestroyImpl() override;
 
@@ -256,6 +267,8 @@
     const raw_ref<const Format> mFormat;
     wgpu::TextureViewDimension mDimension;
     SubresourceRange mRange;
+    const wgpu::TextureUsage mUsage = wgpu::TextureUsage::None;
+    const wgpu::TextureUsage mInternalUsage = wgpu::TextureUsage::None;
 };
 
 }  // namespace dawn::native
diff --git a/src/dawn/native/metal/TextureMTL.mm b/src/dawn/native/metal/TextureMTL.mm
index 4397701..9df2144 100644
--- a/src/dawn/native/metal/TextureMTL.mm
+++ b/src/dawn/native/metal/TextureMTL.mm
@@ -103,13 +103,14 @@
 
 bool RequiresCreatingNewTextureView(
     const TextureBase* texture,
+    wgpu::TextureUsage internalViewUsage,
     const UnpackedPtr<TextureViewDescriptor>& textureViewDescriptor) {
     constexpr wgpu::TextureUsage kShaderUsageNeedsView =
         wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
     constexpr wgpu::TextureUsage kUsageNeedsView = kShaderUsageNeedsView |
                                                    wgpu::TextureUsage::RenderAttachment |
                                                    wgpu::TextureUsage::StorageAttachment;
-    if ((texture->GetInternalUsage() & kUsageNeedsView) == 0) {
+    if ((internalViewUsage & kUsageNeedsView) == 0) {
         return false;
     }
 
@@ -789,7 +790,7 @@
     Aspect aspect = SelectFormatAspects(texture->GetFormat(), descriptor->aspect);
     id<MTLTexture> mtlTexture = texture->GetMTLTexture(aspect);
 
-    bool needsNewView = RequiresCreatingNewTextureView(texture, descriptor);
+    bool needsNewView = RequiresCreatingNewTextureView(texture, GetInternalUsage(), descriptor);
     if (device->IsToggleEnabled(Toggle::MetalUseCombinedDepthStencilFormatForStencil8) &&
         GetTexture()->GetFormat().format == wgpu::TextureFormat::Stencil8) {
         // If MetalUseCombinedDepthStencilFormatForStencil8 is true and the format is Stencil8,
@@ -850,7 +851,7 @@
 }
 
 TextureView::AttachmentInfo TextureView::GetAttachmentInfo() const {
-    DAWN_ASSERT(GetTexture()->GetInternalUsage() &
+    DAWN_ASSERT(GetInternalUsage() &
                 (wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::StorageAttachment));
     // Use our own view if the formats do not match.
     // If the formats do not match, format reinterpretation will be required.
diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp
index 6c12824..006cd51 100644
--- a/src/dawn/native/vulkan/TextureVk.cpp
+++ b/src/dawn/native/vulkan/TextureVk.cpp
@@ -1607,6 +1607,7 @@
                 viewDesc.mipLevelCount = 1u;
                 viewDesc.baseArrayLayer = layer;
                 viewDesc.arrayLayerCount = 1u;
+                viewDesc.usage = wgpu::TextureUsage::RenderAttachment;
 
                 ColorAttachmentIndex ca0(uint8_t(0));
                 DAWN_TRY_ASSIGN(beginCmd.colorAttachments[ca0].view,
@@ -1781,8 +1782,7 @@
 }
 
 MaybeError TextureView::Initialize(const UnpackedPtr<TextureViewDescriptor>& descriptor) {
-    if ((GetTexture()->GetInternalUsage() &
-         ~(wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst)) == 0) {
+    if ((GetInternalUsage() & ~(wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst)) == 0) {
         // If the texture view has no other usage than CopySrc and CopyDst, then it can't
         // actually be used as a render pass attachment or sampled/storage texture. The Vulkan
         // validation errors warn if you create such a vkImageView, so return early.
@@ -1797,15 +1797,9 @@
     Device* device = ToBackend(GetTexture()->GetDevice());
     VkImageViewCreateInfo createInfo = GetCreateInfo(descriptor->format, descriptor->dimension);
 
-    // Remove StorageBinding usage if the format doesn't support it.
-    wgpu::TextureUsage usage = GetTexture()->GetInternalUsage();
-    if (!GetFormat().supportsStorageUsage) {
-        usage &= ~wgpu::TextureUsage::StorageBinding;
-    }
-
     VkImageViewUsageCreateInfo usageInfo = {};
     usageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
-    usageInfo.usage = VulkanImageUsage(device, usage, GetFormat());
+    usageInfo.usage = VulkanImageUsage(device, GetInternalUsage(), GetFormat());
     createInfo.pNext = &usageInfo;
 
     VkSamplerYcbcrConversionInfo samplerYCbCrInfo = {};
diff --git a/src/dawn/node/binding/GPUTexture.cpp b/src/dawn/node/binding/GPUTexture.cpp
index d2668f8..c13586b 100644
--- a/src/dawn/node/binding/GPUTexture.cpp
+++ b/src/dawn/node/binding/GPUTexture.cpp
@@ -62,7 +62,9 @@
         !conv(desc.arrayLayerCount, descriptor.arrayLayerCount) ||  //
         !conv(desc.format, descriptor.format) ||                    //
         !conv(desc.dimension, descriptor.dimension) ||              //
-        !conv(desc.aspect, descriptor.aspect) || !conv(desc.label, descriptor.label)) {
+        !conv(desc.aspect, descriptor.aspect) ||                    //
+        !conv(desc.label, descriptor.label) ||                      //
+        !conv(desc.usage, descriptor.usage)) {
         return {};
     }
     return interop::GPUTextureView::Create<GPUTextureView>(env, desc, texture_.CreateView(&desc));
diff --git a/src/dawn/tests/end2end/TextureViewTests.cpp b/src/dawn/tests/end2end/TextureViewTests.cpp
index af00dab..7b3878a 100644
--- a/src/dawn/tests/end2end/TextureViewTests.cpp
+++ b/src/dawn/tests/end2end/TextureViewTests.cpp
@@ -166,6 +166,7 @@
         mDefaultTextureViewDescriptor.mipLevelCount = mipLevelCount;
         mDefaultTextureViewDescriptor.baseArrayLayer = 0;
         mDefaultTextureViewDescriptor.arrayLayerCount = arrayLayerCount;
+        mDefaultTextureViewDescriptor.usage = kUsage;
 
         // Create a texture with pixel = (0, 0, 0, level * 10 + layer + 1) at level `level` and
         // layer `layer`.
diff --git a/src/dawn/tests/unittests/validation/BindGroupValidationTests.cpp b/src/dawn/tests/unittests/validation/BindGroupValidationTests.cpp
index eb59fa3..e3032a3 100644
--- a/src/dawn/tests/unittests/validation/BindGroupValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/BindGroupValidationTests.cpp
@@ -460,10 +460,30 @@
     utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
 
     // Make an render attachment texture and try to set it for a SampledTexture binding
-    wgpu::Texture outputTexture =
-        CreateTexture(wgpu::TextureUsage::RenderAttachment, wgpu::TextureFormat::RGBA8Unorm, 1);
-    wgpu::TextureView outputTextureView = outputTexture.CreateView();
-    ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, outputTextureView}}));
+    {
+        wgpu::Texture outputTexture =
+            CreateTexture(wgpu::TextureUsage::RenderAttachment, wgpu::TextureFormat::RGBA8Unorm, 1);
+        wgpu::TextureView outputTextureView = outputTexture.CreateView();
+        ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, outputTextureView}}));
+    }
+
+    // Make a sampled/render attachment texture and a view without sampling and attempt to bind it
+    {
+        wgpu::Texture outputTexture =
+            CreateTexture(wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding,
+                          wgpu::TextureFormat::RGBA8Unorm, 1);
+        wgpu::TextureViewDescriptor viewDescriptor;
+        viewDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
+        viewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
+        viewDescriptor.baseMipLevel = 0;
+        viewDescriptor.mipLevelCount = 1;
+        viewDescriptor.baseArrayLayer = 0;
+        viewDescriptor.arrayLayerCount = 1;
+        viewDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
+
+        wgpu::TextureView outputTextureView = outputTexture.CreateView(&viewDescriptor);
+        ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, outputTextureView}}));
+    }
 }
 
 // Check that a storage texture binding must have the correct usage
diff --git a/src/dawn/tests/unittests/validation/TextureViewValidationTests.cpp b/src/dawn/tests/unittests/validation/TextureViewValidationTests.cpp
index f56277d..8f1fa64 100644
--- a/src/dawn/tests/unittests/validation/TextureViewValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/TextureViewValidationTests.cpp
@@ -945,6 +945,59 @@
     ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, view}}));
 }
 
+// Tests that texture view usage is validated for the texture view format and is compatible with the
+// source texture usages
+TEST_F(TextureViewValidationTest, Usage) {
+    wgpu::TextureFormat viewFormats[] = {wgpu::TextureFormat::RGBA8Unorm,
+                                         wgpu::TextureFormat::RGBA8UnormSrgb};
+
+    wgpu::TextureDescriptor textureDescriptor;
+    textureDescriptor.dimension = wgpu::TextureDimension::e2D;
+    textureDescriptor.size.width = kWidth;
+    textureDescriptor.size.height = kHeight;
+    textureDescriptor.sampleCount = 1;
+    textureDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
+    textureDescriptor.mipLevelCount = 1;
+    textureDescriptor.usage = wgpu::TextureUsage::TextureBinding |
+                              wgpu::TextureUsage::RenderAttachment |
+                              wgpu::TextureUsage::StorageBinding;
+    textureDescriptor.viewFormats = viewFormats;
+    textureDescriptor.viewFormatCount = 2;
+    wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
+
+    wgpu::TextureViewDescriptor base2DTextureViewDescriptor;
+    base2DTextureViewDescriptor.format = kDefaultTextureFormat;
+    base2DTextureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
+    base2DTextureViewDescriptor.baseMipLevel = 0;
+    base2DTextureViewDescriptor.mipLevelCount = 1;
+    base2DTextureViewDescriptor.baseArrayLayer = 0;
+    base2DTextureViewDescriptor.arrayLayerCount = 1;
+
+    // It is an error to request a usage outside of the source texture's usage
+    {
+        wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
+        descriptor.usage |= wgpu::TextureUsage::CopyDst;
+        ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
+    }
+
+    // It is an error to create a view with RGBA8UnormSrgb and default usage which includes
+    // StorageBinding
+    {
+        wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
+        descriptor.format = wgpu::TextureFormat::RGBA8UnormSrgb;
+        ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
+    }
+
+    // A view can be created for RGBA8UnormSrgb with a compatible subset of usages
+    {
+        wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
+        descriptor.format = wgpu::TextureFormat::RGBA8UnormSrgb;
+        descriptor.usage =
+            wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
+        texture.CreateView(&descriptor);
+    }
+}
+
 class D32S8TextureViewValidationTests : public ValidationTest {
   protected:
     std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
diff --git a/third_party/gpuweb b/third_party/gpuweb
index 2dc56f2..010f5c9 160000
--- a/third_party/gpuweb
+++ b/third_party/gpuweb
@@ -1 +1 @@
-Subproject commit 2dc56f29788a2b8087ef0de87379c0b40a6f2dd5
+Subproject commit 010f5c9ddfd21bc963025979d08eb7489058c1c7