Metal: set both depth/stencil attachments for combined formats

Adds a toggle to workaround another issue where Metal fails to set
the depth/stencil attachment correctly for a combined depth stencil
format if just one of the attachments is used. The workaround forces
both attachments to be set, giving the unused one LoadOp::Load and
StoreOp::Store so its contents are preserved.

Bug: dawn:1389
Change-Id: Iacbefcc57b33bf11ca8fcacb03506301646fe59d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/117175
Reviewed-by: Loko Kung <lokokung@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Austin Eng 2023-01-21 02:42:15 +00:00 committed by Dawn LUCI CQ
parent be4f5cdbe8
commit 387d57c805
10 changed files with 143 additions and 22 deletions

View File

@ -328,8 +328,19 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
"https://crbug.com/1237175"}},
{Toggle::MetalUseCombinedDepthStencilFormatForStencil8,
{"metal_use_combined_depth_stencil_format_for_stencil8",
"Use a combined depth stencil format instead of stencil8. The stencil8 format alone does not "
"work correctly.",
"Use a combined depth stencil format instead of stencil8. Works around an issue where the "
"stencil8 format alone does not work correctly. This toggle also causes depth stencil "
"attachments using a stencil8 format to also set the depth attachment in the Metal render "
"pass. This works around another issue where Metal fails to set the stencil attachment "
"correctly for a combined depth stencil format if the depth attachment is not also set.",
"https://crbug.com/dawn/1389"}},
{Toggle::MetalUseBothDepthAndStencilAttachmentsForCombinedDepthStencilFormats,
{"metal_use_both_depth_and_stencil_attachments_for_combined_depth_stencil_formats",
"In Metal, depth and stencil attachments are set separately. Setting just one without the "
"other does not work correctly for combined depth stencil formats on some Metal drivers. "
"This workarounds ensures that both are set. This situation arises during lazy clears, or "
"for stencil8 formats if metal_use_combined_depth_stencil_format_for_stencil8 is also "
"enabled.",
"https://crbug.com/dawn/1389"}},
{Toggle::UseTempTextureInStencilTextureToBufferCopy,
{"use_temp_texture_in_stencil_texture_to_buffer_copy",

View File

@ -83,6 +83,7 @@ enum class Toggle {
VulkanSplitCommandBufferOnDepthStencilComputeSampleAfterRenderPass,
D3D12Allocate2DTexturewithCopyDstAsCommittedResource,
MetalUseCombinedDepthStencilFormatForStencil8,
MetalUseBothDepthAndStencilAttachmentsForCombinedDepthStencilFormats,
UseTempTextureInStencilTextureToBufferCopy,
DisallowDeprecatedAPIs,

View File

@ -169,6 +169,7 @@ NSRef<MTLComputePassDescriptor> CreateMTLComputePassDescriptor(BeginComputePassC
}
NSRef<MTLRenderPassDescriptor> CreateMTLRenderPassDescriptor(
const Device* device,
BeginRenderPassCmd* renderPass,
bool useCounterSamplingAtStageBoundary) {
// Note that this creates a descriptor that's autoreleased so we don't use AcquireNSRef
@ -801,11 +802,11 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
commandContext->EndBlit();
LazyClearRenderPassAttachments(cmd);
Device* device = ToBackend(GetDevice());
NSRef<MTLRenderPassDescriptor> descriptor = CreateMTLRenderPassDescriptor(
cmd, ToBackend(GetDevice())->UseCounterSamplingAtStageBoundary());
device, cmd, device->UseCounterSamplingAtStageBoundary());
DAWN_TRY(EncodeMetalRenderPass(
ToBackend(GetDevice()), commandContext, descriptor.Get(), cmd->width,
cmd->height,
device, commandContext, descriptor.Get(), cmd->width, cmd->height,
[this](id<MTLRenderCommandEncoder> encoder, BeginRenderPassCmd* cmd)
-> MaybeError { return this->EncodeRenderPass(encoder, cmd); },
cmd));

View File

@ -260,6 +260,8 @@ void Device::InitTogglesFromDriver() {
#if DAWN_PLATFORM_IS(MACOS)
if (gpu_info::IsIntel(vendorId)) {
SetToggle(Toggle::UseTempTextureInStencilTextureToBufferCopy, true);
SetToggle(Toggle::MetalUseBothDepthAndStencilAttachmentsForCombinedDepthStencilFormats,
true);
if ([NSProcessInfo.processInfo
isOperatingSystemAtLeastVersion:NSOperatingSystemVersion{12, 0, 0}]) {

View File

@ -373,14 +373,24 @@ MaybeError RenderPipeline::Initialize() {
if (HasDepthStencilAttachment()) {
wgpu::TextureFormat depthStencilFormat = GetDepthStencilFormat();
const Format& internalFormat = GetDevice()->GetValidInternalFormat(depthStencilFormat);
MTLPixelFormat metalFormat = MetalPixelFormat(GetDevice(), depthStencilFormat);
if (internalFormat.HasDepth()) {
descriptorMTL.depthAttachmentPixelFormat = metalFormat;
}
if (internalFormat.HasStencil()) {
descriptorMTL.stencilAttachmentPixelFormat = metalFormat;
if (GetDevice()->IsToggleEnabled(
Toggle::MetalUseBothDepthAndStencilAttachmentsForCombinedDepthStencilFormats)) {
if (GetDepthStencilAspects(metalFormat) & Aspect::Depth) {
descriptorMTL.depthAttachmentPixelFormat = metalFormat;
}
if (GetDepthStencilAspects(metalFormat) & Aspect::Stencil) {
descriptorMTL.stencilAttachmentPixelFormat = metalFormat;
}
} else {
const Format& internalFormat = GetDevice()->GetValidInternalFormat(depthStencilFormat);
if (internalFormat.HasDepth()) {
descriptorMTL.depthAttachmentPixelFormat = metalFormat;
}
if (internalFormat.HasStencil()) {
descriptorMTL.stencilAttachmentPixelFormat = metalFormat;
}
}
}

View File

@ -32,6 +32,7 @@ enum class SingleShaderStage;
namespace dawn::native::metal {
Aspect GetDepthStencilAspects(MTLPixelFormat format);
MTLCompareFunction ToMetalCompareFunction(wgpu::CompareFunction compareFunction);
struct TextureBufferCopySplit {

View File

@ -140,8 +140,29 @@ void ResolveInAnotherRenderPass(
commandContext->BeginRender(mtlRenderPassForResolve);
commandContext->EndRender();
}
} // anonymous namespace
Aspect GetDepthStencilAspects(MTLPixelFormat format) {
switch (format) {
case MTLPixelFormatDepth16Unorm:
case MTLPixelFormatDepth32Float:
return Aspect::Depth;
#if DAWN_PLATFORM_IS(MACOS)
case MTLPixelFormatDepth24Unorm_Stencil8:
#endif
case MTLPixelFormatDepth32Float_Stencil8:
return Aspect::Depth | Aspect::Stencil;
case MTLPixelFormatStencil8:
return Aspect::Stencil;
default:
UNREACHABLE();
}
}
MTLCompareFunction ToMetalCompareFunction(wgpu::CompareFunction compareFunction) {
switch (compareFunction) {
case wgpu::CompareFunction::Never:
@ -347,6 +368,34 @@ MaybeError EncodeMetalRenderPass(Device* device,
// workarounds to happen at the same time, it handles workarounds one by one and calls
// itself recursively to handle the next workaround if needed.
// Handle the workaround where both depth and stencil attachments must be set for a
// combined depth-stencil format, not just one.
if (device->IsToggleEnabled(
Toggle::MetalUseBothDepthAndStencilAttachmentsForCombinedDepthStencilFormats)) {
const bool hasDepthAttachment = mtlRenderPass.depthAttachment.texture != nil;
const bool hasStencilAttachment = mtlRenderPass.stencilAttachment.texture != nil;
if (hasDepthAttachment && !hasStencilAttachment) {
if (GetDepthStencilAspects([mtlRenderPass.depthAttachment.texture pixelFormat]) &
Aspect::Stencil) {
mtlRenderPass.stencilAttachment.texture = mtlRenderPass.depthAttachment.texture;
mtlRenderPass.stencilAttachment.level = mtlRenderPass.depthAttachment.level;
mtlRenderPass.stencilAttachment.slice = mtlRenderPass.depthAttachment.slice;
mtlRenderPass.stencilAttachment.loadAction = MTLLoadActionLoad;
mtlRenderPass.stencilAttachment.storeAction = MTLStoreActionStore;
}
} else if (hasStencilAttachment && !hasDepthAttachment) {
if (GetDepthStencilAspects([mtlRenderPass.stencilAttachment.texture pixelFormat]) &
Aspect::Depth) {
mtlRenderPass.depthAttachment.texture = mtlRenderPass.stencilAttachment.texture;
mtlRenderPass.depthAttachment.level = mtlRenderPass.stencilAttachment.level;
mtlRenderPass.depthAttachment.slice = mtlRenderPass.stencilAttachment.slice;
mtlRenderPass.depthAttachment.loadAction = MTLLoadActionLoad;
mtlRenderPass.depthAttachment.storeAction = MTLStoreActionStore;
}
}
}
// Handles the workaround for r8unorm rg8unorm mipmap rendering being broken on some
// devices. Render to a temporary texture instead and then copy back to the attachment.
if (device->IsToggleEnabled(Toggle::MetalRenderR8RG8UnormSmallMipToTempTexture)) {

View File

@ -875,6 +875,47 @@ TEST_P(StencilCopyTests, ToStencilAspectAtNonZeroOffset) {
}
}
// Test uploading to the non-zero mip, stencil-only aspect of a texture,
// and then checking the contents with a stencil test.
TEST_P(StencilCopyTests, CopyNonzeroMipThenReadWithStencilTest) {
// Copies to a single aspect are unsupported on OpenGL.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
// Create a stencil texture
constexpr uint32_t kWidth = 4;
constexpr uint32_t kHeight = 4;
constexpr uint32_t kMipLevel = 1;
wgpu::Texture depthStencilTexture =
CreateDepthStencilTexture(kWidth, kHeight,
wgpu::TextureUsage::RenderAttachment |
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst,
kMipLevel + 1);
std::vector<uint8_t> stencilData = {
7u, 7u, //
7u, 7u, //
};
// Upload the stencil data.
{
wgpu::TextureDataLayout dataLayout = {};
dataLayout.bytesPerRow = kWidth >> kMipLevel;
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
depthStencilTexture, 1, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
wgpu::Extent3D copySize = {kWidth >> kMipLevel, kHeight >> kMipLevel, 1};
queue.WriteTexture(&imageCopyTexture, stencilData.data(), stencilData.size(), &dataLayout,
&copySize);
}
// Check the stencil contents.
ExpectAttachmentStencilTestData(depthStencilTexture, GetParam().mTextureFormat,
kWidth >> kMipLevel, kWidth >> kMipLevel, 0u, kMipLevel, 7u);
}
DAWN_INSTANTIATE_TEST_P(DepthStencilCopyTests,
{D3D12Backend(), MetalBackend(),
MetalBackend({"use_temp_texture_in_stencil_texture_to_buffer_copy"}),
@ -907,8 +948,10 @@ DAWN_INSTANTIATE_TEST_P(
D3D12Backend({"d3d12_use_temp_buffer_in_depth_stencil_texture_and_buffer_"
"copy_with_non_zero_buffer_offset"}),
MetalBackend(), MetalBackend({"metal_use_combined_depth_stencil_format_for_stencil8"}),
MetalBackend({"use_temp_texture_in_stencil_texture_to_buffer_copy"}), OpenGLBackend(),
OpenGLESBackend(),
MetalBackend({"use_temp_texture_in_stencil_texture_to_buffer_copy"}),
MetalBackend(
{"metal_use_both_depth_and_stencil_attachments_for_combined_depth_stencil_formats"}),
OpenGLBackend(), OpenGLESBackend(),
// Test with the vulkan_use_s8 toggle forced on and off.
VulkanBackend({"vulkan_use_s8"}, {}), VulkanBackend({}, {"vulkan_use_s8"})},
std::vector<wgpu::TextureFormat>(utils::kStencilFormats.begin(), utils::kStencilFormats.end()));

View File

@ -115,6 +115,8 @@ class DepthStencilLoadOpTests : public DawnTestWithParams<DepthStencilLoadOpTest
switch (GetParam().mCheck) {
case Check::SampleDepth: {
DAWN_TEST_UNSUPPORTED_IF(utils::IsStencilOnlyFormat(GetParam().mFormat));
std::vector<float> expectedDepth(mipSize * mipSize, kDepthValues[mipLevel]);
ExpectSampledDepthData(
texture, mipSize, mipSize, 0, mipLevel,
@ -124,6 +126,8 @@ class DepthStencilLoadOpTests : public DawnTestWithParams<DepthStencilLoadOpTest
}
case Check::CopyDepth: {
DAWN_TEST_UNSUPPORTED_IF(utils::IsStencilOnlyFormat(GetParam().mFormat));
if (GetParam().mFormat == wgpu::TextureFormat::Depth16Unorm) {
std::vector<uint16_t> expectedDepth(mipSize * mipSize,
kU16DepthValues[mipLevel]);
@ -150,6 +154,8 @@ class DepthStencilLoadOpTests : public DawnTestWithParams<DepthStencilLoadOpTest
}
case Check::DepthTest: {
DAWN_TEST_UNSUPPORTED_IF(utils::IsStencilOnlyFormat(GetParam().mFormat));
std::vector<float> expectedDepth(mipSize * mipSize, kDepthValues[mipLevel]);
ExpectAttachmentDepthTestData(texture, GetParam().mFormat, mipSize, mipSize, 0,
mipLevel, expectedDepth)
@ -232,8 +238,12 @@ auto GenerateParam() {
auto params2 = MakeParamGenerator<DepthStencilLoadOpTestParams>(
{D3D12Backend(), D3D12Backend({}, {"use_d3d12_render_pass"}), MetalBackend(),
MetalBackend({"metal_use_combined_depth_stencil_format_for_stencil8"}),
MetalBackend(
{"metal_use_both_depth_and_stencil_attachments_for_combined_depth_stencil_formats"}),
OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
{wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureFormat::Depth32FloatStencil8},
{wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureFormat::Depth32FloatStencil8,
wgpu::TextureFormat::Stencil8},
{Check::CopyStencil, Check::StencilTest, Check::DepthTest, Check::SampleDepth});
std::vector<DepthStencilLoadOpTestParams> allParams;
@ -285,9 +295,7 @@ TEST_P(StencilClearValueOverflowTest, StencilClearValueOverFlowUint16) {
DAWN_INSTANTIATE_TEST_P(StencilClearValueOverflowTest,
{D3D12Backend(), D3D12Backend({}, {"use_d3d12_render_pass"}),
MetalBackend(),
MetalBackend({"metal_use_combined_depth_stencil_format_for_stencil8"}),
OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
MetalBackend(), OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
{wgpu::TextureFormat::Depth24PlusStencil8,
wgpu::TextureFormat::Depth32FloatStencil8, wgpu::TextureFormat::Stencil8},
{Check::CopyStencil, Check::StencilTest});

View File

@ -335,10 +335,6 @@ crbug.com/dawn/1083 [ monterey ] webgpu:api,operation,command_buffer,copyTexture
crbug.com/dawn/1083 [ monterey ] webgpu:api,operation,command_buffer,copyTextureToTexture:copy_depth_stencil:format="depth24plus-stencil8" [ Failure ]
crbug.com/dawn/1083 [ monterey ] webgpu:api,operation,command_buffer,copyTextureToTexture:copy_depth_stencil:format="depth32float" [ Failure ]
crbug.com/dawn/1083 [ monterey ] webgpu:api,operation,command_buffer,copyTextureToTexture:copy_depth_stencil:format="depth32float-stencil8" [ Failure ]
crbug.com/dawn/1083 [ monterey ] webgpu:api,operation,command_buffer,image_copy:offsets_and_sizes_copy_depth_stencil:format="stencil8";copyMethod="CopyB2T";aspect="stencil-only" [ Failure ]
crbug.com/dawn/1083 [ monterey ] webgpu:api,operation,command_buffer,image_copy:offsets_and_sizes_copy_depth_stencil:format="stencil8";copyMethod="WriteTexture";aspect="stencil-only" [ Failure ]
crbug.com/dawn/1083 [ monterey ] webgpu:api,operation,command_buffer,image_copy:rowsPerImage_and_bytesPerRow_depth_stencil:format="stencil8";copyMethod="CopyB2T";aspect="stencil-only" [ Failure ]
crbug.com/dawn/1083 [ monterey ] webgpu:api,operation,command_buffer,image_copy:rowsPerImage_and_bytesPerRow_depth_stencil:format="stencil8";copyMethod="WriteTexture";aspect="stencil-only" [ Failure ]
############################################################################
# Flaky on Intel Mac
@ -353,7 +349,6 @@ crbug.com/dawn/1500 [ intel-gen-9 monterey ] webgpu:api,operation,command_buffer
crbug.com/dawn/1389 [ monterey ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToBuffer";format="depth16unorm" [ Failure ]
crbug.com/dawn/1389 [ monterey ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToTexture";format="depth16unorm" [ Failure ]
crbug.com/dawn/1389 [ monterey ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="DepthTest";format="depth16unorm" [ Failure ]
crbug.com/dawn/1389 [ monterey ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="StencilTest";format="stencil8" [ Failure ]
################################################################################
# copyToTexture,canvas:color_space_conversion:* fail with swiftshader