From 645ef7e425d6ff4ee64b782d27767e0a5732be50 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 18 Oct 2020 13:06:48 -0700 Subject: A number of fixes for PSO creation refactoring (API240075) --- Graphics/GraphicsEngine/CMakeLists.txt | 1 + .../GraphicsEngine/include/DeviceContextBase.hpp | 8 +- .../GraphicsEngine/include/PipelineStateBase.hpp | 450 +++++++-------------- Graphics/GraphicsEngine/interface/APIInfo.h | 119 +++--- Graphics/GraphicsEngine/interface/PipelineState.h | 10 +- Graphics/GraphicsEngine/interface/RenderDevice.h | 4 +- Graphics/GraphicsEngine/src/APIInfo.cpp | 2 + Graphics/GraphicsEngine/src/PipelineStateBase.cpp | 260 ++++++++++++ 8 files changed, 494 insertions(+), 360 deletions(-) create mode 100644 Graphics/GraphicsEngine/src/PipelineStateBase.cpp (limited to 'Graphics/GraphicsEngine') 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:: 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:: 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; - /// \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 m_ShaderStageTypes = {}; - - RefCntAutoPtr 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& 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(); + ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool); - void ValidateResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) const - { - if (SrcLayout.Variables != nullptr) - { - MemPool.AddRequiredSize(SrcLayout.NumVariables); - for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) - { - VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null"); - MemPool.AddRequiredSize(strlen(SrcLayout.Variables[i].Name) + 1); - } - } - - if (SrcLayout.StaticSamplers != nullptr) - { - MemPool.AddRequiredSize(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(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(InputLayout.NumElements); + const auto& InputLayout = CreateInfo.GraphicsPipeline.InputLayout; + MemPool.AddSpace(InputLayout.NumElements); for (Uint32 i = 0; i < InputLayout.NumElements; ++i) { auto& LayoutElem = InputLayout.LayoutElements[i]; - MemPool.AddRequiredSize(strlen(LayoutElem.HLSLSemantic) + 1); - BufferSlotsUsed = std::max(BufferSlotsUsed, LayoutElem.BufferSlot + 1); - } - - MemPool.AddRequiredSize(BufferSlotsUsed); - } - - void InitResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) const - { - if (SrcLayout.Variables != nullptr) - { - auto* Variables = MemPool.Allocate(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(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(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(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(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 void ExtractShaders(const GraphicsPipelineStateCreateInfo& CreateInfo, @@ -450,6 +258,7 @@ protected: { auto ShaderType = pShader->GetDesc().ShaderType; ShaderStages.emplace_back(ShaderType, ValidatedCast(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(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(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(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(std::max(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(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(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(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(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 m_ShaderStageTypes = {}; + + RefCntAutoPtr 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 -- cgit v1.2.3