From f952a392dedc7c5f466b5873f9c673bc3f765397 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 19 Jun 2023 13:46:37 +0200 Subject: [PATCH] Add **stencil buffer** support to `GPUPipelineState` --- Source/Engine/Graphics/GPUDevice.cpp | 141 ++++++++---------- Source/Engine/Graphics/GPUPipelineState.h | 60 ++++++++ .../DirectX/DX12/GPUPipelineStateDX12.cpp | 39 ++++- .../Vulkan/DescriptorSetVulkan.h | 49 ------ .../Vulkan/GPUPipelineStateVulkan.cpp | 33 ++++ 5 files changed, 188 insertions(+), 134 deletions(-) diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index acc1f4525..019cfad5a 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -90,96 +90,79 @@ GPUResourceType GPUPipelineState::GetResourceType() const return GPUResourceType::PipelineState; } +// @formatter:off GPUPipelineState::Description GPUPipelineState::Description::Default = { - // Enable/disable depth write - true, - // Enable/disable depth test - true, - // DepthClipEnable - true, - // DepthFunc - ComparisonFunc::Less, - // Vertex shader - nullptr, - // Hull shader - nullptr, - // Domain shader - nullptr, - // Geometry shader - nullptr, - // Pixel shader - nullptr, - // Primitives topology - PrimitiveTopologyType::Triangle, - // True if use wireframe rendering - false, - // Primitives culling mode - CullMode::Normal, - // Colors blending mode - BlendingMode::Opaque, + true, // DepthEnable + true, // DepthWriteEnable + true, // DepthClipEnable + ComparisonFunc::Less, // DepthFunc + false, // StencilEnable + 0xff, // StencilReadMask + 0xff, // StencilWriteMask + ComparisonFunc::Always, // StencilFunc + StencilOperation::Keep, // StencilFailOp + StencilOperation::Keep, // StencilDepthFailOp + StencilOperation::Keep, // StencilPassOp + nullptr, // VS + nullptr, // HS + nullptr, // DS + nullptr, // GS + nullptr, // PS + PrimitiveTopologyType::Triangle, // PrimitiveTopology + false, // Wireframe + CullMode::Normal, // CullMode + BlendingMode::Opaque, // BlendMode }; GPUPipelineState::Description GPUPipelineState::Description::DefaultNoDepth = { - // Enable/disable depth write - false, - // Enable/disable depth test - false, - // DepthClipEnable - false, - // DepthFunc - ComparisonFunc::Less, - // Vertex shader - nullptr, - // Hull shader - nullptr, - // Domain shader - nullptr, - // Geometry shader - nullptr, - // Pixel shader - nullptr, - // Primitives topology - PrimitiveTopologyType::Triangle, - // True if use wireframe rendering - false, - // Primitives culling mode - CullMode::Normal, - // Colors blending mode - BlendingMode::Opaque, + false, // DepthEnable + false, // DepthWriteEnable + false, // DepthClipEnable + ComparisonFunc::Less, // DepthFunc + false, // StencilEnable + 0xff, // StencilReadMask + 0xff, // StencilWriteMask + ComparisonFunc::Always, // StencilFunc + StencilOperation::Keep, // StencilFailOp + StencilOperation::Keep, // StencilDepthFailOp + StencilOperation::Keep, // StencilPassOp + nullptr, // VS + nullptr, // HS + nullptr, // DS + nullptr, // GS + nullptr, // PS + PrimitiveTopologyType::Triangle, // PrimitiveTopology + false, // Wireframe + CullMode::Normal, // CullMode + BlendingMode::Opaque, // BlendMode }; GPUPipelineState::Description GPUPipelineState::Description::DefaultFullscreenTriangle = { - // Enable/disable depth write - false, - // Enable/disable depth test - false, - // DepthClipEnable - false, - // DepthFunc - ComparisonFunc::Less, - // Vertex shader - nullptr, - // Set to default quad VS via GPUDevice - // Hull shader - nullptr, - // Domain shader - nullptr, - // Geometry shader - nullptr, - // Pixel shader - nullptr, - // Primitives topology - PrimitiveTopologyType::Triangle, - // True if use wireframe rendering - false, - // Primitives culling mode - CullMode::TwoSided, - // Colors blending mode - BlendingMode::Opaque, + false, // DepthEnable + false, // DepthWriteEnable + false, // DepthClipEnable + ComparisonFunc::Less, // DepthFunc + false, // StencilEnable + 0xff, // StencilReadMask + 0xff, // StencilWriteMask + ComparisonFunc::Always, // StencilFunc + StencilOperation::Keep, // StencilFailOp + StencilOperation::Keep, // StencilDepthFailOp + StencilOperation::Keep, // StencilPassOp + nullptr, // VS (Set to default quad VS via GPUDevice) + nullptr, // HS + nullptr, // DS + nullptr, // GS + nullptr, // PS + PrimitiveTopologyType::Triangle, // PrimitiveTopology + false, // Wireframe + CullMode::TwoSided, // CullMode + BlendingMode::Opaque, // BlendMode }; +// @formatter:on GPUResource::GPUResource() : ScriptingObject(SpawnParams(Guid::New(), TypeInitializer)) diff --git a/Source/Engine/Graphics/GPUPipelineState.h b/Source/Engine/Graphics/GPUPipelineState.h index b9b6395e4..880817d8c 100644 --- a/Source/Engine/Graphics/GPUPipelineState.h +++ b/Source/Engine/Graphics/GPUPipelineState.h @@ -7,6 +7,31 @@ #include "Enums.h" #include "GPUResource.h" +/// +/// Stencil operation modes. +/// +API_ENUM() enum class StencilOperation : byte +{ + // Keep the existing stencil data. + Keep, + // Set the stencil data to 0. + Zero, + // Set the stencil data to the reference value (set via GPUContext::SetStencilRef). + Replace, + // Increment the stencil value by 1, and clamp the result. + IncrementSaturated, + // Decrement the stencil value by 1, and clamp the result. + DecrementSaturated, + // Invert the stencil data. + Invert, + // Increment the stencil value by 1, and wrap the result if necessary. + Increment, + // Decrement the stencil value by 1, and wrap the result if necessary. + Decrement, + + API_ENUM(Attributes="HideInEditor") MAX +}; + /// /// Describes full graphics pipeline state within single object. /// @@ -44,6 +69,41 @@ public: /// API_FIELD() ComparisonFunc DepthFunc; + /// + /// Enable/disable stencil buffer usage + /// + API_FIELD() bool StencilEnable; + + /// + /// The read mask applied to the reference value and each stencil buffer entry to determine the significant bits for the stencil test. + /// + API_FIELD() uint8 StencilReadMask; + + /// + /// The write mask applied to values written into the stencil buffer. + /// + API_FIELD() uint8 StencilWriteMask; + + /// + /// The comparison function for the stencil test. + /// + API_FIELD() ComparisonFunc StencilFunc; + + /// + /// The stencil operation to perform when stencil testing fails. + /// + API_FIELD() StencilOperation StencilFailOp; + + /// + /// The stencil operation to perform when stencil testing passes and depth testing fails. + /// + API_FIELD() StencilOperation StencilDepthFailOp; + + /// + /// The stencil operation to perform when stencil testing and depth testing both pass. + /// + API_FIELD() StencilOperation StencilPassOp; + /// /// Vertex shader program /// diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp index b23d4d2fe..79f1895dc 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp @@ -9,6 +9,31 @@ #include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h" #include "Engine/Graphics/PixelFormatExtensions.h" +static D3D12_STENCIL_OP ToStencilOp(StencilOperation value) +{ + switch (value) + { + case StencilOperation::Keep: + return D3D12_STENCIL_OP_KEEP; + case StencilOperation::Zero: + return D3D12_STENCIL_OP_ZERO; + case StencilOperation::Replace: + return D3D12_STENCIL_OP_REPLACE; + case StencilOperation::IncrementSaturated: + return D3D12_STENCIL_OP_INCR_SAT; + case StencilOperation::DecrementSaturated: + return D3D12_STENCIL_OP_DECR_SAT; + case StencilOperation::Invert: + return D3D12_STENCIL_OP_INVERT; + case StencilOperation::Increment: + return D3D12_STENCIL_OP_INCR; + case StencilOperation::Decrement: + return D3D12_STENCIL_OP_DECR; + default: + return D3D12_STENCIL_OP_KEEP; + }; +} + GPUPipelineStateDX12::GPUPipelineStateDX12(GPUDeviceDX12* device) : GPUResourceDX12(device, StringView::Empty) , _states(16) @@ -169,12 +194,14 @@ bool GPUPipelineStateDX12::Init(const Description& desc) psDesc.DepthStencilState.DepthEnable = !!desc.DepthEnable; psDesc.DepthStencilState.DepthWriteMask = desc.DepthWriteEnable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; psDesc.DepthStencilState.DepthFunc = static_cast(desc.DepthFunc); - psDesc.DepthStencilState.StencilEnable = FALSE; - psDesc.DepthStencilState.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; - psDesc.DepthStencilState.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; - const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS }; - psDesc.DepthStencilState.FrontFace = defaultStencilOp; - psDesc.DepthStencilState.BackFace = defaultStencilOp; + psDesc.DepthStencilState.StencilEnable = !!desc.StencilEnable; + psDesc.DepthStencilState.StencilReadMask = desc.StencilReadMask; + psDesc.DepthStencilState.StencilWriteMask = desc.StencilWriteMask; + psDesc.DepthStencilState.FrontFace.StencilFailOp = ToStencilOp(desc.StencilFailOp); + psDesc.DepthStencilState.FrontFace.StencilDepthFailOp = ToStencilOp(desc.StencilDepthFailOp); + psDesc.DepthStencilState.FrontFace.StencilPassOp = ToStencilOp(desc.StencilPassOp); + psDesc.DepthStencilState.FrontFace.StencilFunc = static_cast(desc.StencilFunc); + psDesc.DepthStencilState.BackFace = psDesc.DepthStencilState.FrontFace; // Rasterizer State psDesc.RasterizerState.FillMode = desc.Wireframe ? D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID; diff --git a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h index a3aff7b60..d8d80b51e 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h @@ -26,71 +26,22 @@ namespace DescriptorSet { // Vertex shader stage Vertex = 0, - // Pixel shader stage Pixel = 1, - // Geometry shader stage Geometry = 2, - // Hull shader stage Hull = 3, - // Domain shader stage Domain = 4, - // Graphics pipeline stages count GraphicsStagesCount = 5, - // Compute pipeline slot Compute = 0, - // The maximum amount of slots for all stages Max = 5, }; - inline Stage GetSetForFrequency(ShaderStage stage) - { - switch (stage) - { - case ShaderStage::Vertex: - return Vertex; - case ShaderStage::Hull: - return Hull; - case ShaderStage::Domain: - return Domain; - case ShaderStage::Pixel: - return Pixel; - case ShaderStage::Geometry: - return Geometry; - case ShaderStage::Compute: - return Compute; - default: - CRASH; - return Max; - } - } - - inline ShaderStage GetFrequencyForGfxSet(Stage stage) - { - switch (stage) - { - case Vertex: - return ShaderStage::Vertex; - case Hull: - return ShaderStage::Hull; - case Domain: - return ShaderStage::Domain; - case Pixel: - return ShaderStage::Pixel; - case Geometry: - return ShaderStage::Geometry; - default: - CRASH; - return (ShaderStage)ShaderStage_Count; - } - } - template inline bool CopyAndReturnNotEqual(T& a, T b) { diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp index 5946aee20..136a7c6e5 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp @@ -9,6 +9,31 @@ #include "Engine/Core/Log.h" #include "Engine/Profiler/ProfilerCPU.h" +static VkStencilOp ToVulkanStencilOp(const StencilOperation value) +{ + switch (value) + { + case StencilOperation::Keep: + return VK_STENCIL_OP_KEEP; + case StencilOperation::Zero: + return VK_STENCIL_OP_ZERO; + case StencilOperation::Replace: + return VK_STENCIL_OP_REPLACE; + case StencilOperation::IncrementSaturated: + return VK_STENCIL_OP_INCREMENT_AND_CLAMP; + case StencilOperation::DecrementSaturated: + return VK_STENCIL_OP_DECREMENT_AND_CLAMP; + case StencilOperation::Invert: + return VK_STENCIL_OP_INVERT; + case StencilOperation::Increment: + return VK_STENCIL_OP_INCREMENT_AND_WRAP; + case StencilOperation::Decrement: + return VK_STENCIL_OP_DECREMENT_AND_WRAP; + default: + return VK_STENCIL_OP_KEEP; + } +} + GPUShaderProgramCSVulkan::~GPUShaderProgramCSVulkan() { if (_pipelineState) @@ -289,6 +314,14 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) _descDepthStencil.depthTestEnable = desc.DepthEnable; _descDepthStencil.depthWriteEnable = desc.DepthWriteEnable; _descDepthStencil.depthCompareOp = RenderToolsVulkan::ToVulkanCompareOp(desc.DepthFunc); + _descDepthStencil.stencilTestEnable = desc.StencilEnable; + _descDepthStencil.front.compareMask = desc.StencilReadMask; + _descDepthStencil.front.writeMask = desc.StencilWriteMask; + _descDepthStencil.front.compareOp = RenderToolsVulkan::ToVulkanCompareOp(desc.StencilFunc); + _descDepthStencil.front.failOp = ToVulkanStencilOp(desc.StencilFailOp); + _descDepthStencil.front.depthFailOp = ToVulkanStencilOp(desc.StencilDepthFailOp); + _descDepthStencil.front.passOp = ToVulkanStencilOp(desc.StencilPassOp); + _descDepthStencil.front = _descDepthStencil.back; _desc.pDepthStencilState = &_descDepthStencil; // Rasterization