[dawn][native][metal] Clean up texture view initialization
Original plan here was to simply avoid mixing early-false and early-true
returns in RequiresCreatingNewTextureView. But I did more than that, as
it turns out there was a lot more tangled logic here.
Bug: 447271110
Change-Id: I824bc6cf997f2ee28a24126a4e08550ed2b76859
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/265335
Reviewed-by: Fr <beaufort.francois@gmail.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn/native/metal/TextureMTL.h b/src/dawn/native/metal/TextureMTL.h
index 547086a..6100a4b 100644
--- a/src/dawn/native/metal/TextureMTL.h
+++ b/src/dawn/native/metal/TextureMTL.h
@@ -61,6 +61,9 @@
Texture(DeviceBase* device, const UnpackedPtr<TextureDescriptor>& descriptor);
+ MTLTextureType GetMTLTextureType() const;
+ MTLTextureUsage GetMTLTextureUsage() const;
+
id<MTLTexture> GetMTLTexture(Aspect aspect) const;
IOSurfaceRef GetIOSurface();
NSPRef<id<MTLTexture>> CreateFormatView(wgpu::TextureFormat format);
@@ -94,9 +97,11 @@
TextureBase::ClearValue clearValue);
absl::InlinedVector<NSPRef<id<MTLTexture>>, kMaxPlanesPerFormat> mMtlPlaneTextures;
- MTLPixelFormat mMtlFormat = MTLPixelFormatInvalid;
+ MTLPixelFormat mMtlFormat = MTLPixelFormatInvalid;
+ MTLTextureType mMtlTextureType;
MTLTextureUsage mMtlUsage;
+
CFRef<IOSurfaceRef> mIOSurface = nullptr;
};
diff --git a/src/dawn/native/metal/TextureMTL.mm b/src/dawn/native/metal/TextureMTL.mm
index a1d9ec4..32876fe 100644
--- a/src/dawn/native/metal/TextureMTL.mm
+++ b/src/dawn/native/metal/TextureMTL.mm
@@ -130,63 +130,38 @@
return mtlSwizzle;
}
-bool ShouldCreateNewTextureView(const TextureBase* texture,
- wgpu::TextureUsage internalViewUsage,
- const UnpackedPtr<TextureViewDescriptor>& textureViewDescriptor,
- bool needsSwizzle) {
- constexpr wgpu::TextureUsage kShaderUsageNeedsView =
- wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
- constexpr wgpu::TextureUsage kUsageNeedsView = kShaderUsageNeedsView |
- wgpu::TextureUsage::RenderAttachment |
- wgpu::TextureUsage::StorageAttachment;
- if ((internalViewUsage & kUsageNeedsView) == 0) {
- return false;
- }
+bool RequiresCreatingNewTextureView(const Texture* texture,
+ bool viewMtlFormatDiffers,
+ wgpu::TextureUsage internalViewUsage,
+ const UnpackedPtr<TextureViewDescriptor>& textureViewDescriptor,
+ MTLTextureType textureViewType,
+ const std::optional<MTLTextureSwizzleChannels>& swizzle) {
+ // A view can have render attachment usages, shader binding usages, or both, so those are the
+ // cases handled below. (Technically they can have copy-only usages, but such views can't be
+ // used for anything, so we don't bother to optimize to avoid creating views in that case.)
- if (texture->GetFormat().format != textureViewDescriptor->format &&
- !texture->GetFormat().HasDepthOrStencil()) {
- // Color format reinterpretation required.
- // Note: Depth/stencil formats don't support reinterpretation.
- // See also TextureView::GetAttachmentInfo when modifying this condition.
+ // Different format (color format reinterpretation or aspect subsetting) always requires a view.
+ if (viewMtlFormatDiffers) {
return true;
}
- // Reinterpretation not required. Now, we only need a new view if the view dimension or
- // set of subresources for the shader is different from the base texture.
- if ((texture->GetInternalUsage() & kShaderUsageNeedsView) == 0) {
- return false;
- }
-
- if (texture->GetArrayLayers() != textureViewDescriptor->arrayLayerCount ||
- (texture->GetArrayLayers() == 1 && texture->GetDimension() == wgpu::TextureDimension::e2D &&
- textureViewDescriptor->dimension == wgpu::TextureViewDimension::e2DArray)) {
- // If the view has a different number of array layers, we need a new view.
- // And, if the original texture is a 2D texture with one array layer, we need a new
- // view to view it as a 2D array texture.
- return true;
- }
-
- if (texture->GetNumMipLevels() != textureViewDescriptor->mipLevelCount) {
- return true;
- }
-
- // If the texture is created with MTLTextureUsagePixelFormatView, we need
- // a new view to perform format reinterpretation.
- if ((MetalTextureUsage(texture->GetFormat(), texture->GetInternalUsage()) &
- MTLTextureUsagePixelFormatView) != 0) {
- return true;
- }
-
- switch (textureViewDescriptor->dimension) {
- case wgpu::TextureViewDimension::Cube:
- case wgpu::TextureViewDimension::CubeArray:
+ // A view is only needed for any other parameters if used from a shader. (For attachments,
+ // subresource indices are passed elsewhere in the backend, not as part of the Metal view.)
+ bool hasShaderUsages = internalViewUsage & (wgpu::TextureUsage::StorageBinding |
+ wgpu::TextureUsage::TextureBinding);
+ if (hasShaderUsages) {
+ if (texture->GetNumMipLevels() != textureViewDescriptor->mipLevelCount) {
return true;
- default:
- break;
- }
-
- if (needsSwizzle) {
- return true;
+ }
+ if (texture->GetArrayLayers() != textureViewDescriptor->arrayLayerCount) {
+ return true;
+ }
+ if (texture->GetMTLTextureType() != textureViewType) {
+ return true;
+ }
+ if (swizzle.has_value()) {
+ return true;
+ }
}
return false;
@@ -272,7 +247,7 @@
if (GetDevice()->IsToggleEnabled(Toggle::MetalUseCombinedDepthStencilFormatForStencil8) &&
GetFormat().format == wgpu::TextureFormat::Stencil8) {
// If we used a combined depth stencil format instead of stencil8, we need
- // MTLTextureUsagePixelFormatView to reinterpet as stencil8.
+ // MTLTextureUsagePixelFormatView to reinterpret as stencil8.
mtlDesc.usage |= MTLTextureUsagePixelFormatView;
}
mtlDesc.mipmapLevelCount = GetNumMipLevels();
@@ -370,6 +345,7 @@
if (!GetFormat().IsMultiPlanar()) {
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
+ mMtlTextureType = [*mtlDesc textureType];
mMtlUsage = [*mtlDesc usage];
mMtlFormat = [*mtlDesc pixelFormat];
mMtlPlaneTextures.resize(1);
@@ -395,6 +371,7 @@
"Usage flags (%s) include %s, which is not compatible with creation from IOSurface.",
GetInternalUsage(), wgpu::TextureUsage::TransientAttachment);
+ mMtlTextureType = MTLTextureType2D;
mMtlUsage = MetalTextureUsage(GetFormat(), GetInternalUsage());
// Multiplanar format doesn't have equivalent MTLPixelFormat so just set it to invalid.
mMtlFormat = MTLPixelFormatInvalid;
@@ -417,6 +394,7 @@
void Texture::InitializeAsWrapping(const UnpackedPtr<TextureDescriptor>& descriptor,
NSPRef<id<MTLTexture>> wrapped) {
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
+ mMtlTextureType = [*mtlDesc textureType];
mMtlUsage = [*mtlDesc usage];
mMtlFormat = [*mtlDesc pixelFormat];
mMtlPlaneTextures.resize(1);
@@ -433,6 +411,7 @@
GetInternalUsage(), wgpu::TextureUsage::TransientAttachment);
mIOSurface = memory->GetIOSurface();
+ mMtlTextureType = MTLTextureType2D;
mMtlUsage = memory->GetMtlTextureUsage();
mMtlFormat = memory->GetMtlPixelFormat();
mMtlPlaneTextures = memory->GetMtlPlaneTextures();
@@ -486,6 +465,14 @@
}
}
+MTLTextureType Texture::GetMTLTextureType() const {
+ return mMtlTextureType;
+}
+
+MTLTextureUsage Texture::GetMTLTextureUsage() const {
+ return mMtlUsage;
+}
+
id<MTLTexture> Texture::GetMTLTexture(Aspect aspect) const {
switch (aspect) {
case Aspect::Plane0:
@@ -807,59 +794,56 @@
Aspect aspect = SelectFormatAspects(texture->GetFormat(), descriptor->aspect);
id<MTLTexture> mtlTexture = texture->GetMTLTexture(aspect);
- std::optional<MTLTextureSwizzleChannels> mtlSwizzle = ComputeMetalSwizzle();
- bool needsNewView =
- ShouldCreateNewTextureView(texture, GetInternalUsage(), descriptor, mtlSwizzle.has_value());
- if (device->IsToggleEnabled(Toggle::MetalUseCombinedDepthStencilFormatForStencil8) &&
- GetTexture()->GetFormat().format == wgpu::TextureFormat::Stencil8) {
- // If MetalUseCombinedDepthStencilFormatForStencil8 is true and the format is Stencil8,
- // we used a combined format instead on texture allocation.
- // We need a new view to view it as stencil8.
- needsNewView = true;
- }
- if (!needsNewView) {
- mMtlTextureView = mtlTexture;
- } else if (texture->GetFormat().IsMultiPlanar()) {
+ if (texture->GetFormat().IsMultiPlanar()) {
// For multiplanar texture, plane view is already created in
// InitializeFromInternalMultiPlanarTexture(). The view is only nullptr if aspect is
// invalid.
DAWN_ASSERT(mtlTexture != nullptr);
mMtlTextureView = mtlTexture;
} else {
- MTLPixelFormat viewFormat = MetalPixelFormat(device, descriptor->format);
- MTLPixelFormat textureFormat = MetalPixelFormat(device, GetTexture()->GetFormat().format);
+ MTLTextureType textureViewType =
+ MetalTextureViewType(descriptor->dimension, texture->GetSampleCount());
+ std::optional<MTLTextureSwizzleChannels> mtlSwizzle = ComputeMetalSwizzle();
+ MTLPixelFormat viewFormat = MetalPixelFormat(device, descriptor->format);
+ MTLPixelFormat textureFormat = MetalPixelFormat(device, texture->GetFormat().format);
if (aspect == Aspect::Stencil && textureFormat != MTLPixelFormatStencil8) {
+ // Note we never use MTLPixelFormatDepth24Unorm_Stencil8 (doesn't exist on Apple GPUs).
DAWN_ASSERT(textureFormat == MTLPixelFormatDepth32Float_Stencil8);
viewFormat = MTLPixelFormatX32_Stencil8;
- } else if (GetTexture()->GetFormat().HasDepth() && GetTexture()->GetFormat().HasStencil()) {
+ } else if (texture->GetFormat().HasDepth() && texture->GetFormat().HasStencil()) {
// Depth-only views for depth/stencil textures in Metal simply use the original
// texture's format.
viewFormat = textureFormat;
}
- MTLTextureType textureViewType =
- MetalTextureViewType(descriptor->dimension, texture->GetSampleCount());
- auto mipLevelRange = NSMakeRange(descriptor->baseMipLevel, descriptor->mipLevelCount);
- auto arrayLayerRange = NSMakeRange(descriptor->baseArrayLayer, descriptor->arrayLayerCount);
-
- if (mtlSwizzle) {
- mMtlTextureView =
- AcquireNSPRef([mtlTexture newTextureViewWithPixelFormat:viewFormat
- textureType:textureViewType
- levels:mipLevelRange
- slices:arrayLayerRange
- swizzle:mtlSwizzle.value()]);
+ if (!RequiresCreatingNewTextureView(texture, viewFormat != textureFormat,
+ GetInternalUsage(), descriptor, textureViewType,
+ mtlSwizzle)) {
+ mMtlTextureView = mtlTexture;
} else {
- mMtlTextureView =
- AcquireNSPRef([mtlTexture newTextureViewWithPixelFormat:viewFormat
- textureType:textureViewType
- levels:mipLevelRange
- slices:arrayLayerRange]);
- }
+ auto mipLevelRange = NSMakeRange(descriptor->baseMipLevel, descriptor->mipLevelCount);
+ auto arrayLayerRange =
+ NSMakeRange(descriptor->baseArrayLayer, descriptor->arrayLayerCount);
- if (mMtlTextureView == nil) {
- return DAWN_INTERNAL_ERROR("Failed to create MTLTexture view.");
+ if (mtlSwizzle) {
+ mMtlTextureView =
+ AcquireNSPRef([mtlTexture newTextureViewWithPixelFormat:viewFormat
+ textureType:textureViewType
+ levels:mipLevelRange
+ slices:arrayLayerRange
+ swizzle:mtlSwizzle.value()]);
+ } else {
+ mMtlTextureView =
+ AcquireNSPRef([mtlTexture newTextureViewWithPixelFormat:viewFormat
+ textureType:textureViewType
+ levels:mipLevelRange
+ slices:arrayLayerRange]);
+ }
+
+ if (mMtlTextureView == nil) {
+ return DAWN_INTERNAL_ERROR("Failed to create MTLTexture view.");
+ }
}
}
diff --git a/src/dawn/native/metal/UtilsMetal.mm b/src/dawn/native/metal/UtilsMetal.mm
index 9deb93dc..d63edf5 100644
--- a/src/dawn/native/metal/UtilsMetal.mm
+++ b/src/dawn/native/metal/UtilsMetal.mm
@@ -255,6 +255,7 @@
return MTLPixelFormatDepth32Float;
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
+ // Note we never use MTLPixelFormatDepth24Unorm_Stencil8 (doesn't exist on Apple GPUs).
return MTLPixelFormatDepth32Float_Stencil8;
case wgpu::TextureFormat::Depth16Unorm:
return MTLPixelFormatDepth16Unorm;
@@ -308,6 +309,7 @@
case wgpu::TextureFormat::BC6HRGBUfloat:
case wgpu::TextureFormat::BC7RGBAUnorm:
case wgpu::TextureFormat::BC7RGBAUnormSrgb:
+ DAWN_UNREACHABLE();
#endif
case wgpu::TextureFormat::ETC2RGB8Unorm:
@@ -457,9 +459,6 @@
case MTLPixelFormatDepth32Float:
return Aspect::Depth;
-#if DAWN_PLATFORM_IS(MACOS)
- case MTLPixelFormatDepth24Unorm_Stencil8:
-#endif
case MTLPixelFormatDepth32Float_Stencil8:
return Aspect::Depth | Aspect::Stencil;
@@ -467,6 +466,7 @@
return Aspect::Stencil;
default:
+ // Note we never use MTLPixelFormatDepth24Unorm_Stencil8 (doesn't exist on Apple GPUs).
DAWN_UNREACHABLE();
}
}