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