diff --git a/src/dawn/native/CommandEncoder.cpp b/src/dawn/native/CommandEncoder.cpp index 6cdb86b2c2..29d4ba6734 100644 --- a/src/dawn/native/CommandEncoder.cpp +++ b/src/dawn/native/CommandEncoder.cpp @@ -369,15 +369,19 @@ namespace dawn::native { } } else { DAWN_TRY(ValidateLoadOp(depthStencilAttachment->stencilLoadOp)); - DAWN_INVALID_IF(depthStencilAttachment->stencilLoadOp == wgpu::LoadOp::Undefined, - "stencilLoadOp must be set if the attachment (%s) has a stencil " - "aspect and stencilReadOnly (%u) is false.", - attachment, depthStencilAttachment->stencilReadOnly); + DAWN_INVALID_IF( + depthStencilAttachment->stencilLoadOp == wgpu::LoadOp::Undefined, + "stencilLoadOp (%s) must be set if the attachment (%s) has a stencil " + "aspect and stencilReadOnly (%u) is false.", + depthStencilAttachment->stencilLoadOp, attachment, + depthStencilAttachment->stencilReadOnly); DAWN_TRY(ValidateStoreOp(depthStencilAttachment->stencilStoreOp)); - DAWN_INVALID_IF(depthStencilAttachment->depthStoreOp == wgpu::StoreOp::Undefined, - "stencilStoreOp must be set if the attachment (%s) has a stencil " - "aspect and stencilReadOnly (%u) is false.", - attachment, depthStencilAttachment->stencilReadOnly); + DAWN_INVALID_IF( + depthStencilAttachment->stencilStoreOp == wgpu::StoreOp::Undefined, + "stencilStoreOp (%s) must be set if the attachment (%s) has a stencil " + "aspect and stencilReadOnly (%u) is false.", + depthStencilAttachment->stencilStoreOp, attachment, + depthStencilAttachment->stencilReadOnly); } if (!std::isnan(depthStencilAttachment->clearDepth)) { diff --git a/src/dawn/native/Format.cpp b/src/dawn/native/Format.cpp index 2c725e8327..1e4b694cb6 100644 --- a/src/dawn/native/Format.cpp +++ b/src/dawn/native/Format.cpp @@ -264,13 +264,22 @@ namespace dawn::native { internalFormat.baseFormat = baseFormat; } - AspectInfo* firstAspect = internalFormat.aspectInfo.data(); - firstAspect->block.byteSize = 1; - firstAspect->block.width = 1; - firstAspect->block.height = 1; - firstAspect->baseType = wgpu::TextureComponentType::Uint; - firstAspect->supportedSampleTypes = SampleTypeBit::Uint; - firstAspect->format = format; + // Duplicate the data for the stencil aspect in both the first and second aspect info. + // - aspectInfo[0] is used by AddMultiAspectFormat to copy the info for the whole + // stencil8 aspect of depth-stencil8 formats. + // - aspectInfo[1] is the actual info used in the rest of Dawn since + // GetAspectIndex(Aspect::Stencil) is 1. + ASSERT(GetAspectIndex(Aspect::Stencil) == 1); + + internalFormat.aspectInfo[0].block.byteSize = 1; + internalFormat.aspectInfo[0].block.width = 1; + internalFormat.aspectInfo[0].block.height = 1; + internalFormat.aspectInfo[0].baseType = wgpu::TextureComponentType::Uint; + internalFormat.aspectInfo[0].supportedSampleTypes = SampleTypeBit::Uint; + internalFormat.aspectInfo[0].format = format; + + internalFormat.aspectInfo[1] = internalFormat.aspectInfo[0]; + AddFormat(internalFormat); }; @@ -330,9 +339,17 @@ namespace dawn::native { internalFormat.baseFormat = baseFormat; } + // Multi aspect formats just copy information about single-aspect formats. This + // means that the single-plane formats must have been added before multi-aspect + // ones. (it is ASSERTed below). const size_t firstFormatIndex = ComputeFormatIndex(firstFormat); const size_t secondFormatIndex = ComputeFormatIndex(secondFormat); + ASSERT(table[firstFormatIndex].aspectInfo[0].format != + wgpu::TextureFormat::Undefined); + ASSERT(table[secondFormatIndex].aspectInfo[0].format != + wgpu::TextureFormat::Undefined); + internalFormat.aspectInfo[0] = table[firstFormatIndex].aspectInfo[0]; internalFormat.aspectInfo[1] = table[secondFormatIndex].aspectInfo[0]; @@ -388,8 +405,7 @@ namespace dawn::native { AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, false, false, 16, SampleTypeBit::UnfilterableFloat, 4); // Depth-stencil formats - // TODO(dawn:666): Implement the stencil8 format - AddStencilFormat(wgpu::TextureFormat::Stencil8, false); + AddStencilFormat(wgpu::TextureFormat::Stencil8, true); AddDepthFormat(wgpu::TextureFormat::Depth16Unorm, 2, true); // TODO(crbug.com/dawn/843): This is 4 because we read this to perform zero initialization, // and textures are always use depth32float. We should improve this to be more robust. Perhaps, diff --git a/src/dawn/native/Format.h b/src/dawn/native/Format.h index 441794734d..0f72d874e5 100644 --- a/src/dawn/native/Format.h +++ b/src/dawn/native/Format.h @@ -72,7 +72,7 @@ namespace dawn::native { // an internal Dawn enum. wgpu::TextureComponentType baseType; SampleTypeBit supportedSampleTypes; - wgpu::TextureFormat format; + wgpu::TextureFormat format = wgpu::TextureFormat::Undefined; }; // The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the diff --git a/src/dawn/native/Subresource.cpp b/src/dawn/native/Subresource.cpp index a83142bfca..6ebba9ff94 100644 --- a/src/dawn/native/Subresource.cpp +++ b/src/dawn/native/Subresource.cpp @@ -87,6 +87,10 @@ namespace dawn::native { return 1; } else if (aspects == (Aspect::Plane0 | Aspect::Plane1)) { return 2; + } else if (aspects == Aspect::Stencil) { + // Fake a the existence of a depth aspect so that the stencil data stays at index 1. + ASSERT(GetAspectIndex(Aspect::Stencil) == 1); + return 2; } else { ASSERT(aspects == (Aspect::Depth | Aspect::Stencil)); return 2; diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp index d7aa8c6145..e36c671703 100644 --- a/src/dawn/native/Toggles.cpp +++ b/src/dawn/native/Toggles.cpp @@ -99,6 +99,12 @@ namespace dawn::native { "backend will use D32S8 (toggle to on) but setting the toggle to off will make it " "use the D24S8 format when possible.", "https://crbug.com/dawn/286"}}, + {Toggle::VulkanUseS8, + {"vulkan_use_s8", + "Vulkan has a pure stencil8 format but it is not universally available. When this " + "toggle is on, the backend will use S8 for the stencil8 format, otherwise it will " + "fallback to D32S8 or D24S8.", + "https://crbug.com/dawn/666"}}, {Toggle::MetalDisableSamplerCompare, {"metal_disable_sampler_compare", "Disables the use of sampler compare on Metal. This is unsupported before A9 " diff --git a/src/dawn/native/Toggles.h b/src/dawn/native/Toggles.h index c4e5755cd6..87c32bf2b2 100644 --- a/src/dawn/native/Toggles.h +++ b/src/dawn/native/Toggles.h @@ -35,6 +35,7 @@ namespace dawn::native { UseD3D12ResidencyManagement, SkipValidation, VulkanUseD32S8, + VulkanUseS8, MetalDisableSamplerCompare, MetalUseSharedModeForCounterSampleBuffer, DisableBaseVertex, diff --git a/src/dawn/native/d3d12/CommandBufferD3D12.cpp b/src/dawn/native/d3d12/CommandBufferD3D12.cpp index d16c92ef7c..86022c72e2 100644 --- a/src/dawn/native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn/native/d3d12/CommandBufferD3D12.cpp @@ -1327,7 +1327,7 @@ namespace dawn::native::d3d12 { } } - if (renderPassBuilder->HasDepth()) { + if (renderPassBuilder->HasDepthOrStencil()) { D3D12_CLEAR_FLAGS clearFlags = {}; float depthClear = 0.0f; uint8_t stencilClear = 0u; @@ -1359,7 +1359,7 @@ namespace dawn::native::d3d12 { commandList->OMSetRenderTargets( static_cast(renderPassBuilder->GetHighestColorAttachmentIndexPlusOne()), renderPassBuilder->GetRenderTargetViews(), FALSE, - renderPassBuilder->HasDepth() + renderPassBuilder->HasDepthOrStencil() ? &renderPassBuilder->GetRenderPassDepthStencilDescriptor()->cpuDescriptor : nullptr); } @@ -1384,7 +1384,7 @@ namespace dawn::native::d3d12 { commandContext->GetCommandList4()->BeginRenderPass( static_cast(renderPassBuilder.GetHighestColorAttachmentIndexPlusOne()), renderPassBuilder.GetRenderPassRenderTargetDescriptors().data(), - renderPassBuilder.HasDepth() + renderPassBuilder.HasDepthOrStencil() ? renderPassBuilder.GetRenderPassDepthStencilDescriptor() : nullptr, renderPassBuilder.GetRenderPassFlags()); diff --git a/src/dawn/native/d3d12/RenderPassBuilderD3D12.cpp b/src/dawn/native/d3d12/RenderPassBuilderD3D12.cpp index 247850ee67..fc4133108b 100644 --- a/src/dawn/native/d3d12/RenderPassBuilderD3D12.cpp +++ b/src/dawn/native/d3d12/RenderPassBuilderD3D12.cpp @@ -136,8 +136,8 @@ namespace dawn::native::d3d12 { return mHighestColorAttachmentIndexPlusOne; } - bool RenderPassBuilder::HasDepth() const { - return mHasDepth; + bool RenderPassBuilder::HasDepthOrStencil() const { + return mHasDepthOrStencil; } ityp::span @@ -204,7 +204,7 @@ namespace dawn::native::d3d12 { wgpu::StoreOp storeOp, float clearDepth, DXGI_FORMAT format) { - mHasDepth = true; + mHasDepthOrStencil = true; mRenderPassDepthStencilDesc.DepthBeginningAccess.Type = D3D12BeginningAccessType(loadOp); if (loadOp == wgpu::LoadOp::Clear) { mRenderPassDepthStencilDesc.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth = @@ -218,6 +218,7 @@ namespace dawn::native::d3d12 { wgpu::StoreOp storeOp, uint8_t clearStencil, DXGI_FORMAT format) { + mHasDepthOrStencil = true; mRenderPassDepthStencilDesc.StencilBeginningAccess.Type = D3D12BeginningAccessType(loadOp); if (loadOp == wgpu::LoadOp::Clear) { mRenderPassDepthStencilDesc.StencilBeginningAccess.Clear.ClearValue.DepthStencil diff --git a/src/dawn/native/d3d12/RenderPassBuilderD3D12.h b/src/dawn/native/d3d12/RenderPassBuilderD3D12.h index cbbc29ba1f..5731c5268a 100644 --- a/src/dawn/native/d3d12/RenderPassBuilderD3D12.h +++ b/src/dawn/native/d3d12/RenderPassBuilderD3D12.h @@ -52,7 +52,7 @@ namespace dawn::native::d3d12 { // Returns attachment RTVs to use with OMSetRenderTargets. const D3D12_CPU_DESCRIPTOR_HANDLE* GetRenderTargetViews() const; - bool HasDepth() const; + bool HasDepthOrStencil() const; // Functions that set the appropriate values in the render pass descriptors. void SetDepthAccess(wgpu::LoadOp loadOp, @@ -83,7 +83,7 @@ namespace dawn::native::d3d12 { private: ColorAttachmentIndex mHighestColorAttachmentIndexPlusOne{uint8_t(0)}; - bool mHasDepth = false; + bool mHasDepthOrStencil = false; D3D12_RENDER_PASS_FLAGS mRenderPassFlags = D3D12_RENDER_PASS_FLAG_NONE; D3D12_RENDER_PASS_DEPTH_STENCIL_DESC mRenderPassDepthStencilDesc; ityp:: diff --git a/src/dawn/native/d3d12/RenderPipelineD3D12.cpp b/src/dawn/native/d3d12/RenderPipelineD3D12.cpp index 0e0e8f29b2..7168454e6c 100644 --- a/src/dawn/native/d3d12/RenderPipelineD3D12.cpp +++ b/src/dawn/native/d3d12/RenderPipelineD3D12.cpp @@ -279,7 +279,11 @@ namespace dawn::native::d3d12 { D3D12_DEPTH_STENCIL_DESC ComputeDepthStencilDesc(const DepthStencilState* descriptor) { D3D12_DEPTH_STENCIL_DESC mDepthStencilDescriptor; - mDepthStencilDescriptor.DepthEnable = TRUE; + mDepthStencilDescriptor.DepthEnable = + (descriptor->depthCompare == wgpu::CompareFunction::Always && + !descriptor->depthWriteEnabled) + ? FALSE + : TRUE; mDepthStencilDescriptor.DepthWriteMask = descriptor->depthWriteEnabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; diff --git a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp index 8c888f5e68..b16b0a2389 100644 --- a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp +++ b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp @@ -299,7 +299,8 @@ namespace dawn::native::d3d12 { // incorrectly allocate a mismatched size. if (resourceInfo.SizeInBytes == 0 || resourceInfo.SizeInBytes == std::numeric_limits::max()) { - return DAWN_OUT_OF_MEMORY_ERROR("Resource allocation size was invalid."); + return DAWN_OUT_OF_MEMORY_ERROR(absl::StrFormat( + "Resource allocation size (%u) was invalid.", resourceInfo.SizeInBytes)); } BuddyMemoryAllocator* allocator = diff --git a/src/dawn/native/d3d12/TextureD3D12.cpp b/src/dawn/native/d3d12/TextureD3D12.cpp index 95f9cb9b3d..ae79a1bb39 100644 --- a/src/dawn/native/d3d12/TextureD3D12.cpp +++ b/src/dawn/native/d3d12/TextureD3D12.cpp @@ -178,6 +178,8 @@ namespace dawn::native::d3d12 { case wgpu::TextureFormat::Depth24Plus: return DXGI_FORMAT_R32_TYPELESS; + // Depth24UnormStencil8 is the smallest format supported on D3D12 that has stencil. + case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Depth24UnormStencil8: return DXGI_FORMAT_R24G8_TYPELESS; case wgpu::TextureFormat::Depth24PlusStencil8: @@ -253,8 +255,6 @@ namespace dawn::native::d3d12 { case wgpu::TextureFormat::ASTC12x12UnormSrgb: case wgpu::TextureFormat::R8BG8Biplanar420Unorm: - // TODO(dawn:666): implement stencil8 - case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Undefined: UNREACHABLE(); } @@ -346,6 +346,8 @@ namespace dawn::native::d3d12 { case wgpu::TextureFormat::Depth32Float: case wgpu::TextureFormat::Depth24Plus: return DXGI_FORMAT_D32_FLOAT; + // Depth24UnormStencil8 is the smallest format supported on D3D12 that has stencil. + case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Depth24UnormStencil8: return DXGI_FORMAT_D24_UNORM_S8_UINT; case wgpu::TextureFormat::Depth24PlusStencil8: @@ -424,8 +426,6 @@ namespace dawn::native::d3d12 { case wgpu::TextureFormat::ASTC12x12Unorm: case wgpu::TextureFormat::ASTC12x12UnormSrgb: - // TODO(dawn:666): implement stencil8 - case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Undefined: UNREACHABLE(); } @@ -684,6 +684,7 @@ namespace dawn::native::d3d12 { case wgpu::TextureFormat::Depth24UnormStencil8: case wgpu::TextureFormat::Depth24PlusStencil8: case wgpu::TextureFormat::Depth32FloatStencil8: + case wgpu::TextureFormat::Stencil8: switch (aspect) { case Aspect::Depth: return DXGI_FORMAT_R32_FLOAT; @@ -1179,6 +1180,7 @@ namespace dawn::native::d3d12 { case wgpu::TextureFormat::Depth16Unorm: mSrvDesc.Format = DXGI_FORMAT_R16_UNORM; break; + case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Depth24UnormStencil8: switch (descriptor->aspect) { case wgpu::TextureAspect::DepthOnly: diff --git a/src/dawn/native/metal/ComputePipelineMTL.mm b/src/dawn/native/metal/ComputePipelineMTL.mm index a7663b6eb2..71d5a01cce 100644 --- a/src/dawn/native/metal/ComputePipelineMTL.mm +++ b/src/dawn/native/metal/ComputePipelineMTL.mm @@ -43,7 +43,7 @@ namespace dawn::native::metal { newComputePipelineStateWithFunction:computeData.function.Get() error:&error]); if (error != nullptr) { - return DAWN_INTERNAL_ERROR("Error creating pipeline state" + + return DAWN_INTERNAL_ERROR("Error creating pipeline state " + std::string([error.localizedDescription UTF8String])); } ASSERT(mMtlComputePipelineState != nil); diff --git a/src/dawn/native/metal/RenderPipelineMTL.mm b/src/dawn/native/metal/RenderPipelineMTL.mm index 6b7e0fecb7..18adb692de 100644 --- a/src/dawn/native/metal/RenderPipelineMTL.mm +++ b/src/dawn/native/metal/RenderPipelineMTL.mm @@ -391,7 +391,7 @@ namespace dawn::native::metal { AcquireNSPRef([mtlDevice newRenderPipelineStateWithDescriptor:descriptorMTL error:&error]); if (error != nullptr) { - return DAWN_INTERNAL_ERROR(std::string("Error creating pipeline state") + + return DAWN_INTERNAL_ERROR(std::string("Error creating pipeline state ") + [error.localizedDescription UTF8String]); } ASSERT(mMtlRenderPipelineState != nil); diff --git a/src/dawn/native/metal/TextureMTL.mm b/src/dawn/native/metal/TextureMTL.mm index 05473ab825..c47039fb27 100644 --- a/src/dawn/native/metal/TextureMTL.mm +++ b/src/dawn/native/metal/TextureMTL.mm @@ -289,6 +289,8 @@ namespace dawn::native::metal { // TODO (dawn:1181): Allow non-conformant implementation on macOS 10.11 UNREACHABLE(); } + case wgpu::TextureFormat::Stencil8: + return MTLPixelFormatStencil8; #if defined(DAWN_PLATFORM_MACOS) case wgpu::TextureFormat::Depth24UnormStencil8: @@ -383,8 +385,6 @@ namespace dawn::native::metal { case wgpu::TextureFormat::ASTC12x12Unorm: case wgpu::TextureFormat::ASTC12x12UnormSrgb: - // TODO(dawn:666): implement stencil8 - case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Undefined: UNREACHABLE(); } diff --git a/src/dawn/native/opengl/GLFormat.cpp b/src/dawn/native/opengl/GLFormat.cpp index 6f7e1dee19..36e40a97f0 100644 --- a/src/dawn/native/opengl/GLFormat.cpp +++ b/src/dawn/native/opengl/GLFormat.cpp @@ -95,6 +95,7 @@ namespace dawn::native::opengl { AddFormat(wgpu::TextureFormat::Depth24Plus, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, Type::DepthStencil); AddFormat(wgpu::TextureFormat::Depth24PlusStencil8, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, Type::DepthStencil); AddFormat(wgpu::TextureFormat::Depth16Unorm, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, Type::DepthStencil); + AddFormat(wgpu::TextureFormat::Stencil8, GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE, Type::DepthStencil); // Block compressed formats AddFormat(wgpu::TextureFormat::BC1RGBAUnorm, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); diff --git a/src/dawn/native/opengl/UtilsGL.cpp b/src/dawn/native/opengl/UtilsGL.cpp index ec94704398..616110eefd 100644 --- a/src/dawn/native/opengl/UtilsGL.cpp +++ b/src/dawn/native/opengl/UtilsGL.cpp @@ -46,6 +46,9 @@ namespace dawn::native::opengl { GLint GetStencilMaskFromStencilFormat(wgpu::TextureFormat depthStencilFormat) { switch (depthStencilFormat) { case wgpu::TextureFormat::Depth24PlusStencil8: + case wgpu::TextureFormat::Depth24UnormStencil8: + case wgpu::TextureFormat::Depth32FloatStencil8: + case wgpu::TextureFormat::Stencil8: return 0xFF; default: diff --git a/src/dawn/native/vulkan/AdapterVk.cpp b/src/dawn/native/vulkan/AdapterVk.cpp index 4437882295..5862bf899b 100644 --- a/src/dawn/native/vulkan/AdapterVk.cpp +++ b/src/dawn/native/vulkan/AdapterVk.cpp @@ -44,7 +44,7 @@ namespace dawn::native::vulkan { bool Adapter::IsDepthStencilFormatSupported(VkFormat format) { ASSERT(format == VK_FORMAT_D16_UNORM_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT || - format == VK_FORMAT_D32_SFLOAT_S8_UINT); + format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_S8_UINT); VkFormatProperties properties; mVulkanInstance->GetFunctions().GetPhysicalDeviceFormatProperties(mPhysicalDevice, format, diff --git a/src/dawn/native/vulkan/DeviceVk.cpp b/src/dawn/native/vulkan/DeviceVk.cpp index 6612dd64cc..7660f4c1bc 100644 --- a/src/dawn/native/vulkan/DeviceVk.cpp +++ b/src/dawn/native/vulkan/DeviceVk.cpp @@ -93,9 +93,9 @@ namespace dawn::native::vulkan { DAWN_TRY(PrepareRecordingContext()); - // The environment can request to use D32S8 or D24S8 when it's not available. Override - // the decision if it is not applicable. - ApplyDepth24PlusS8Toggle(); + // The environment can request to various options for depth-stencil formats that could be + // unavailable. Override the decision if it is not applicable. + ApplyDepthStencilFormatToggles(); // The environment can only request to use VK_KHR_zero_initialize_workgroup_memory when the // extension is available. Override the decision if it is no applicable. @@ -518,13 +518,17 @@ namespace dawn::native::vulkan { // By default try to initialize workgroup memory with OpConstantNull according to the Vulkan // extension VK_KHR_zero_initialize_workgroup_memory. SetToggle(Toggle::VulkanUseZeroInitializeWorkgroupMemoryExtension, true); + + // By default try to use S8 if available. + SetToggle(Toggle::VulkanUseS8, true); } - void Device::ApplyDepth24PlusS8Toggle() { + void Device::ApplyDepthStencilFormatToggles() { bool supportsD32s8 = ToBackend(GetAdapter())->IsDepthStencilFormatSupported(VK_FORMAT_D32_SFLOAT_S8_UINT); bool supportsD24s8 = ToBackend(GetAdapter())->IsDepthStencilFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT); + bool supportsS8 = ToBackend(GetAdapter())->IsDepthStencilFormatSupported(VK_FORMAT_S8_UINT); ASSERT(supportsD32s8 || supportsD24s8); @@ -534,6 +538,9 @@ namespace dawn::native::vulkan { if (!supportsD32s8) { ForceSetToggle(Toggle::VulkanUseD32S8, false); } + if (!supportsS8) { + ForceSetToggle(Toggle::VulkanUseS8, false); + } } void Device::ApplyUseZeroInitializeWorkgroupMemoryExtensionToggle() { diff --git a/src/dawn/native/vulkan/DeviceVk.h b/src/dawn/native/vulkan/DeviceVk.h index 3159629374..55697efeec 100644 --- a/src/dawn/native/vulkan/DeviceVk.h +++ b/src/dawn/native/vulkan/DeviceVk.h @@ -151,7 +151,7 @@ namespace dawn::native::vulkan { uint32_t FindComputeSubgroupSize() const; void InitTogglesFromDriver(); - void ApplyDepth24PlusS8Toggle(); + void ApplyDepthStencilFormatToggles(); void ApplyUseZeroInitializeWorkgroupMemoryExtensionToggle(); void DestroyImpl() override; diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp index 4a47a4c7f1..e96f8a000a 100644 --- a/src/dawn/native/vulkan/TextureVk.cpp +++ b/src/dawn/native/vulkan/TextureVk.cpp @@ -318,6 +318,14 @@ namespace dawn::native::vulkan { return VK_FORMAT_D24_UNORM_S8_UINT; case wgpu::TextureFormat::Depth32FloatStencil8: return VK_FORMAT_D32_SFLOAT_S8_UINT; + case wgpu::TextureFormat::Stencil8: + // Try to use the stencil8 format if possible, otherwise use whatever format we can + // use that contains a stencil8 component. + if (device->IsToggleEnabled(Toggle::VulkanUseS8)) { + return VK_FORMAT_S8_UINT; + } else { + return VulkanImageFormat(device, wgpu::TextureFormat::Depth24PlusStencil8); + } case wgpu::TextureFormat::BC1RGBAUnorm: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; @@ -429,8 +437,6 @@ namespace dawn::native::vulkan { case wgpu::TextureFormat::R8BG8Biplanar420Unorm: return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; - // TODO(dawn:666): implement stencil8 - case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Undefined: break; } @@ -982,6 +988,12 @@ namespace dawn::native::vulkan { // single plane in a new SubresourceStorage. The barriers will be produced // for DEPTH | STENCIL since the SubresourceRange uses Aspect::CombinedDepthStencil. bool Texture::ShouldCombineDepthStencilBarriers() const { + // If the Stencil8 format is being emulated then memory barriers also need to include + // the depth aspect. (See: crbug.com/dawn/1331) + if (GetFormat().format == wgpu::TextureFormat::Stencil8 && + !GetDevice()->IsToggleEnabled(Toggle::VulkanUseS8)) { + return true; + } return GetFormat().aspects == (Aspect::Depth | Aspect::Stencil); } diff --git a/src/dawn/tests/end2end/DepthStencilCopyTests.cpp b/src/dawn/tests/end2end/DepthStencilCopyTests.cpp index f037555966..a74359ea87 100644 --- a/src/dawn/tests/end2end/DepthStencilCopyTests.cpp +++ b/src/dawn/tests/end2end/DepthStencilCopyTests.cpp @@ -126,53 +126,6 @@ class DepthStencilCopyTests : public DawnTestWithParamsvertex.module = mVertexModule; - - std::string fsSource = R"( - @stage(fragment) fn main() -> @builtin(frag_depth) f32 { - return )" + std::to_string(regionDepth) + - ";\n}"; - - desc->cFragment.module = utils::CreateShaderModule(device, fsSource.c_str()); - wgpu::DepthStencilState* depthStencil = desc->EnableDepthStencil(format); - depthStencil->depthWriteEnabled = true; - desc->cFragment.targetCount = 0; - } - - // Initialize the depth/stencil values for the texture using a render pass. - // The texture will be cleared to the "clear" value, and then bottom left corner will - // be written with the "region" value. - void InitializeDepthTextureRegion(wgpu::Texture texture, - wgpu::TextureFormat depthFormat, - float clearDepth, - float regionDepth, - uint32_t mipLevel = 0) { - wgpu::TextureViewDescriptor viewDesc = {}; - viewDesc.baseMipLevel = mipLevel; - viewDesc.mipLevelCount = 1; - - utils::ComboRenderPassDescriptor renderPassDesc({}, texture.CreateView(&viewDesc)); - renderPassDesc.UnsetDepthStencilLoadStoreOpsForFormat(depthFormat); - renderPassDesc.cDepthStencilAttachmentInfo.depthClearValue = clearDepth; - - utils::ComboRenderPipelineDescriptor renderPipelineDesc; - PopulatePipelineDescriptorWriteDepth(&renderPipelineDesc, GetParam().mTextureFormat, - regionDepth); - - wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc); - wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); - wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPassDesc); - pass.SetPipeline(pipeline); - pass.Draw(6); - pass.End(); - - wgpu::CommandBuffer commands = commandEncoder.Finish(); - queue.Submit(1, &commands); - } - // Initialize the depth/stencil values for the texture using a render pass. // The texture will be cleared to the "clear" values, and then bottom left corner will // be written with the "region" values. @@ -182,21 +135,43 @@ class DepthStencilCopyTests : public DawnTestWithParamsdepthCompare = wgpu::CompareFunction::Always; + renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"( + @stage(fragment) fn main() {} + )"); + } else { + depthStencil->depthWriteEnabled = true; + renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, std::string(R"( + @stage(fragment) fn main() -> @builtin(frag_depth) f32 { + return )" + std::to_string(regionDepth) + R"(; + })") + .c_str()); + } + if (!utils::IsDepthOnlyFormat(format)) { + depthStencil->stencilFront.passOp = wgpu::StencilOperation::Replace; + } + + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc); + + // Build the render pass used for initialization. wgpu::TextureViewDescriptor viewDesc = {}; viewDesc.baseMipLevel = mipLevel; viewDesc.mipLevelCount = 1; utils::ComboRenderPassDescriptor renderPassDesc({}, texture.CreateView(&viewDesc)); + renderPassDesc.UnsetDepthStencilLoadStoreOpsForFormat(format); renderPassDesc.cDepthStencilAttachmentInfo.depthClearValue = clearDepth; renderPassDesc.cDepthStencilAttachmentInfo.stencilClearValue = clearStencil; - utils::ComboRenderPipelineDescriptor renderPipelineDesc; - PopulatePipelineDescriptorWriteDepth(&renderPipelineDesc, GetParam().mTextureFormat, - regionDepth); - renderPipelineDesc.cDepthStencil.stencilFront.passOp = wgpu::StencilOperation::Replace; - - wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc); - // Draw the quad (two triangles) wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPassDesc); @@ -471,7 +446,7 @@ TEST_P(DepthCopyTests, FromDepthAspect) { kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc); constexpr float kInitDepth = 0.2f; - InitializeDepthTextureRegion(texture, GetParam().mTextureFormat, 0.f, kInitDepth); + InitializeDepthStencilTextureRegion(texture, 0.f, kInitDepth, 0, 0); // This expectation is the test as it performs the CopyTextureToBuffer. if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) { @@ -511,7 +486,7 @@ TEST_P(DepthCopyTests, FromNonZeroMipDepthAspect) { 9, 9, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, 2); constexpr float kInitDepth = 0.4f; - InitializeDepthTextureRegion(depthTexture, GetParam().mTextureFormat, 0.f, kInitDepth, 1); + InitializeDepthStencilTextureRegion(depthTexture, 0.f, kInitDepth, 0, 0, /*mipLevel*/ 1); // This expectation is the test as it performs the CopyTextureToBuffer. if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) { @@ -670,17 +645,19 @@ TEST_P(StencilCopyTests, ToStencilAspect) { // Create a stencil texture constexpr uint32_t kWidth = 4; constexpr uint32_t kHeight = 4; + const bool hasDepth = !utils::IsStencilOnlyFormat(GetParam().mTextureFormat); wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst); - { + if (hasDepth) { wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); // Clear depth to 0.7, so we can check that the stencil copy doesn't mutate the depth. utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView()); + passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat); passDescriptor.cDepthStencilAttachmentInfo.depthClearValue = 0.7; wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor); @@ -727,10 +704,14 @@ TEST_P(StencilCopyTests, ToStencilAspect) { renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"( @stage(fragment) fn main() { })"); + renderPipelineDesc.cFragment.targetCount = 0; wgpu::DepthStencilState* depthStencil = renderPipelineDesc.EnableDepthStencil(GetParam().mTextureFormat); depthStencil->stencilFront.passOp = wgpu::StencilOperation::DecrementClamp; - renderPipelineDesc.cFragment.targetCount = 0; + if (!hasDepth) { + depthStencil->depthWriteEnabled = false; + depthStencil->depthCompare = wgpu::CompareFunction::Always; + } wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc); @@ -739,6 +720,7 @@ TEST_P(StencilCopyTests, ToStencilAspect) { utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView()); passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load; passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load; + passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat); // Draw the quad in the bottom left (two triangles). wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor); @@ -754,19 +736,23 @@ TEST_P(StencilCopyTests, ToStencilAspect) { EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0, wgpu::TextureAspect::StencilOnly); - ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth, kHeight, - 0, 0, - { - 0.7, 0.7, 0.7, 0.7, // - 0.7, 0.7, 0.7, 0.7, // - 0.7, 0.7, 0.7, 0.7, // - 0.7, 0.7, 0.7, 0.7, // - }); + if (hasDepth) { + ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth, + kHeight, 0, 0, + { + 0.7, 0.7, 0.7, 0.7, // + 0.7, 0.7, 0.7, 0.7, // + 0.7, 0.7, 0.7, 0.7, // + 0.7, 0.7, 0.7, 0.7, // + }); + } } DAWN_INSTANTIATE_TEST_P(DepthStencilCopyTests, {D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(), - VulkanBackend()}, + // Test with the vulkan_use_s8 toggle forced on and off. + VulkanBackend({"vulkan_use_s8"}, {}), + VulkanBackend({}, {"vulkan_use_s8"})}, std::vector(utils::kDepthAndStencilFormats.begin(), utils::kDepthAndStencilFormats.end())); @@ -784,6 +770,8 @@ DAWN_INSTANTIATE_TEST_P(DepthCopyFromBufferTests, DAWN_INSTANTIATE_TEST_P(StencilCopyTests, {D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(), - VulkanBackend()}, + // Test with the vulkan_use_s8 toggle forced on and off. + VulkanBackend({"vulkan_use_s8"}, {}), + VulkanBackend({}, {"vulkan_use_s8"})}, std::vector(utils::kStencilFormats.begin(), utils::kStencilFormats.end())); diff --git a/src/dawn/utils/TextureUtils.cpp b/src/dawn/utils/TextureUtils.cpp index 8fbd8df958..312c1dbdae 100644 --- a/src/dawn/utils/TextureUtils.cpp +++ b/src/dawn/utils/TextureUtils.cpp @@ -215,12 +215,17 @@ namespace utils { } } + bool IsStencilOnlyFormat(wgpu::TextureFormat textureFormat) { + return textureFormat == wgpu::TextureFormat::Stencil8; + } + uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat) { switch (textureFormat) { case wgpu::TextureFormat::R8Unorm: case wgpu::TextureFormat::R8Snorm: case wgpu::TextureFormat::R8Uint: case wgpu::TextureFormat::R8Sint: + case wgpu::TextureFormat::Stencil8: return 1u; case wgpu::TextureFormat::R16Uint: @@ -339,8 +344,6 @@ namespace utils { // Block size of a multi-planar format depends on aspect. case wgpu::TextureFormat::R8BG8Biplanar420Unorm: - // TODO(dawn:666): implement stencil8 - case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Undefined: break; } @@ -391,6 +394,7 @@ namespace utils { case wgpu::TextureFormat::Depth16Unorm: case wgpu::TextureFormat::Depth24UnormStencil8: case wgpu::TextureFormat::Depth32FloatStencil8: + case wgpu::TextureFormat::Stencil8: return 1u; case wgpu::TextureFormat::BC1RGBAUnorm: @@ -457,8 +461,6 @@ namespace utils { // Block size of a multi-planar format depends on aspect. case wgpu::TextureFormat::R8BG8Biplanar420Unorm: - // TODO(dawn:666): implement stencil8 - case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Undefined: break; } @@ -509,6 +511,7 @@ namespace utils { case wgpu::TextureFormat::Depth16Unorm: case wgpu::TextureFormat::Depth24UnormStencil8: case wgpu::TextureFormat::Depth32FloatStencil8: + case wgpu::TextureFormat::Stencil8: return 1u; case wgpu::TextureFormat::BC1RGBAUnorm: @@ -575,8 +578,6 @@ namespace utils { // Block size of a multi-planar format depends on aspect. case wgpu::TextureFormat::R8BG8Biplanar420Unorm: - // TODO(dawn:666): implement stencil8 - case wgpu::TextureFormat::Stencil8: case wgpu::TextureFormat::Undefined: break; } diff --git a/src/dawn/utils/TextureUtils.h b/src/dawn/utils/TextureUtils.h index 8472bc9de6..f9dab08eac 100644 --- a/src/dawn/utils/TextureUtils.h +++ b/src/dawn/utils/TextureUtils.h @@ -22,8 +22,7 @@ #include "dawn/common/Assert.h" namespace utils { - // TODO(dawn:666): Add Stencil8 format when it's implemented. - static constexpr std::array kAllTextureFormats = { + static constexpr std::array kAllTextureFormats = { wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R8Snorm, wgpu::TextureFormat::R8Uint, @@ -66,6 +65,7 @@ namespace utils { wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureFormat::Depth24UnormStencil8, wgpu::TextureFormat::Depth32FloatStencil8, + wgpu::TextureFormat::Stencil8, wgpu::TextureFormat::BC1RGBAUnorm, wgpu::TextureFormat::BC1RGBAUnormSrgb, wgpu::TextureFormat::BC2RGBAUnorm, @@ -206,16 +206,16 @@ namespace utils { kBCFormats.size() + kETC2Formats.size() + kASTCFormats.size(), "Number of compressed format must equal number of BC, ETC2, and ASTC formats."); - // TODO(dawn:666): Add Stencil8 format when it's implemented. static constexpr std::array kDepthFormats = { wgpu::TextureFormat::Depth16Unorm, wgpu::TextureFormat::Depth32Float, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureFormat::Depth24UnormStencil8, wgpu::TextureFormat::Depth32FloatStencil8, }; - static constexpr std::array kStencilFormats = { + static constexpr std::array kStencilFormats = { wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureFormat::Depth24UnormStencil8, wgpu::TextureFormat::Depth32FloatStencil8, + wgpu::TextureFormat::Stencil8, }; static constexpr std::array kDepthAndStencilFormats = { wgpu::TextureFormat::Depth24PlusStencil8, @@ -230,6 +230,7 @@ namespace utils { bool IsASTCTextureFormat(wgpu::TextureFormat textureFormat); bool IsDepthOnlyFormat(wgpu::TextureFormat textureFormat); + bool IsStencilOnlyFormat(wgpu::TextureFormat textureFormat); bool TextureFormatSupportsMultisampling(wgpu::TextureFormat textureFormat); bool TextureFormatSupportsResolveTarget(wgpu::TextureFormat textureFormat);