Support sampling depth and stencil of combined d/s formats

This CL adds sampling of depth-only and stencil-only texture
views on all backends. However, Metal on macOS <= 10.11 will
need a workaround to use separate depth/stencil textures for
each aspect since it is impossible to sample the stencil
aspect of a combined depth/stencil texture.

Also fixes sampling of depth24plus on D3D12 which had an
incomplete check for determining if a TYPELESS format is
necessary.

Bug: dawn:439, dawn:553
Change-Id: Id4991c565f822add200054296714e2dcd330119a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30725
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Austin Eng
2020-11-04 15:27:11 +00:00
committed by Commit Bot service account
parent 9d6265bc07
commit a0f1725c4f
9 changed files with 633 additions and 153 deletions

View File

@@ -150,7 +150,7 @@ namespace dawn_native {
};
auto AddDepthStencilFormat = [&AddFormat](wgpu::TextureFormat format, Aspect aspects,
uint32_t byteSize, bool isDepthSampleable) {
uint32_t byteSize) {
Format internalFormat;
internalFormat.format = format;
internalFormat.isRenderable = true;
@@ -162,12 +162,8 @@ namespace dawn_native {
internalFormat.firstAspect.block.width = 1;
internalFormat.firstAspect.block.height = 1;
internalFormat.firstAspect.baseType = wgpu::TextureComponentType::Float;
if (isDepthSampleable) {
internalFormat.firstAspect.supportedComponentTypes =
ComponentTypeBit::Float | ComponentTypeBit::DepthComparison;
} else {
internalFormat.firstAspect.supportedComponentTypes = ComponentTypeBit::None;
}
internalFormat.firstAspect.supportedComponentTypes =
ComponentTypeBit::Float | ComponentTypeBit::DepthComparison;
AddFormat(internalFormat);
};
@@ -238,12 +234,12 @@ namespace dawn_native {
AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, 16, Type::Float);
// Depth-stencil formats
AddDepthStencilFormat(wgpu::TextureFormat::Depth32Float, Aspect::Depth, 4, true);
AddDepthStencilFormat(wgpu::TextureFormat::Depth24Plus, Aspect::Depth, 4, false);
AddDepthStencilFormat(wgpu::TextureFormat::Depth32Float, Aspect::Depth, 4);
AddDepthStencilFormat(wgpu::TextureFormat::Depth24Plus, Aspect::Depth, 4);
// 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, false);
Aspect::Depth | Aspect::Stencil, 4);
// BC compressed formats
bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC);

View File

@@ -171,7 +171,7 @@ namespace dawn_native { namespace d3d12 {
return DXGI_FORMAT_R32_TYPELESS;
case wgpu::TextureFormat::Depth24PlusStencil8:
return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
return DXGI_FORMAT_R32G8X24_TYPELESS;
case wgpu::TextureFormat::BC1RGBAUnorm:
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
@@ -451,8 +451,8 @@ namespace dawn_native { namespace d3d12 {
// This will need to be much more nuanced when WebGPU has
// texture view compatibility rules.
bool needsTypelessFormat = GetFormat().format == wgpu::TextureFormat::Depth32Float &&
(GetUsage() & wgpu::TextureUsage::Sampled) != 0;
const bool needsTypelessFormat =
GetFormat().HasDepthOrStencil() && (GetUsage() & wgpu::TextureUsage::Sampled) != 0;
DXGI_FORMAT dxgiFormat = needsTypelessFormat
? D3D12TypelessTextureFormat(GetFormat().format)
@@ -1027,13 +1027,50 @@ namespace dawn_native { namespace d3d12 {
TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor)
: TextureViewBase(texture, descriptor) {
mSrvDesc.Format = D3D12TextureFormat(descriptor->format);
if (descriptor->format == wgpu::TextureFormat::Depth32Float) {
// TODO(enga): This will need to be much more nuanced when WebGPU has
// texture view compatibility rules.
mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT;
}
mSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
// TODO(enga): This will need to be much more nuanced when WebGPU has
// texture view compatibility rules.
UINT planeSlice = 0;
if (GetFormat().HasDepthOrStencil()) {
// Configure the SRV descriptor to reinterpret the texture allocated as
// TYPELESS as a single-plane shader-accessible view.
switch (descriptor->format) {
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24Plus:
mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT;
break;
case wgpu::TextureFormat::Depth24PlusStencil8:
switch (descriptor->aspect) {
case wgpu::TextureAspect::DepthOnly:
planeSlice = 0;
mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
break;
case wgpu::TextureAspect::StencilOnly:
planeSlice = 1;
mSrvDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
// Stencil is accessed using the .g component in the shader.
// Map it to the zeroth component to match other APIs.
mSrvDesc.Shader4ComponentMapping =
D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
break;
case wgpu::TextureAspect::All:
// A single aspect is not selected. The texture view must not be
// sampled.
mSrvDesc.Format = DXGI_FORMAT_UNKNOWN;
break;
}
break;
default:
UNREACHABLE();
break;
}
}
// Currently we always use D3D12_TEX2D_ARRAY_SRV because we cannot specify base array layer
// and layer count in D3D12_TEX2D_SRV. For 2D texture views, we treat them as 1-layer 2D
// array textures.
@@ -1065,7 +1102,7 @@ namespace dawn_native { namespace d3d12 {
mSrvDesc.Texture2DArray.FirstArraySlice = descriptor->baseArrayLayer;
mSrvDesc.Texture2DArray.MipLevels = descriptor->mipLevelCount;
mSrvDesc.Texture2DArray.MostDetailedMip = descriptor->baseMipLevel;
mSrvDesc.Texture2DArray.PlaneSlice = 0;
mSrvDesc.Texture2DArray.PlaneSlice = planeSlice;
mSrvDesc.Texture2DArray.ResourceMinLODClamp = 0;
break;
case wgpu::TextureViewDimension::Cube:
@@ -1093,6 +1130,7 @@ namespace dawn_native { namespace d3d12 {
}
const D3D12_SHADER_RESOURCE_VIEW_DESC& TextureView::GetSRVDescriptor() const {
ASSERT(mSrvDesc.Format != DXGI_FORMAT_UNKNOWN);
return mSrvDesc;
}

View File

@@ -34,7 +34,7 @@ namespace dawn_native { namespace metal {
return usage & kUsageNeedsTextureView;
}
MTLTextureUsage MetalTextureUsage(wgpu::TextureUsage usage) {
MTLTextureUsage MetalTextureUsage(const Format& format, wgpu::TextureUsage usage) {
MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0
if (usage & (wgpu::TextureUsage::Storage)) {
@@ -43,6 +43,14 @@ namespace dawn_native { namespace metal {
if (usage & (wgpu::TextureUsage::Sampled)) {
result |= MTLTextureUsageShaderRead;
// For sampling stencil aspect of combined depth/stencil. See TextureView
// constructor.
if (@available(macOS 10.12, iOS 10.0, *)) {
if (IsSubset(Aspect::Depth | Aspect::Stencil, format.aspects)) {
result |= MTLTextureUsagePixelFormatView;
}
}
}
if (usage & (wgpu::TextureUsage::RenderAttachment)) {
@@ -85,6 +93,11 @@ namespace dawn_native { namespace metal {
return true;
}
if (IsSubset(Aspect::Depth | Aspect::Stencil, texture->GetFormat().aspects) &&
textureViewDescriptor->aspect == wgpu::TextureAspect::StencilOnly) {
return true;
}
switch (textureViewDescriptor->dimension) {
case wgpu::TextureViewDimension::Cube:
case wgpu::TextureViewDimension::CubeArray:
@@ -285,7 +298,8 @@ namespace dawn_native { namespace metal {
return {};
}
MTLTextureDescriptor* CreateMetalTextureDescriptor(const TextureDescriptor* descriptor) {
MTLTextureDescriptor* CreateMetalTextureDescriptor(DeviceBase* device,
const TextureDescriptor* descriptor) {
MTLTextureDescriptor* mtlDesc = [MTLTextureDescriptor new];
mtlDesc.width = descriptor->size.width;
@@ -293,7 +307,8 @@ namespace dawn_native { namespace metal {
mtlDesc.sampleCount = descriptor->sampleCount;
// TODO: add MTLTextureUsagePixelFormatView when needed when we support format
// reinterpretation.
mtlDesc.usage = MetalTextureUsage(descriptor->usage);
mtlDesc.usage = MetalTextureUsage(device->GetValidInternalFormat(descriptor->format),
descriptor->usage);
mtlDesc.pixelFormat = MetalPixelFormat(descriptor->format);
mtlDesc.mipmapLevelCount = descriptor->mipLevelCount;
mtlDesc.storageMode = MTLStorageModePrivate;
@@ -328,7 +343,7 @@ namespace dawn_native { namespace metal {
Texture::Texture(Device* device, const TextureDescriptor* descriptor)
: TextureBase(device, descriptor, TextureState::OwnedInternal) {
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(descriptor);
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
mMtlTexture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc];
[mtlDesc release];
@@ -351,7 +366,7 @@ namespace dawn_native { namespace metal {
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor),
TextureState::OwnedInternal) {
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor));
device, reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor));
mtlDesc.storageMode = kIOSurfaceStorageMode;
mMtlTexture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc
iosurface:ioSurface
@@ -581,6 +596,20 @@ namespace dawn_native { namespace metal {
mMtlTextureView = [mtlTexture retain];
} else {
MTLPixelFormat format = MetalPixelFormat(descriptor->format);
if (descriptor->aspect == wgpu::TextureAspect::StencilOnly) {
if (@available(macOS 10.12, iOS 10.0, *)) {
ASSERT(format == MTLPixelFormatDepth32Float_Stencil8);
format = MTLPixelFormatX32_Stencil8;
} else {
// TODO(enga): Add a workaround to back combined depth/stencil textures
// with Sampled usage using two separate textures.
// Or, consider always using the workaround for D32S8.
GetDevice()->ConsumedError(
DAWN_DEVICE_LOST_ERROR("Cannot create stencil-only texture view of "
"combined depth/stencil format."));
}
}
MTLTextureType textureViewType =
MetalTextureViewType(descriptor->dimension, texture->GetSampleCount());
auto mipLevelRange = NSMakeRange(descriptor->baseMipLevel, descriptor->mipLevelCount);

View File

@@ -306,6 +306,24 @@ namespace dawn_native { namespace opengl {
for (auto unit : mPipeline->GetTextureUnitsForTextureView(viewIndex)) {
gl.ActiveTexture(GL_TEXTURE0 + unit);
gl.BindTexture(target, handle);
if (ToBackend(view->GetTexture())->GetGLFormat().format ==
GL_DEPTH_STENCIL) {
Aspect aspect = view->GetAspects();
ASSERT(HasOneBit(aspect));
switch (aspect) {
case Aspect::None:
case Aspect::Color:
UNREACHABLE();
case Aspect::Depth:
gl.TexParameteri(target, GL_DEPTH_STENCIL_TEXTURE_MODE,
GL_DEPTH_COMPONENT);
break;
case Aspect::Stencil:
gl.TexParameteri(target, GL_DEPTH_STENCIL_TEXTURE_MODE,
GL_STENCIL_INDEX);
break;
}
}
}
break;
}

View File

@@ -96,6 +96,16 @@ namespace dawn_native { namespace opengl {
return true;
}
if (ToBackend(texture)->GetGLFormat().format == GL_DEPTH_STENCIL &&
(texture->GetUsage() & wgpu::TextureUsage::Sampled) != 0 &&
textureViewDescriptor->aspect == wgpu::TextureAspect::StencilOnly) {
// We need a separate view for one of the depth or stencil planes
// because each glTextureView needs it's own handle to set
// GL_DEPTH_STENCIL_TEXTURE_MODE. Choose the stencil aspect for the
// extra handle since it is likely sampled less often.
return true;
}
switch (textureViewDescriptor->dimension) {
case wgpu::TextureViewDimension::Cube:
case wgpu::TextureViewDimension::CubeArray: