Reland: 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
Reland additions:
Only validate explicit view usage for now. Until it is possible to
request explicit usages from the WebGPU API, the RGBA8UnormSrgb and
BGRA8UnormSrgb would not be usable as view formats if the base
texture has StorageBinding usage. Remove the StorageBinding usage in
this case and emit a warning.
Bug: 363903526
Change-Id: Ia96991e239300a482bfa6a053397aaec7fab4e67
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/208335
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
diff --git a/DEPS b/DEPS
index 563b5ed..dd6cc46 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 aeca9b9..7168d65 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -4619,7 +4619,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 601e699..0da292a 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 b2b3e89..9cfc694 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..ccdc97b 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 ef76f78..a1d4228 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 8f6bec8..8232ea5 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,42 @@
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;
+}
+
+wgpu::TextureUsage RemoveInvalidViewUsages(wgpu::TextureUsage viewUsage, const Format* viewFormat) {
+ wgpu::TextureUsage adjustedUsage = viewUsage;
+ if (viewFormat->format == wgpu::TextureFormat::RGBA8UnormSrgb ||
+ viewFormat->format == wgpu::TextureFormat::BGRA8UnormSrgb) {
+ adjustedUsage = viewUsage & ~wgpu::TextureUsage::StorageBinding;
+ }
+
+ return adjustedUsage;
+}
+
+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());
+
+ // Validate the view usage only when it is explicitly requested for now because it is not yet
+ // possible to request view usage all the way from the WebGPU API.
+ if (usage != wgpu::TextureUsage::None) {
+ 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 +552,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 +642,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 +697,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 +863,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,8 +1356,30 @@
mDimension(descriptor->dimension),
mRange({ConvertViewAspect(*mFormat, descriptor->aspect),
{descriptor->baseArrayLayer, descriptor->arrayLayerCount},
- {descriptor->baseMipLevel, descriptor->mipLevelCount}}) {
+ {descriptor->baseMipLevel, descriptor->mipLevelCount}}),
+ mUsage(RemoveInvalidViewUsages(GetTextureViewUsage(texture->GetUsage(), descriptor->usage),
+ &mFormat.get())),
+ mInternalUsage(
+ AddInternalUsages(GetDevice(),
+ GetTextureViewUsage(texture->GetInternalUsage(), descriptor->usage),
+ *mFormat,
+ texture->GetSampleCount(),
+ texture->GetNumMipLevels(),
+ texture->GetArrayLayers())) {
GetObjectTrackingList()->Track(this);
+
+ // Emit a warning if invalid usages were removed for this view.
+ // TODO(363903526): Remove this warning after deprecation period.
+ wgpu::TextureUsage inheritedUsage = GetTextureViewUsage(texture->GetUsage(), descriptor->usage);
+ if (mUsage != inheritedUsage) {
+ DAWN_ASSERT(descriptor->usage == wgpu::TextureUsage::None);
+ std::string warning = absl::StrFormat(
+ "%s with format (%s) and inherited usage (%s) is deprecated. Please request explicit "
+ "usages on texture views when the view format is not compatible with all inherited "
+ "texture usages.",
+ this, mFormat->format, inheritedUsage);
+ GetDevice()->EmitLog(WGPULoggingType_Warning, warning.c_str());
+ }
}
TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag, StringView label)
@@ -1396,6 +1470,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 115d65c..cc73f4e 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 99d0223..30a1c32 100644
--- a/src/dawn/native/vulkan/TextureVk.cpp
+++ b/src/dawn/native/vulkan/TextureVk.cpp
@@ -1102,6 +1102,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,
@@ -1850,8 +1851,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.
@@ -1866,15 +1866,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 e40ac93..8805f84 100644
--- a/src/dawn/node/binding/GPUTexture.cpp
+++ b/src/dawn/node/binding/GPUTexture.cpp
@@ -59,7 +59,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..cd718e5 100644
--- a/src/dawn/tests/unittests/validation/TextureViewValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/TextureViewValidationTests.cpp
@@ -945,6 +945,64 @@
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;
+
+ // TODO(363903526): Change this to inherited usage when inherited and explicit usages are
+ // validated the same way.
+ descriptor.usage = textureDescriptor.usage;
+
+ 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