summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngine
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-10-18 20:06:48 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-10-18 20:06:48 +0000
commit645ef7e425d6ff4ee64b782d27767e0a5732be50 (patch)
tree8502aea9ba6100af3a0908c5975a75debc5fd7de /Graphics/GraphicsEngine
parentRefactored LinearAllocator (diff)
downloadDiligentCore-645ef7e425d6ff4ee64b782d27767e0a5732be50.tar.gz
DiligentCore-645ef7e425d6ff4ee64b782d27767e0a5732be50.zip
A number of fixes for PSO creation refactoring (API240075)
Diffstat (limited to 'Graphics/GraphicsEngine')
-rw-r--r--Graphics/GraphicsEngine/CMakeLists.txt1
-rw-r--r--Graphics/GraphicsEngine/include/DeviceContextBase.hpp8
-rw-r--r--Graphics/GraphicsEngine/include/PipelineStateBase.hpp450
-rw-r--r--Graphics/GraphicsEngine/interface/APIInfo.h119
-rw-r--r--Graphics/GraphicsEngine/interface/PipelineState.h10
-rw-r--r--Graphics/GraphicsEngine/interface/RenderDevice.h4
-rw-r--r--Graphics/GraphicsEngine/src/APIInfo.cpp2
-rw-r--r--Graphics/GraphicsEngine/src/PipelineStateBase.cpp260
8 files changed, 494 insertions, 360 deletions
diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt
index b99138ca..d95257fe 100644
--- a/Graphics/GraphicsEngine/CMakeLists.txt
+++ b/Graphics/GraphicsEngine/CMakeLists.txt
@@ -66,6 +66,7 @@ set(SOURCE
src/DefaultShaderSourceStreamFactory.cpp
src/EngineMemory.cpp
src/FramebufferBase.cpp
+ src/PipelineStateBase.cpp
src/ResourceMappingBase.cpp
src/RenderPassBase.cpp
src/TextureBase.cpp
diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
index 90285834..4eebd683 100644
--- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
+++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
@@ -1664,6 +1664,13 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
return;
}
+ const auto& PSODesc = m_pPipelineState->GetDesc();
+ if (!PSODesc.IsAnyGraphicsPipeline())
+ {
+ LOG_ERROR_MESSAGE("Pipeline state '", PSODesc.Name, "' is not a graphics pipeline");
+ return;
+ }
+
TEXTURE_FORMAT BoundRTVFormats[8] = {TEX_FORMAT_UNKNOWN};
TEXTURE_FORMAT BoundDSVFormat = TEX_FORMAT_UNKNOWN;
@@ -1677,7 +1684,6 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
BoundDSVFormat = m_pBoundDepthStencil ? m_pBoundDepthStencil->GetDesc().Format : TEX_FORMAT_UNKNOWN;
- const auto& PSODesc = m_pPipelineState->GetDesc();
const auto& GraphicsPipeline = m_pPipelineState->GetGraphicsPipelineDesc();
if (GraphicsPipeline.NumRenderTargets != m_NumBoundRenderTargets)
{
diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
index ef5b38c2..cda2247e 100644
--- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
+++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
@@ -43,6 +43,11 @@
namespace Diligent
{
+void ValidateGraphicsPipelineCreateInfo(const GraphicsPipelineStateCreateInfo& CreateInfo) noexcept(false);
+void ValidateComputePipelineCreateInfo(const ComputePipelineStateCreateInfo& CreateInfo) noexcept(false);
+
+void CorrectGraphicsPipelineDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept;
+
/// Template class implementing base functionality for a pipeline state object.
/// \tparam BaseInterface - base interface that this class will inheret
@@ -57,10 +62,10 @@ class PipelineStateBase : public DeviceObjectBase<BaseInterface, RenderDeviceImp
public:
using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, PipelineStateDesc>;
- /// \param pRefCounters - reference counters object that controls the lifetime of this PSO
- /// \param pDevice - pointer to the device.
- /// \param CreateInfo - graphics pipeline state create info.
- /// \param bIsDeviceInternal - flag indicating if the pipeline state is an internal device object and
+ /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO
+ /// \param pDevice - Pointer to the device.
+ /// \param CreateInfo - Pipeline state create info.
+ /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and
/// must not keep a strong reference to the device.
PipelineStateBase(IReferenceCounters* pRefCounters,
RenderDeviceImplType* pDevice,
@@ -75,6 +80,35 @@ public:
this->m_Desc.CommandQueueMask &= DeviceQueuesMask;
}
+ /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO
+ /// \param pDevice - Pointer to the device.
+ /// \param GraphicsPipelineCI - Graphics pipeline create information.
+ /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and
+ /// must not keep a strong reference to the device.
+ PipelineStateBase(IReferenceCounters* pRefCounters,
+ RenderDeviceImplType* pDevice,
+ const GraphicsPipelineStateCreateInfo& GraphicsPipelineCI,
+ bool bIsDeviceInternal = false) :
+ PipelineStateBase{pRefCounters, pDevice, GraphicsPipelineCI.PSODesc, bIsDeviceInternal}
+ {
+ ValidateGraphicsPipelineCreateInfo(GraphicsPipelineCI);
+ }
+
+ /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO
+ /// \param pDevice - Pointer to the device.
+ /// \param ComputePipelineCI - Compute pipeline create information.
+ /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and
+ /// must not keep a strong reference to the device.
+ PipelineStateBase(IReferenceCounters* pRefCounters,
+ RenderDeviceImplType* pDevice,
+ const ComputePipelineStateCreateInfo& ComputePipelineCI,
+ bool bIsDeviceInternal = false) :
+ PipelineStateBase{pRefCounters, pDevice, ComputePipelineCI.PSODesc, bIsDeviceInternal}
+ {
+ ValidateComputePipelineCreateInfo(ComputePipelineCI);
+ }
+
+
~PipelineStateBase()
{
/*
@@ -125,25 +159,7 @@ public:
return *m_pGraphicsPipelineDesc;
}
-
-protected:
- size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout
-
- Uint32* m_pStrides = nullptr;
- Uint8 m_BufferSlotsUsed = 0;
-
- Uint8 m_NumShaderStages = 0; ///< Number of shader stages in this PSO
-
- /// Array of shader types for every shader stage used by this PSO
- std::array<SHADER_TYPE, MAX_SHADERS_IN_PIPELINE> m_ShaderStageTypes = {};
-
- RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object
-
- GraphicsPipelineDesc* m_pGraphicsPipelineDesc = nullptr;
-
protected:
-#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ", GetPipelineTypeString(this->m_Desc.PipelineType), " PSO '", this->m_Desc.Name, "' is invalid: ", ##__VA_ARGS__)
-
Int8 GetStaticVariableCountHelper(SHADER_TYPE ShaderType, const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& ResourceLayoutIndex) const
{
if (!IsConsistentShaderType(ShaderType, this->m_Desc.PipelineType))
@@ -204,239 +220,31 @@ protected:
return LayoutInd;
}
-private:
- void CheckRasterizerStateDesc(GraphicsPipelineDesc& GraphicsPipeline) const
- {
- const auto& RSDesc = GraphicsPipeline.RasterizerDesc;
- if (RSDesc.FillMode == FILL_MODE_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED");
- if (RSDesc.CullMode == CULL_MODE_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED");
- }
-
- void CheckAndCorrectDepthStencilDesc(GraphicsPipelineDesc& GraphicsPipeline) const
- {
- auto& DSSDesc = GraphicsPipeline.DepthStencilDesc;
- if (DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN)
- {
- if (DSSDesc.DepthEnable)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN when depth is enabled");
- else
- DSSDesc.DepthFunc = DepthStencilStateDesc{}.DepthFunc;
- }
-
- auto CheckAndCorrectStencilOpDesc = [&](StencilOpDesc& OpDesc, const char* FaceName) //
- {
- if (DSSDesc.StencilEnable)
- {
- if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
- if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilDepthFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
- if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilPassOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
- if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN)
- LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFunc must not be COMPARISON_FUNC_UNKNOWN when stencil is enabled");
- }
- else
- {
- if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED)
- OpDesc.StencilFailOp = StencilOpDesc{}.StencilFailOp;
- if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED)
- OpDesc.StencilDepthFailOp = StencilOpDesc{}.StencilDepthFailOp;
- if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED)
- OpDesc.StencilPassOp = StencilOpDesc{}.StencilPassOp;
- if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN)
- OpDesc.StencilFunc = StencilOpDesc{}.StencilFunc;
- }
- };
- CheckAndCorrectStencilOpDesc(DSSDesc.FrontFace, "FrontFace");
- CheckAndCorrectStencilOpDesc(DSSDesc.BackFace, "BackFace");
- }
- void CheckAndCorrectBlendStateDesc(GraphicsPipelineDesc& GraphicsPipeline) const
+ void ReserveSpaceForPipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo,
+ LinearAllocator& MemPool)
{
- auto& BlendDesc = GraphicsPipeline.BlendDesc;
- for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
- {
- auto& RTDesc = BlendDesc.RenderTargets[rt];
- // clang-format off
- const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
- const auto LogicOpEnable = RTDesc.LogicOperationEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
- // clang-format on
- if (BlendEnable)
- {
- if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlend must not be BLEND_FACTOR_UNDEFINED");
- if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlend must not be BLEND_FACTOR_UNDEFINED");
- if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOp must not be BLEND_OPERATION_UNDEFINED");
-
- if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
- if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
- if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED)
- LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED");
- }
- else
- {
- if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED)
- RTDesc.SrcBlend = RenderTargetBlendDesc{}.SrcBlend;
- if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED)
- RTDesc.DestBlend = RenderTargetBlendDesc{}.DestBlend;
- if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED)
- RTDesc.BlendOp = RenderTargetBlendDesc{}.BlendOp;
-
- if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED)
- RTDesc.SrcBlendAlpha = RenderTargetBlendDesc{}.SrcBlendAlpha;
- if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED)
- RTDesc.DestBlendAlpha = RenderTargetBlendDesc{}.DestBlendAlpha;
- if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED)
- RTDesc.BlendOpAlpha = RenderTargetBlendDesc{}.BlendOpAlpha;
- }
-
- if (!LogicOpEnable)
- RTDesc.LogicOp = RenderTargetBlendDesc{}.LogicOp;
- }
- }
+ MemPool.AddSpace<GraphicsPipelineDesc>();
+ ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
- void ValidateResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) const
- {
- if (SrcLayout.Variables != nullptr)
- {
- MemPool.AddRequiredSize<ShaderResourceVariableDesc>(SrcLayout.NumVariables);
- for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
- {
- VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null");
- MemPool.AddRequiredSize<Char>(strlen(SrcLayout.Variables[i].Name) + 1);
- }
- }
-
- if (SrcLayout.StaticSamplers != nullptr)
- {
- MemPool.AddRequiredSize<StaticSamplerDesc>(SrcLayout.NumStaticSamplers);
- for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i)
- {
- VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null");
- MemPool.AddRequiredSize<Char>(strlen(SrcLayout.StaticSamplers[i].SamplerOrTextureName) + 1);
- }
- }
- }
-
- void ValidateGraphicsPipeline(const GraphicsPipelineDesc& GraphicsPipeline, LinearAllocator& MemPool) const
- {
- if (GraphicsPipeline.pRenderPass != nullptr)
- {
- if (GraphicsPipeline.NumRenderTargets != 0)
- LOG_PSO_ERROR_AND_THROW("NumRenderTargets must be 0 when explicit render pass is used");
- if (GraphicsPipeline.DSVFormat != TEX_FORMAT_UNKNOWN)
- LOG_PSO_ERROR_AND_THROW("DSVFormat must be TEX_FORMAT_UNKNOWN when explicit render pass is used");
-
- for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
- {
- if (GraphicsPipeline.RTVFormats[rt] != TEX_FORMAT_UNKNOWN)
- LOG_PSO_ERROR_AND_THROW("RTVFormats[", rt, "] must be TEX_FORMAT_UNKNOWN when explicit render pass is used");
- }
-
- const auto& RPDesc = GraphicsPipeline.pRenderPass->GetDesc();
- if (GraphicsPipeline.SubpassIndex >= RPDesc.SubpassCount)
- LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") exceeds the number of subpasses (", Uint32{RPDesc.SubpassCount}, ") in render pass '", RPDesc.Name, "'");
- }
- else
- {
- if (GraphicsPipeline.SubpassIndex != 0)
- LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used");
- }
-
- const auto& InputLayout = GraphicsPipeline.InputLayout;
- Uint32 BufferSlotsUsed = 0;
- MemPool.AddRequiredSize<LayoutElement>(InputLayout.NumElements);
+ const auto& InputLayout = CreateInfo.GraphicsPipeline.InputLayout;
+ MemPool.AddSpace<LayoutElement>(InputLayout.NumElements);
for (Uint32 i = 0; i < InputLayout.NumElements; ++i)
{
auto& LayoutElem = InputLayout.LayoutElements[i];
- MemPool.AddRequiredSize<Char>(strlen(LayoutElem.HLSLSemantic) + 1);
- BufferSlotsUsed = std::max(BufferSlotsUsed, LayoutElem.BufferSlot + 1);
- }
-
- MemPool.AddRequiredSize<Uint32>(BufferSlotsUsed);
- }
-
- void InitResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) const
- {
- if (SrcLayout.Variables != nullptr)
- {
- auto* Variables = MemPool.Allocate<ShaderResourceVariableDesc>(SrcLayout.NumVariables);
- DstLayout.Variables = Variables;
- for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
- {
- Variables[i] = SrcLayout.Variables[i];
- Variables[i].Name = MemPool.CopyString(SrcLayout.Variables[i].Name);
- }
- }
-
- if (SrcLayout.StaticSamplers != nullptr)
- {
- auto* StaticSamplers = MemPool.Allocate<StaticSamplerDesc>(SrcLayout.NumStaticSamplers);
- DstLayout.StaticSamplers = StaticSamplers;
- for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i)
- {
-#ifdef DILIGENT_DEVELOPMENT
- {
- const auto& BorderColor = SrcLayout.StaticSamplers[i].Desc.BorderColor;
- if (!((BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 0) ||
- (BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 1) ||
- (BorderColor[0] == 1 && BorderColor[1] == 1 && BorderColor[2] == 1 && BorderColor[3] == 1)))
- {
- LOG_WARNING_MESSAGE("Static sampler for variable \"", SrcLayout.StaticSamplers[i].SamplerOrTextureName, "\" specifies border color (",
- BorderColor[0], ", ", BorderColor[1], ", ", BorderColor[2], ", ", BorderColor[3],
- "). D3D12 static samplers only allow transparent black (0,0,0,0), opaque black (0,0,0,1) or opaque white (1,1,1,1) as border colors");
- }
- }
-#endif
-
- StaticSamplers[i] = SrcLayout.StaticSamplers[i];
- StaticSamplers[i].SamplerOrTextureName = MemPool.CopyString(SrcLayout.StaticSamplers[i].SamplerOrTextureName);
- }
+ MemPool.AddSpaceForString(LayoutElem.HLSLSemantic);
+ m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, static_cast<Uint8>(LayoutElem.BufferSlot + 1));
}
- }
-protected:
-#define VALIDATE_SHADER_TYPE(Shader, ExpectedType, ShaderName) \
- if (Shader && Shader->GetDesc().ShaderType != ExpectedType) \
- { \
- LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(Shader->GetDesc().ShaderType), " is not a valid type for ", ShaderName, " shader"); \
+ MemPool.AddSpace<Uint32>(m_BufferSlotsUsed);
}
- void ValidateAndReserveSpace(const GraphicsPipelineStateCreateInfo& CreateInfo,
- LinearAllocator& MemPool) const
+ void ReserveSpaceForPipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo,
+ LinearAllocator& MemPool) const
{
- VALIDATE_SHADER_TYPE(CreateInfo.pVS, SHADER_TYPE_VERTEX, "vertex")
- VALIDATE_SHADER_TYPE(CreateInfo.pPS, SHADER_TYPE_PIXEL, "pixel")
- VALIDATE_SHADER_TYPE(CreateInfo.pGS, SHADER_TYPE_GEOMETRY, "geometry")
- VALIDATE_SHADER_TYPE(CreateInfo.pHS, SHADER_TYPE_HULL, "hull")
- VALIDATE_SHADER_TYPE(CreateInfo.pDS, SHADER_TYPE_DOMAIN, "domain")
- VALIDATE_SHADER_TYPE(CreateInfo.pAS, SHADER_TYPE_AMPLIFICATION, "amplification")
- VALIDATE_SHADER_TYPE(CreateInfo.pMS, SHADER_TYPE_MESH, "mesh")
-
- MemPool.AddRequiredSize<GraphicsPipelineDesc>(1);
- ValidateResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
-
- ValidateGraphicsPipeline(CreateInfo.GraphicsPipeline, MemPool);
+ ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
}
- void ValidateAndReserveSpace(const ComputePipelineStateCreateInfo& CreateInfo,
- LinearAllocator& MemPool) const
- {
- if (CreateInfo.pCS == nullptr)
- {
- LOG_ERROR_AND_THROW("Compute shader is not provided");
- }
- VALIDATE_SHADER_TYPE(CreateInfo.pCS, SHADER_TYPE_COMPUTE, "compute");
-
- ValidateResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
- }
template <typename ShaderImplType, typename TShaderStages>
void ExtractShaders(const GraphicsPipelineStateCreateInfo& CreateInfo,
@@ -450,6 +258,7 @@ protected:
{
auto ShaderType = pShader->GetDesc().ShaderType;
ShaderStages.emplace_back(ShaderType, ValidatedCast<ShaderImplType>(pShader));
+ VERIFY(m_ShaderStageTypes[m_NumShaderStages] == SHADER_TYPE_UNKNOWN, "This shader stage is already initialized.");
m_ShaderStageTypes[m_NumShaderStages++] = ShaderType;
}
};
@@ -463,6 +272,7 @@ protected:
AddShaderStage(CreateInfo.pDS);
AddShaderStage(CreateInfo.pGS);
AddShaderStage(CreateInfo.pPS);
+ VERIFY(CreateInfo.pVS != nullptr, "Vertex shader must not be null");
break;
}
@@ -471,6 +281,7 @@ protected:
AddShaderStage(CreateInfo.pAS);
AddShaderStage(CreateInfo.pMS);
AddShaderStage(CreateInfo.pPS);
+ VERIFY(CreateInfo.pMS != nullptr, "Mesh shader must not be null");
break;
}
@@ -488,63 +299,29 @@ protected:
VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once.");
ShaderStages.clear();
- auto AddShaderStage = [&](IShader* pShader) {
- if (pShader != nullptr)
- {
- auto ShaderType = pShader->GetDesc().ShaderType;
- ShaderStages.emplace_back(ShaderType, ValidatedCast<ShaderImplType>(pShader));
- m_ShaderStageTypes[m_NumShaderStages++] = ShaderType;
- }
- };
- AddShaderStage(CreateInfo.pCS);
+ VERIFY_EXPR(CreateInfo.PSODesc.PipelineType == PIPELINE_TYPE_COMPUTE);
+ VERIFY_EXPR(CreateInfo.pCS != nullptr);
+ VERIFY_EXPR(CreateInfo.pCS->GetDesc().ShaderType == SHADER_TYPE_COMPUTE);
+
+ ShaderStages.emplace_back(SHADER_TYPE_COMPUTE, ValidatedCast<ShaderImplType>(CreateInfo.pCS));
+ m_ShaderStageTypes[m_NumShaderStages++] = SHADER_TYPE_COMPUTE;
VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages);
}
- void InitGraphicsPipeline(const GraphicsPipelineStateCreateInfo& CreateInfo,
- LinearAllocator& MemPool)
+ void InitializePipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo,
+ LinearAllocator& MemPool)
{
- this->m_pGraphicsPipelineDesc = MemPool.CopyArray(&CreateInfo.GraphicsPipeline, 1);
+ this->m_pGraphicsPipelineDesc = MemPool.Copy(CreateInfo.GraphicsPipeline);
- InitResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
+ auto& GraphicsPipeline = *this->m_pGraphicsPipelineDesc;
+ CorrectGraphicsPipelineDesc(GraphicsPipeline);
- auto& GraphicsPipeline = *this->m_pGraphicsPipelineDesc;
- const auto& PSODesc = this->m_Desc;
-
- CheckAndCorrectBlendStateDesc(GraphicsPipeline);
- CheckRasterizerStateDesc(GraphicsPipeline);
- CheckAndCorrectDepthStencilDesc(GraphicsPipeline);
-
- if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS)
- {
- DEV_CHECK_ERR(CreateInfo.pVS, "Vertex shader must be defined");
- DEV_CHECK_ERR(!CreateInfo.pAS && !CreateInfo.pMS, "Mesh shaders are not supported in graphics pipeline");
- }
- else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH)
- {
- DEV_CHECK_ERR(CreateInfo.pMS, "Mesh shader must be defined");
- DEV_CHECK_ERR(!CreateInfo.pVS && !CreateInfo.pGS && !CreateInfo.pDS && !CreateInfo.pHS,
- "Vertex, geometry and tessellation shaders are not supported in a mesh pipeline");
- DEV_CHECK_ERR(GraphicsPipeline.InputLayout.NumElements == 0, "Input layout ignored in mesh shader");
- DEV_CHECK_ERR(GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ||
- GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_UNDEFINED,
- "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)");
- }
+ CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
m_pRenderPass = GraphicsPipeline.pRenderPass;
-
- for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt)
- {
- auto RTVFmt = GraphicsPipeline.RTVFormats[rt];
- if (RTVFmt != TEX_FORMAT_UNKNOWN)
- {
- LOG_ERROR_MESSAGE("Render target format (", GetTextureFormatAttribs(RTVFmt).Name, ") of unused slot ", rt,
- " must be set to TEX_FORMAT_UNKNOWN");
- }
- }
-
if (m_pRenderPass)
{
const auto& RPDesc = m_pRenderPass->GetDesc();
@@ -577,8 +354,10 @@ protected:
LayoutElement* pLayoutElements = MemPool.Allocate<LayoutElement>(InputLayout.NumElements);
for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem)
{
- pLayoutElements[Elem] = InputLayout.LayoutElements[Elem];
- pLayoutElements[Elem].HLSLSemantic = MemPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic);
+ const auto& SrcElem = InputLayout.LayoutElements[Elem];
+ pLayoutElements[Elem] = SrcElem;
+ VERIFY_EXPR(SrcElem.HLSLSemantic != nullptr);
+ pLayoutElements[Elem].HLSLSemantic = MemPool.CopyString(SrcElem.HLSLSemantic);
}
GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements;
@@ -599,10 +378,10 @@ protected:
auto BuffSlot = LayoutElem.BufferSlot;
if (BuffSlot >= Strides.size())
{
- UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds maximum allowed value (", Strides.size() - 1, ")");
+ UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds the maximum allowed value (", Strides.size() - 1, ")");
continue;
}
- m_BufferSlotsUsed = static_cast<Uint8>(std::max<Uint32>(m_BufferSlotsUsed, BuffSlot + 1));
+ VERIFY_EXPR(BuffSlot < m_BufferSlotsUsed);
auto& CurrAutoStride = TightStrides[BuffSlot];
// If offset is not explicitly specified, use current auto stride value
@@ -662,14 +441,91 @@ protected:
}
}
- void InitComputePipeline(const ComputePipelineStateCreateInfo& CreateInfo,
- LinearAllocator& MemPool)
+ void InitializePipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo,
+ LinearAllocator& MemPool)
{
- InitResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
+ CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
}
-#undef VALIDATE_SHADER_TYPE
-#undef LOG_PSO_ERROR_AND_THROW
+private:
+ void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) const
+ {
+ if (SrcLayout.Variables != nullptr)
+ {
+ MemPool.AddSpace<ShaderResourceVariableDesc>(SrcLayout.NumVariables);
+ for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
+ {
+ VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null");
+ MemPool.AddSpaceForString(SrcLayout.Variables[i].Name);
+ }
+ }
+
+ if (SrcLayout.StaticSamplers != nullptr)
+ {
+ MemPool.AddSpace<StaticSamplerDesc>(SrcLayout.NumStaticSamplers);
+ for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i)
+ {
+ VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null");
+ MemPool.AddSpaceForString(SrcLayout.StaticSamplers[i].SamplerOrTextureName);
+ }
+ }
+ }
+
+ void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) const
+ {
+ if (SrcLayout.Variables != nullptr)
+ {
+ auto* Variables = MemPool.Allocate<ShaderResourceVariableDesc>(SrcLayout.NumVariables);
+ DstLayout.Variables = Variables;
+ for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
+ {
+ const auto& SrcVar = SrcLayout.Variables[i];
+ Variables[i] = SrcVar;
+ Variables[i].Name = MemPool.CopyString(SrcVar.Name);
+ }
+ }
+
+ if (SrcLayout.StaticSamplers != nullptr)
+ {
+ auto* StaticSamplers = MemPool.Allocate<StaticSamplerDesc>(SrcLayout.NumStaticSamplers);
+ DstLayout.StaticSamplers = StaticSamplers;
+ for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i)
+ {
+ const auto& SrcSmplr = SrcLayout.StaticSamplers[i];
+#ifdef DILIGENT_DEVELOPMENT
+ {
+ const auto& BorderColor = SrcSmplr.Desc.BorderColor;
+ if (!((BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 0) ||
+ (BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 1) ||
+ (BorderColor[0] == 1 && BorderColor[1] == 1 && BorderColor[2] == 1 && BorderColor[3] == 1)))
+ {
+ LOG_WARNING_MESSAGE("Static sampler for variable \"", SrcSmplr.SamplerOrTextureName, "\" specifies border color (",
+ BorderColor[0], ", ", BorderColor[1], ", ", BorderColor[2], ", ", BorderColor[3],
+ "). D3D12 static samplers only allow transparent black (0,0,0,0), opaque black (0,0,0,1) or opaque white (1,1,1,1) as border colors");
+ }
+ }
+#endif
+
+ StaticSamplers[i] = SrcSmplr;
+ StaticSamplers[i].SamplerOrTextureName = MemPool.CopyString(SrcSmplr.SamplerOrTextureName);
+ }
+ }
+ }
+
+protected:
+ size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout
+
+ Uint32* m_pStrides = nullptr;
+ Uint8 m_BufferSlotsUsed = 0;
+
+ Uint8 m_NumShaderStages = 0; ///< Number of shader stages in this PSO
+
+ /// Array of shader types for every shader stage used by this PSO
+ std::array<SHADER_TYPE, MAX_SHADERS_IN_PIPELINE> m_ShaderStageTypes = {};
+
+ RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object
+
+ GraphicsPipelineDesc* m_pGraphicsPipelineDesc = nullptr;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h
index a7596e3f..10cf096e 100644
--- a/Graphics/GraphicsEngine/interface/APIInfo.h
+++ b/Graphics/GraphicsEngine/interface/APIInfo.h
@@ -30,7 +30,7 @@
/// \file
/// Diligent API information
-#define DILIGENT_API_VERSION 240074
+#define DILIGENT_API_VERSION 240075
#include "../../../Primitives/interface/BasicTypes.h"
@@ -39,64 +39,65 @@ DILIGENT_BEGIN_NAMESPACE(Diligent)
/// Diligent API Info. This tructure can be used to verify API compatibility.
struct APIInfo
{
- size_t StructSize DEFAULT_INITIALIZER(0);
- int APIVersion DEFAULT_INITIALIZER(0);
- size_t RenderTargetBlendDescSize DEFAULT_INITIALIZER(0);
- size_t BlendStateDescSize DEFAULT_INITIALIZER(0);
- size_t BufferDescSize DEFAULT_INITIALIZER(0);
- size_t BufferDataSize DEFAULT_INITIALIZER(0);
- size_t BufferFormatSize DEFAULT_INITIALIZER(0);
- size_t BufferViewDescSize DEFAULT_INITIALIZER(0);
- size_t StencilOpDescSize DEFAULT_INITIALIZER(0);
- size_t DepthStencilStateDescSize DEFAULT_INITIALIZER(0);
- size_t SamplerCapsSize DEFAULT_INITIALIZER(0);
- size_t TextureCapsSize DEFAULT_INITIALIZER(0);
- size_t DeviceCapsSize DEFAULT_INITIALIZER(0);
- size_t DrawAttribsSize DEFAULT_INITIALIZER(0);
- size_t DispatchComputeAttribsSize DEFAULT_INITIALIZER(0);
- size_t ViewportSize DEFAULT_INITIALIZER(0);
- size_t RectSize DEFAULT_INITIALIZER(0);
- size_t CopyTextureAttribsSize DEFAULT_INITIALIZER(0);
- size_t DeviceObjectAttribsSize DEFAULT_INITIALIZER(0);
- size_t GraphicsAdapterInfoSize DEFAULT_INITIALIZER(0);
- size_t DisplayModeAttribsSize DEFAULT_INITIALIZER(0);
- size_t SwapChainDescSize DEFAULT_INITIALIZER(0);
- size_t FullScreenModeDescSize DEFAULT_INITIALIZER(0);
- size_t EngineCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineGLCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineD3D11CreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineD3D12CreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineVkCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineMtlCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t BoxSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatAttribsSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatInfoSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatInfoExtSize DEFAULT_INITIALIZER(0);
- size_t StateTransitionDescSize DEFAULT_INITIALIZER(0);
- size_t LayoutElementSize DEFAULT_INITIALIZER(0);
- size_t InputLayoutDescSize DEFAULT_INITIALIZER(0);
- size_t SampleDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderResourceVariableDescSize DEFAULT_INITIALIZER(0);
- size_t StaticSamplerDescSize DEFAULT_INITIALIZER(0);
- size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0);
- size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0);
- size_t ComputePipelineDescSize DEFAULT_INITIALIZER(0);
- size_t PipelineStateDescSize DEFAULT_INITIALIZER(0);
- size_t RasterizerStateDescSize DEFAULT_INITIALIZER(0);
- size_t ResourceMappingEntrySize DEFAULT_INITIALIZER(0);
- size_t ResourceMappingDescSize DEFAULT_INITIALIZER(0);
- size_t SamplerDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderMacroSize DEFAULT_INITIALIZER(0);
- size_t ShaderCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t ShaderResourceDescSize DEFAULT_INITIALIZER(0);
- size_t DepthStencilClearValueSize DEFAULT_INITIALIZER(0);
- size_t OptimizedClearValueSize DEFAULT_INITIALIZER(0);
- size_t TextureDescSize DEFAULT_INITIALIZER(0);
- size_t TextureSubResDataSize DEFAULT_INITIALIZER(0);
- size_t TextureDataSize DEFAULT_INITIALIZER(0);
- size_t MappedTextureSubresourceSize DEFAULT_INITIALIZER(0);
- size_t TextureViewDescSize DEFAULT_INITIALIZER(0);
+ size_t StructSize DEFAULT_INITIALIZER(0);
+ int APIVersion DEFAULT_INITIALIZER(0);
+ size_t RenderTargetBlendDescSize DEFAULT_INITIALIZER(0);
+ size_t BlendStateDescSize DEFAULT_INITIALIZER(0);
+ size_t BufferDescSize DEFAULT_INITIALIZER(0);
+ size_t BufferDataSize DEFAULT_INITIALIZER(0);
+ size_t BufferFormatSize DEFAULT_INITIALIZER(0);
+ size_t BufferViewDescSize DEFAULT_INITIALIZER(0);
+ size_t StencilOpDescSize DEFAULT_INITIALIZER(0);
+ size_t DepthStencilStateDescSize DEFAULT_INITIALIZER(0);
+ size_t SamplerCapsSize DEFAULT_INITIALIZER(0);
+ size_t TextureCapsSize DEFAULT_INITIALIZER(0);
+ size_t DeviceCapsSize DEFAULT_INITIALIZER(0);
+ size_t DrawAttribsSize DEFAULT_INITIALIZER(0);
+ size_t DispatchComputeAttribsSize DEFAULT_INITIALIZER(0);
+ size_t ViewportSize DEFAULT_INITIALIZER(0);
+ size_t RectSize DEFAULT_INITIALIZER(0);
+ size_t CopyTextureAttribsSize DEFAULT_INITIALIZER(0);
+ size_t DeviceObjectAttribsSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsAdapterInfoSize DEFAULT_INITIALIZER(0);
+ size_t DisplayModeAttribsSize DEFAULT_INITIALIZER(0);
+ size_t SwapChainDescSize DEFAULT_INITIALIZER(0);
+ size_t FullScreenModeDescSize DEFAULT_INITIALIZER(0);
+ size_t EngineCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineGLCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineD3D11CreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineD3D12CreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineVkCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineMtlCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t BoxSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatAttribsSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatInfoSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatInfoExtSize DEFAULT_INITIALIZER(0);
+ size_t StateTransitionDescSize DEFAULT_INITIALIZER(0);
+ size_t LayoutElementSize DEFAULT_INITIALIZER(0);
+ size_t InputLayoutDescSize DEFAULT_INITIALIZER(0);
+ size_t SampleDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderResourceVariableDescSize DEFAULT_INITIALIZER(0);
+ size_t StaticSamplerDescSize DEFAULT_INITIALIZER(0);
+ size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsPipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t ComputePipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t PipelineStateDescSize DEFAULT_INITIALIZER(0);
+ size_t RasterizerStateDescSize DEFAULT_INITIALIZER(0);
+ size_t ResourceMappingEntrySize DEFAULT_INITIALIZER(0);
+ size_t ResourceMappingDescSize DEFAULT_INITIALIZER(0);
+ size_t SamplerDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderMacroSize DEFAULT_INITIALIZER(0);
+ size_t ShaderCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t ShaderResourceDescSize DEFAULT_INITIALIZER(0);
+ size_t DepthStencilClearValueSize DEFAULT_INITIALIZER(0);
+ size_t OptimizedClearValueSize DEFAULT_INITIALIZER(0);
+ size_t TextureDescSize DEFAULT_INITIALIZER(0);
+ size_t TextureSubResDataSize DEFAULT_INITIALIZER(0);
+ size_t TextureDataSize DEFAULT_INITIALIZER(0);
+ size_t MappedTextureSubresourceSize DEFAULT_INITIALIZER(0);
+ size_t TextureViewDescSize DEFAULT_INITIALIZER(0);
};
typedef struct APIInfo APIInfo;
diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h
index e5682e58..cef07c66 100644
--- a/Graphics/GraphicsEngine/interface/PipelineState.h
+++ b/Graphics/GraphicsEngine/interface/PipelineState.h
@@ -324,6 +324,13 @@ struct ComputePipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo)
/// Compute shader to be used with the pipeline
IShader* pCS DEFAULT_INITIALIZER(nullptr);
+
+#if DILIGENT_CPP_INTERFACE
+ ComputePipelineStateCreateInfo() noexcept
+ {
+ PSODesc.PipelineType = PIPELINE_TYPE_COMPUTE;
+ }
+#endif
};
typedef struct ComputePipelineStateCreateInfo ComputePipelineStateCreateInfo;
@@ -349,7 +356,8 @@ DILIGENT_BEGIN_INTERFACE(IPipelineState, IDeviceObject)
virtual const PipelineStateDesc& METHOD(GetDesc)() const override = 0;
#endif
- /// Returns the graphics pipeline description used to create the object
+ /// Returns the graphics pipeline description used to create the object.
+ /// This method must only be called for a graphics or mesh pipeline.
VIRTUAL const GraphicsPipelineDesc REF METHOD(GetGraphicsPipelineDesc)(THIS) CONST PURE;
/// Binds resources for all shaders in the pipeline state
diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h
index ea4e05af..5c72c81a 100644
--- a/Graphics/GraphicsEngine/interface/RenderDevice.h
+++ b/Graphics/GraphicsEngine/interface/RenderDevice.h
@@ -155,7 +155,7 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject)
/// Creates a new graphics pipeline state object
- /// \param [in] PSOCreateInfo - Pipeline state create info, see Diligent::GraphicsPipelineStateCreateInfo for details.
+ /// \param [in] PSOCreateInfo - Graphics pipeline state create info, see Diligent::GraphicsPipelineStateCreateInfo for details.
/// \param [out] ppPipelineState - Address of the memory location where the pointer to the
/// pipeline state interface will be stored.
/// The function calls AddRef(), so that the new object will contain
@@ -166,7 +166,7 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject)
/// Creates a new compute pipeline state object
- /// \param [in] PSOCreateInfo - Pipeline state create info, see Diligent::ComputePipelineStateCreateInfo for details.
+ /// \param [in] PSOCreateInfo - Compute pipeline state create info, see Diligent::ComputePipelineStateCreateInfo for details.
/// \param [out] ppPipelineState - Address of the memory location where the pointer to the
/// pipeline state interface will be stored.
/// The function calls AddRef(), so that the new object will contain
diff --git a/Graphics/GraphicsEngine/src/APIInfo.cpp b/Graphics/GraphicsEngine/src/APIInfo.cpp
index 05aef568..aa2fb3d9 100644
--- a/Graphics/GraphicsEngine/src/APIInfo.cpp
+++ b/Graphics/GraphicsEngine/src/APIInfo.cpp
@@ -90,6 +90,8 @@ static APIInfo InitAPIInfo()
INIT_STRUCTURE_SIZE(StaticSamplerDesc);
INIT_STRUCTURE_SIZE(PipelineResourceLayoutDesc);
INIT_STRUCTURE_SIZE(GraphicsPipelineDesc);
+ INIT_STRUCTURE_SIZE(GraphicsPipelineStateCreateInfo);
+ INIT_STRUCTURE_SIZE(ComputePipelineStateCreateInfo);
INIT_STRUCTURE_SIZE(PipelineStateDesc);
INIT_STRUCTURE_SIZE(RasterizerStateDesc);
INIT_STRUCTURE_SIZE(ResourceMappingEntry);
diff --git a/Graphics/GraphicsEngine/src/PipelineStateBase.cpp b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
new file mode 100644
index 00000000..fedc332d
--- /dev/null
+++ b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "PipelineStateBase.hpp"
+
+namespace Diligent
+{
+
+#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ", GetPipelineTypeString(PSODesc.PipelineType), " PSO '", PSODesc.Name, "' is invalid: ", ##__VA_ARGS__)
+
+namespace
+{
+
+void ValidateRasterizerStateDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false)
+{
+ const auto& RSDesc = GraphicsPipeline.RasterizerDesc;
+ if (RSDesc.FillMode == FILL_MODE_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED");
+ if (RSDesc.CullMode == CULL_MODE_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED");
+}
+
+void ValidateDepthStencilDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false)
+{
+ const auto& DSSDesc = GraphicsPipeline.DepthStencilDesc;
+ if (DSSDesc.DepthEnable && DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN when depth is enabled");
+
+ auto CheckStencilOpDesc = [&](const StencilOpDesc& OpDesc, const char* FaceName) //
+ {
+ if (DSSDesc.StencilEnable)
+ {
+ if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
+ if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilDepthFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
+ if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilPassOp must not be STENCIL_OP_UNDEFINED when stencil is enabled");
+ if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN)
+ LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFunc must not be COMPARISON_FUNC_UNKNOWN when stencil is enabled");
+ }
+ };
+ CheckStencilOpDesc(DSSDesc.FrontFace, "FrontFace");
+ CheckStencilOpDesc(DSSDesc.BackFace, "BackFace");
+}
+
+void CorrectDepthStencilDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept
+{
+ auto& DSSDesc = GraphicsPipeline.DepthStencilDesc;
+ if (!DSSDesc.DepthEnable && DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN)
+ DSSDesc.DepthFunc = DepthStencilStateDesc{}.DepthFunc;
+
+ auto CorrectStencilOpDesc = [&](StencilOpDesc& OpDesc) //
+ {
+ if (!DSSDesc.StencilEnable)
+ {
+ if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED)
+ OpDesc.StencilFailOp = StencilOpDesc{}.StencilFailOp;
+ if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED)
+ OpDesc.StencilDepthFailOp = StencilOpDesc{}.StencilDepthFailOp;
+ if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED)
+ OpDesc.StencilPassOp = StencilOpDesc{}.StencilPassOp;
+ if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN)
+ OpDesc.StencilFunc = StencilOpDesc{}.StencilFunc;
+ }
+ };
+ CorrectStencilOpDesc(DSSDesc.FrontFace);
+ CorrectStencilOpDesc(DSSDesc.BackFace);
+}
+
+void ValidateBlendStateDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false)
+{
+ const auto& BlendDesc = GraphicsPipeline.BlendDesc;
+ for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
+ {
+ auto& RTDesc = BlendDesc.RenderTargets[rt];
+
+ const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
+ if (BlendEnable)
+ {
+ if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlend must not be BLEND_FACTOR_UNDEFINED");
+ if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlend must not be BLEND_FACTOR_UNDEFINED");
+ if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOp must not be BLEND_OPERATION_UNDEFINED");
+
+ if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
+ if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED");
+ if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED)
+ LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED");
+ }
+ }
+}
+
+void CorrectBlendStateDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept
+{
+ auto& BlendDesc = GraphicsPipeline.BlendDesc;
+ for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
+ {
+ auto& RTDesc = BlendDesc.RenderTargets[rt];
+ // clang-format off
+ const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
+ const auto LogicOpEnable = RTDesc.LogicOperationEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0));
+ // clang-format on
+ if (!BlendEnable)
+ {
+ if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED)
+ RTDesc.SrcBlend = RenderTargetBlendDesc{}.SrcBlend;
+ if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED)
+ RTDesc.DestBlend = RenderTargetBlendDesc{}.DestBlend;
+ if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED)
+ RTDesc.BlendOp = RenderTargetBlendDesc{}.BlendOp;
+
+ if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED)
+ RTDesc.SrcBlendAlpha = RenderTargetBlendDesc{}.SrcBlendAlpha;
+ if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED)
+ RTDesc.DestBlendAlpha = RenderTargetBlendDesc{}.DestBlendAlpha;
+ if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED)
+ RTDesc.BlendOpAlpha = RenderTargetBlendDesc{}.BlendOpAlpha;
+ }
+
+ if (!LogicOpEnable)
+ RTDesc.LogicOp = RenderTargetBlendDesc{}.LogicOp;
+ }
+}
+
+} // namespace
+
+#define VALIDATE_SHADER_TYPE(Shader, ExpectedType, ShaderName) \
+ if (Shader != nullptr && Shader->GetDesc().ShaderType != ExpectedType) \
+ { \
+ LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(Shader->GetDesc().ShaderType), " is not a valid type for ", ShaderName, " shader"); \
+ }
+
+void ValidateGraphicsPipelineCreateInfo(const GraphicsPipelineStateCreateInfo& CreateInfo) noexcept(false)
+{
+ const auto& PSODesc = CreateInfo.PSODesc;
+ if (PSODesc.PipelineType != PIPELINE_TYPE_GRAPHICS && PSODesc.PipelineType != PIPELINE_TYPE_MESH)
+ LOG_PSO_ERROR_AND_THROW("Pipeline type must be GRAPHICS or MESH");
+
+ const auto& GraphicsPipeline = CreateInfo.GraphicsPipeline;
+
+ ValidateBlendStateDesc(PSODesc, GraphicsPipeline);
+ ValidateRasterizerStateDesc(PSODesc, GraphicsPipeline);
+ ValidateDepthStencilDesc(PSODesc, GraphicsPipeline);
+
+
+ if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS)
+ {
+ if (CreateInfo.pVS == nullptr)
+ LOG_ERROR_AND_THROW("Vertex shader must not be null");
+
+ DEV_CHECK_ERR(CreateInfo.pAS == nullptr && CreateInfo.pMS == nullptr, "Mesh shaders are not supported in graphics pipeline");
+ }
+ else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH)
+ {
+ if (CreateInfo.pMS == nullptr)
+ LOG_ERROR_AND_THROW("Mesh shader must not be null");
+
+ DEV_CHECK_ERR(CreateInfo.pVS == nullptr && CreateInfo.pGS == nullptr && CreateInfo.pDS == nullptr && CreateInfo.pHS == nullptr,
+ "Vertex, geometry and tessellation shaders are not supported in a mesh pipeline");
+ DEV_CHECK_ERR(GraphicsPipeline.InputLayout.NumElements == 0, "Input layout is ignored in a mesh pipeline");
+ DEV_CHECK_ERR(GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ||
+ GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_UNDEFINED,
+ "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)");
+ }
+
+
+ VALIDATE_SHADER_TYPE(CreateInfo.pVS, SHADER_TYPE_VERTEX, "vertex")
+ VALIDATE_SHADER_TYPE(CreateInfo.pPS, SHADER_TYPE_PIXEL, "pixel")
+ VALIDATE_SHADER_TYPE(CreateInfo.pGS, SHADER_TYPE_GEOMETRY, "geometry")
+ VALIDATE_SHADER_TYPE(CreateInfo.pHS, SHADER_TYPE_HULL, "hull")
+ VALIDATE_SHADER_TYPE(CreateInfo.pDS, SHADER_TYPE_DOMAIN, "domain")
+ VALIDATE_SHADER_TYPE(CreateInfo.pAS, SHADER_TYPE_AMPLIFICATION, "amplification")
+ VALIDATE_SHADER_TYPE(CreateInfo.pMS, SHADER_TYPE_MESH, "mesh")
+
+
+ if (GraphicsPipeline.pRenderPass != nullptr)
+ {
+ if (GraphicsPipeline.NumRenderTargets != 0)
+ LOG_PSO_ERROR_AND_THROW("NumRenderTargets must be 0 when explicit render pass is used");
+ if (GraphicsPipeline.DSVFormat != TEX_FORMAT_UNKNOWN)
+ LOG_PSO_ERROR_AND_THROW("DSVFormat must be TEX_FORMAT_UNKNOWN when explicit render pass is used");
+
+ for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt)
+ {
+ if (GraphicsPipeline.RTVFormats[rt] != TEX_FORMAT_UNKNOWN)
+ LOG_PSO_ERROR_AND_THROW("RTVFormats[", rt, "] must be TEX_FORMAT_UNKNOWN when explicit render pass is used");
+ }
+
+ const auto& RPDesc = GraphicsPipeline.pRenderPass->GetDesc();
+ if (GraphicsPipeline.SubpassIndex >= RPDesc.SubpassCount)
+ LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") exceeds the number of subpasses (", Uint32{RPDesc.SubpassCount}, ") in render pass '", RPDesc.Name, "'");
+ }
+ else
+ {
+ for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt)
+ {
+ auto RTVFmt = GraphicsPipeline.RTVFormats[rt];
+ if (RTVFmt != TEX_FORMAT_UNKNOWN)
+ {
+ LOG_ERROR_MESSAGE("Render target format (", GetTextureFormatAttribs(RTVFmt).Name, ") of unused slot ", rt,
+ " must be set to TEX_FORMAT_UNKNOWN");
+ }
+ }
+
+ if (GraphicsPipeline.SubpassIndex != 0)
+ LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used");
+ }
+}
+
+void ValidateComputePipelineCreateInfo(const ComputePipelineStateCreateInfo& CreateInfo) noexcept(false)
+{
+ const auto& PSODesc = CreateInfo.PSODesc;
+ if (PSODesc.PipelineType != PIPELINE_TYPE_COMPUTE)
+ LOG_PSO_ERROR_AND_THROW("Pipeline type must be COMPUTE");
+
+ if (CreateInfo.pCS == nullptr)
+ LOG_ERROR_AND_THROW("Compute shader must not be null");
+
+ VALIDATE_SHADER_TYPE(CreateInfo.pCS, SHADER_TYPE_COMPUTE, "compute");
+}
+#undef VALIDATE_SHADER_TYPE
+#undef LOG_PSO_ERROR_AND_THROW
+
+void CorrectGraphicsPipelineDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept
+{
+ CorrectBlendStateDesc(GraphicsPipeline);
+ CorrectDepthStencilDesc(GraphicsPipeline);
+}
+
+} // namespace Diligent