From c75307ce6d2d3d18b9ad7ba0bbcf2e2e59ba5a2c Mon Sep 17 00:00:00 2001 From: assiduous Date: Wed, 7 Oct 2020 14:12:45 -0700 Subject: Few minor updates --- Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp | 3 ++- Graphics/GraphicsEngine/interface/Shader.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp index 5648e39d..f82f18cf 100644 --- a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp @@ -32,6 +32,7 @@ #include +#include "Atomics.hpp" #include "ShaderResourceVariable.h" #include "PipelineState.h" #include "StringTools.hpp" @@ -340,7 +341,7 @@ template Date: Thu, 8 Oct 2020 21:45:01 +0300 Subject: removed strong references to shaders in PSO --- .../GraphicsEngine/include/PipelineStateBase.hpp | 603 +++++++++++---------- Graphics/GraphicsEngine/interface/PipelineState.h | 2 +- 2 files changed, 322 insertions(+), 283 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index b54a2f76..76760db5 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -60,44 +60,42 @@ public: /// \param pRefCounters - reference counters object that controls the lifetime of this PSO /// \param pDevice - pointer to the device. /// \param PSODesc - pipeline state description. - /// \param bIsDeviceInternal - flag indicating if the blend state is an internal device object and + /// \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 PipelineStateDesc& PSODesc, bool bIsDeviceInternal = false) : - TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal}, - m_NumShaders{0} + TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal} { - ValidateDesc(); - const auto& SrcLayout = PSODesc.ResourceLayout; size_t StringPoolSize = 0; if (SrcLayout.Variables != nullptr) { for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) + { + VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null"); StringPoolSize += strlen(SrcLayout.Variables[i].Name) + 1; + } } if (SrcLayout.StaticSamplers != nullptr) { for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) + { + VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null"); StringPoolSize += strlen(SrcLayout.StaticSamplers[i].SamplerOrTextureName) + 1; + } } - if (PSODesc.IsAnyGraphicsPipeline()) + switch (PSODesc.PipelineType) { - CheckAndCorrectBlendStateDesc(); - CheckRasterizerStateDesc(); - CheckAndCorrectDepthStencilDesc(); - - const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout; - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - StringPoolSize += strlen(InputLayout.LayoutElements[i].HLSLSemantic) + 1; - } - else - { - DEV_CHECK_ERR(PSODesc.GraphicsPipeline.InputLayout.NumElements == 0, "Compute pipelines must not have input layout elements"); + // clang-format off + case PIPELINE_TYPE_GRAPHICS: + case PIPELINE_TYPE_MESH: ValidateGraphicsPipeline( StringPoolSize); break; + case PIPELINE_TYPE_COMPUTE: ValidateComputePipeline( StringPoolSize); break; + default: UNEXPECTED("unknown pipeline type"); + // clang-format on } m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); @@ -110,7 +108,6 @@ public: DstLayout.Variables = Variables; for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) { - VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null"); Variables[i] = SrcLayout.Variables[i]; Variables[i].Name = m_StringPool.CopyString(SrcLayout.Variables[i].Name); } @@ -123,7 +120,6 @@ public: DstLayout.StaticSamplers = StaticSamplers; for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) { - VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null"); #ifdef DILIGENT_DEVELOPMENT { const auto& BorderColor = SrcLayout.StaticSamplers[i].Desc.BorderColor; @@ -143,208 +139,14 @@ public: } } - - if (this->m_Desc.IsComputePipeline()) + switch (PSODesc.PipelineType) { - const auto& ComputePipeline = PSODesc.ComputePipeline; - if (ComputePipeline.pCS == nullptr) - { - LOG_ERROR_AND_THROW("Compute shader is not provided"); - } - -#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"); \ - } - - VALIDATE_SHADER_TYPE(ComputePipeline.pCS, SHADER_TYPE_COMPUTE, "compute") - - m_pCS = ComputePipeline.pCS; - m_ppShaders[0] = ComputePipeline.pCS; - m_NumShaders = 1; - } - else - { - const auto& GraphicsPipeline = PSODesc.GraphicsPipeline; - - VALIDATE_SHADER_TYPE(GraphicsPipeline.pVS, SHADER_TYPE_VERTEX, "vertex") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pPS, SHADER_TYPE_PIXEL, "pixel") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pGS, SHADER_TYPE_GEOMETRY, "geometry") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pHS, SHADER_TYPE_HULL, "hull") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pDS, SHADER_TYPE_DOMAIN, "domain") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pAS, SHADER_TYPE_AMPLIFICATION, "amplification") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pMS, SHADER_TYPE_MESH, "mesh") -#undef VALIDATE_SHADER_TYPE - - if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) - { - DEV_CHECK_ERR(GraphicsPipeline.pVS, "Vertex shader must be defined"); - DEV_CHECK_ERR(!GraphicsPipeline.pAS && !GraphicsPipeline.pMS, "Mesh shaders are not supported in graphics pipeline"); - m_pVS = GraphicsPipeline.pVS; - m_pPS = GraphicsPipeline.pPS; - m_pGS = GraphicsPipeline.pGS; - m_pDS = GraphicsPipeline.pDS; - m_pHS = GraphicsPipeline.pHS; - } - else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH) - { - DEV_CHECK_ERR(GraphicsPipeline.pMS, "Mesh shader must be defined"); - DEV_CHECK_ERR(!GraphicsPipeline.pVS && !GraphicsPipeline.pGS && !GraphicsPipeline.pDS && !GraphicsPipeline.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)"); - m_pAS = GraphicsPipeline.pAS; - m_pMS = GraphicsPipeline.pMS; - m_pPS = GraphicsPipeline.pPS; - } - - if (GraphicsPipeline.pVS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pVS; - if (GraphicsPipeline.pPS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pPS; - if (GraphicsPipeline.pGS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pGS; - if (GraphicsPipeline.pHS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pHS; - if (GraphicsPipeline.pDS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pDS; - if (GraphicsPipeline.pAS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pAS; - if (GraphicsPipeline.pMS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pMS; - - DEV_CHECK_ERR(m_NumShaders > 0, "There must be at least one shader in the Pipeline State"); - - m_pRenderPass = PSODesc.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(); - VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount); - const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex]; - - this->m_Desc.GraphicsPipeline.NumRenderTargets = static_cast(Subpass.RenderTargetAttachmentCount); - for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt) - { - const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt]; - if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) - { - VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); - this->m_Desc.GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; - } - } - - if (Subpass.pDepthStencilAttachment != nullptr) - { - const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment; - if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) - { - VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); - this->m_Desc.GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; - } - } - } - - const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout; - LayoutElement* pLayoutElements = nullptr; - if (InputLayout.NumElements > 0) - { - pLayoutElements = ALLOCATE(GetRawAllocator(), "Raw memory for input layout elements", LayoutElement, InputLayout.NumElements); - } - this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements; - for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem) - { - pLayoutElements[Elem] = InputLayout.LayoutElements[Elem]; - pLayoutElements[Elem].HLSLSemantic = m_StringPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic); - } - - - // Correct description and compute offsets and tight strides - std::array Strides, TightStrides = {}; - // Set all strides to an invalid value because an application may want to use 0 stride - for (auto& Stride : Strides) - Stride = LAYOUT_ELEMENT_AUTO_STRIDE; - - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - { - auto& LayoutElem = pLayoutElements[i]; - - if (LayoutElem.ValueType == VT_FLOAT32 || LayoutElem.ValueType == VT_FLOAT16) - LayoutElem.IsNormalized = false; // Floating point values cannot be normalized - - auto BuffSlot = LayoutElem.BufferSlot; - if (BuffSlot >= Strides.size()) - { - UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds maximum allowed value (", Strides.size() - 1, ")"); - continue; - } - m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, BuffSlot + 1); - - auto& CurrAutoStride = TightStrides[BuffSlot]; - // If offset is not explicitly specified, use current auto stride value - if (LayoutElem.RelativeOffset == LAYOUT_ELEMENT_AUTO_OFFSET) - { - LayoutElem.RelativeOffset = CurrAutoStride; - } - - // If stride is explicitly specified, use it for the current buffer slot - if (LayoutElem.Stride != LAYOUT_ELEMENT_AUTO_STRIDE) - { - // Verify that the value is consistent with the previously specified stride, if any - if (Strides[BuffSlot] != LAYOUT_ELEMENT_AUTO_STRIDE && Strides[BuffSlot] != LayoutElem.Stride) - { - LOG_ERROR_MESSAGE("Inconsistent strides are specified for buffer slot ", BuffSlot, - ". Input element at index ", LayoutElem.InputIndex, " explicitly specifies stride ", - LayoutElem.Stride, ", while current value is ", Strides[BuffSlot], - ". Specify consistent strides or use LAYOUT_ELEMENT_AUTO_STRIDE to allow " - "the engine compute strides automatically."); - } - Strides[BuffSlot] = LayoutElem.Stride; - } - - CurrAutoStride = std::max(CurrAutoStride, LayoutElem.RelativeOffset + LayoutElem.NumComponents * GetValueSize(LayoutElem.ValueType)); - } - - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - { - auto& LayoutElem = pLayoutElements[i]; - - auto BuffSlot = LayoutElem.BufferSlot; - // If no input elements explicitly specified stride for this buffer slot, use automatic stride - if (Strides[BuffSlot] == LAYOUT_ELEMENT_AUTO_STRIDE) - { - Strides[BuffSlot] = TightStrides[BuffSlot]; - } - else - { - if (Strides[BuffSlot] < TightStrides[BuffSlot]) - { - LOG_ERROR_MESSAGE("Stride ", Strides[BuffSlot], " explicitly specified for slot ", BuffSlot, - " is smaller than the minimum stride ", TightStrides[BuffSlot], - " required to accomodate all input elements."); - } - } - if (LayoutElem.Stride == LAYOUT_ELEMENT_AUTO_STRIDE) - LayoutElem.Stride = Strides[BuffSlot]; - } - - if (m_BufferSlotsUsed > 0) - { - m_pStrides = ALLOCATE(GetRawAllocator(), "Raw memory for buffer strides", Uint32, m_BufferSlotsUsed); - - // Set strides for all unused slots to 0 - for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i) - { - auto Stride = Strides[i]; - m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0; - } - } + // clang-format off + case PIPELINE_TYPE_GRAPHICS: + case PIPELINE_TYPE_MESH: InitGraphicsPipeline(); break; + case PIPELINE_TYPE_COMPUTE: InitComputePipeline(); break; + default: UNEXPECTED("unknown pipeline type"); + // clang-format on } VERIFY_EXPR(m_StringPool.GetRemainingSize() == 0); @@ -399,28 +201,8 @@ public: return m_BufferSlotsUsed; } - IShader* GetVS() { return m_pVS; } - IShader* GetPS() { return m_pPS; } - IShader* GetGS() { return m_pGS; } - IShader* GetDS() { return m_pDS; } - IShader* GetHS() { return m_pHS; } - IShader* GetCS() { return m_pCS; } - - IShader* const* GetShaders() const { return m_ppShaders.data(); } - Uint32 GetNumShaders() const { return m_NumShaders; } - - template - ShaderType* GetShader(Uint32 ShaderInd) - { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return ValidatedCast(m_ppShaders[ShaderInd]); - } - template - ShaderType* GetShader(Uint32 ShaderInd) const - { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return ValidatedCast(m_ppShaders[ShaderInd]); - } + SHADER_TYPE const* GetShaderTypes() const { return m_pShaderTypes.data(); } + Uint32 GetNumShaderTypes() const { return m_NumShaderTypes; } // This function only compares shader resource layout hashes, so // it can potentially give false negatives @@ -431,27 +213,20 @@ public: protected: Uint32 m_BufferSlotsUsed = 0; - Uint32 m_NumShaders = 0; ///< Number of shaders that this PSO uses Uint32* m_pStrides = nullptr; StringPool m_StringPool; - RefCntAutoPtr m_pVS; ///< Strong reference to the vertex shader - RefCntAutoPtr m_pPS; ///< Strong reference to the pixel shader - RefCntAutoPtr m_pGS; ///< Strong reference to the geometry shader - RefCntAutoPtr m_pDS; ///< Strong reference to the domain shader - RefCntAutoPtr m_pHS; ///< Strong reference to the hull shader - RefCntAutoPtr m_pCS; ///< Strong reference to the compute shader - RefCntAutoPtr m_pAS; ///< Strong reference to the amplification shader - RefCntAutoPtr m_pMS; ///< Strong reference to the mesh shader - RefCntAutoPtr m_pRenderPass; ///< Strong reference to the render pass object - std::array m_ppShaders = {}; ///< Array of pointers to the shaders used by this PSO - size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout + Uint8 m_NumShaderTypes = 0; ///< Number of shader types that this PSO uses + std::array m_pShaderTypes = {}; ///< Array of shader types used by this PSO + size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout 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)) @@ -512,46 +287,70 @@ protected: return LayoutInd; } -private: -#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__) +public: + using ShaderStages_t = std::vector>; - void ValidateDesc() const +protected: + void ExtractShaders(ShaderStages_t& ShaderStages) { - if (this->m_Desc.IsComputePipeline()) + auto& Desc = this->m_Desc; + switch (Desc.PipelineType) { - if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr) + case PIPELINE_TYPE_COMPUTE: { - LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null for compute pipelines"); - } - } - else - { - const auto& GraphicsPipeline = this->m_Desc.GraphicsPipeline; - 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"); + if (Desc.ComputePipeline.pCS) ShaderStages.push_back({SHADER_TYPE_COMPUTE, Desc.ComputePipeline.pCS}); - 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"); - } + // reset shader pointers because we don't keep strong references to shaders + Desc.ComputePipeline.pCS = nullptr; + break; + } - 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, "'"); + case PIPELINE_TYPE_GRAPHICS: + { + if (Desc.GraphicsPipeline.pVS) ShaderStages.push_back({SHADER_TYPE_VERTEX, Desc.GraphicsPipeline.pVS}); + if (Desc.GraphicsPipeline.pHS) ShaderStages.push_back({SHADER_TYPE_HULL, Desc.GraphicsPipeline.pHS}); + if (Desc.GraphicsPipeline.pDS) ShaderStages.push_back({SHADER_TYPE_DOMAIN, Desc.GraphicsPipeline.pDS}); + if (Desc.GraphicsPipeline.pGS) ShaderStages.push_back({SHADER_TYPE_GEOMETRY, Desc.GraphicsPipeline.pGS}); + if (Desc.GraphicsPipeline.pPS) ShaderStages.push_back({SHADER_TYPE_PIXEL, Desc.GraphicsPipeline.pPS}); + + // reset shader pointers because we don't keep strong references to shaders + Desc.GraphicsPipeline.pVS = nullptr; + Desc.GraphicsPipeline.pHS = nullptr; + Desc.GraphicsPipeline.pDS = nullptr; + Desc.GraphicsPipeline.pGS = nullptr; + Desc.GraphicsPipeline.pPS = nullptr; + break; } - else + + case PIPELINE_TYPE_MESH: { - if (GraphicsPipeline.SubpassIndex != 0) - LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used"); + if (Desc.GraphicsPipeline.pAS) ShaderStages.push_back({SHADER_TYPE_AMPLIFICATION, Desc.GraphicsPipeline.pAS}); + if (Desc.GraphicsPipeline.pMS) ShaderStages.push_back({SHADER_TYPE_MESH, Desc.GraphicsPipeline.pMS}); + if (Desc.GraphicsPipeline.pPS) ShaderStages.push_back({SHADER_TYPE_PIXEL, Desc.GraphicsPipeline.pPS}); + + // reset shader pointers because we don't keep strong references to shaders + Desc.GraphicsPipeline.pAS = nullptr; + Desc.GraphicsPipeline.pMS = nullptr; + Desc.GraphicsPipeline.pPS = nullptr; + break; } + + default: + UNEXPECTED("unknown pipeline type"); } + +#ifdef DILIGENT_DEVELOPMENT + VERIFY_EXPR(ShaderStages.size() == m_NumShaderTypes); + + for (Uint32 s = 0; s < m_NumShaderTypes; ++s) + { + VERIFY_EXPR(ShaderStages[s].first == m_pShaderTypes[s]); + } +#endif } + +private: void CheckRasterizerStateDesc() const { const auto& RSDesc = this->m_Desc.GraphicsPipeline.RasterizerDesc; @@ -648,6 +447,246 @@ private: RTDesc.LogicOp = RenderTargetBlendDesc{}.LogicOp; } } + + void ValidateGraphicsPipeline(size_t& StringPoolSize) + { + const auto& GraphicsPipeline = this->m_Desc.GraphicsPipeline; + 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"); + } + + CheckAndCorrectBlendStateDesc(); + CheckRasterizerStateDesc(); + CheckAndCorrectDepthStencilDesc(); + + const auto& InputLayout = this->m_Desc.GraphicsPipeline.InputLayout; + for (Uint32 i = 0; i < InputLayout.NumElements; ++i) + StringPoolSize += strlen(InputLayout.LayoutElements[i].HLSLSemantic) + 1; + } + + void ValidateComputePipeline(size_t& StringPoolSize) + { + if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr) + { + LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null for compute pipelines"); + } + DEV_CHECK_ERR(this->m_Desc.GraphicsPipeline.InputLayout.NumElements == 0, "Compute pipelines must not have input layout elements"); + } + +#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"); \ + } + + void InitGraphicsPipeline() + { + const auto& PSODesc = this->m_Desc; + const auto& GraphicsPipeline = PSODesc.GraphicsPipeline; + + VALIDATE_SHADER_TYPE(GraphicsPipeline.pVS, SHADER_TYPE_VERTEX, "vertex") + VALIDATE_SHADER_TYPE(GraphicsPipeline.pPS, SHADER_TYPE_PIXEL, "pixel") + VALIDATE_SHADER_TYPE(GraphicsPipeline.pGS, SHADER_TYPE_GEOMETRY, "geometry") + VALIDATE_SHADER_TYPE(GraphicsPipeline.pHS, SHADER_TYPE_HULL, "hull") + VALIDATE_SHADER_TYPE(GraphicsPipeline.pDS, SHADER_TYPE_DOMAIN, "domain") + VALIDATE_SHADER_TYPE(GraphicsPipeline.pAS, SHADER_TYPE_AMPLIFICATION, "amplification") + VALIDATE_SHADER_TYPE(GraphicsPipeline.pMS, SHADER_TYPE_MESH, "mesh") + + if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) + { + DEV_CHECK_ERR(GraphicsPipeline.pVS, "Vertex shader must be defined"); + DEV_CHECK_ERR(!GraphicsPipeline.pAS && !GraphicsPipeline.pMS, "Mesh shaders are not supported in graphics pipeline"); + } + else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH) + { + DEV_CHECK_ERR(GraphicsPipeline.pMS, "Mesh shader must be defined"); + DEV_CHECK_ERR(!GraphicsPipeline.pVS && !GraphicsPipeline.pGS && !GraphicsPipeline.pDS && !GraphicsPipeline.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)"); + } + + if (GraphicsPipeline.pVS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_VERTEX; + if (GraphicsPipeline.pHS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_HULL; + if (GraphicsPipeline.pDS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_DOMAIN; + if (GraphicsPipeline.pGS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_GEOMETRY; + if (GraphicsPipeline.pAS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_AMPLIFICATION; + if (GraphicsPipeline.pMS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_MESH; + if (GraphicsPipeline.pPS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_PIXEL; + + DEV_CHECK_ERR(m_NumShaderTypes > 0, "There must be at least one shader in the Pipeline State"); + + m_pRenderPass = PSODesc.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(); + VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount); + const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex]; + + this->m_Desc.GraphicsPipeline.NumRenderTargets = static_cast(Subpass.RenderTargetAttachmentCount); + for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt) + { + const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt]; + if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); + this->m_Desc.GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; + } + } + + if (Subpass.pDepthStencilAttachment != nullptr) + { + const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment; + if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); + this->m_Desc.GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; + } + } + } + + const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout; + LayoutElement* pLayoutElements = nullptr; + if (InputLayout.NumElements > 0) + { + pLayoutElements = ALLOCATE(GetRawAllocator(), "Raw memory for input layout elements", LayoutElement, InputLayout.NumElements); + } + for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem) + { + pLayoutElements[Elem] = InputLayout.LayoutElements[Elem]; + pLayoutElements[Elem].HLSLSemantic = m_StringPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic); + } + this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements; + + + // Correct description and compute offsets and tight strides + std::array Strides, TightStrides = {}; + // Set all strides to an invalid value because an application may want to use 0 stride + for (auto& Stride : Strides) + Stride = LAYOUT_ELEMENT_AUTO_STRIDE; + + for (Uint32 i = 0; i < InputLayout.NumElements; ++i) + { + auto& LayoutElem = pLayoutElements[i]; + + if (LayoutElem.ValueType == VT_FLOAT32 || LayoutElem.ValueType == VT_FLOAT16) + LayoutElem.IsNormalized = false; // Floating point values cannot be normalized + + auto BuffSlot = LayoutElem.BufferSlot; + if (BuffSlot >= Strides.size()) + { + UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds maximum allowed value (", Strides.size() - 1, ")"); + continue; + } + m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, BuffSlot + 1); + + auto& CurrAutoStride = TightStrides[BuffSlot]; + // If offset is not explicitly specified, use current auto stride value + if (LayoutElem.RelativeOffset == LAYOUT_ELEMENT_AUTO_OFFSET) + { + LayoutElem.RelativeOffset = CurrAutoStride; + } + + // If stride is explicitly specified, use it for the current buffer slot + if (LayoutElem.Stride != LAYOUT_ELEMENT_AUTO_STRIDE) + { + // Verify that the value is consistent with the previously specified stride, if any + if (Strides[BuffSlot] != LAYOUT_ELEMENT_AUTO_STRIDE && Strides[BuffSlot] != LayoutElem.Stride) + { + LOG_ERROR_MESSAGE("Inconsistent strides are specified for buffer slot ", BuffSlot, + ". Input element at index ", LayoutElem.InputIndex, " explicitly specifies stride ", + LayoutElem.Stride, ", while current value is ", Strides[BuffSlot], + ". Specify consistent strides or use LAYOUT_ELEMENT_AUTO_STRIDE to allow " + "the engine compute strides automatically."); + } + Strides[BuffSlot] = LayoutElem.Stride; + } + + CurrAutoStride = std::max(CurrAutoStride, LayoutElem.RelativeOffset + LayoutElem.NumComponents * GetValueSize(LayoutElem.ValueType)); + } + + for (Uint32 i = 0; i < InputLayout.NumElements; ++i) + { + auto& LayoutElem = pLayoutElements[i]; + + auto BuffSlot = LayoutElem.BufferSlot; + // If no input elements explicitly specified stride for this buffer slot, use automatic stride + if (Strides[BuffSlot] == LAYOUT_ELEMENT_AUTO_STRIDE) + { + Strides[BuffSlot] = TightStrides[BuffSlot]; + } + else + { + if (Strides[BuffSlot] < TightStrides[BuffSlot]) + { + LOG_ERROR_MESSAGE("Stride ", Strides[BuffSlot], " explicitly specified for slot ", BuffSlot, + " is smaller than the minimum stride ", TightStrides[BuffSlot], + " required to accomodate all input elements."); + } + } + if (LayoutElem.Stride == LAYOUT_ELEMENT_AUTO_STRIDE) + LayoutElem.Stride = Strides[BuffSlot]; + } + + if (m_BufferSlotsUsed > 0) + { + m_pStrides = ALLOCATE(GetRawAllocator(), "Raw memory for buffer strides", Uint32, m_BufferSlotsUsed); + + // Set strides for all unused slots to 0 + for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i) + { + auto Stride = Strides[i]; + m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0; + } + } + } + + void InitComputePipeline() + { + const auto& ComputePipeline = this->m_Desc.ComputePipeline; + if (ComputePipeline.pCS == nullptr) + { + LOG_ERROR_AND_THROW("Compute shader is not provided"); + } + + VALIDATE_SHADER_TYPE(ComputePipeline.pCS, SHADER_TYPE_COMPUTE, "compute"); + + m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_COMPUTE; + } + +#undef VALIDATE_SHADER_TYPE #undef LOG_PSO_ERROR_AND_THROW }; diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index 9491168d..2d22c826 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -286,7 +286,7 @@ struct PipelineStateDesc DILIGENT_DERIVE(DeviceObjectAttribs) #if DILIGENT_CPP_INTERFACE bool IsAnyGraphicsPipeline() const { return PipelineType == PIPELINE_TYPE_GRAPHICS || PipelineType == PIPELINE_TYPE_MESH; } - bool IsComputePipeline () const { return PipelineType == PIPELINE_TYPE_COMPUTE; } + bool IsComputePipeline() const { return PipelineType == PIPELINE_TYPE_COMPUTE; } #endif }; typedef struct PipelineStateDesc PipelineStateDesc; -- cgit v1.2.3 From 91aac63f651da1079be93d2fe722cd10e4e15570 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 10 Oct 2020 19:28:54 -0700 Subject: A number of corrections for PSO refactoring --- .../GraphicsEngine/include/PipelineStateBase.hpp | 119 +++++++++------------ 1 file changed, 52 insertions(+), 67 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index 76760db5..09f1bddc 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -68,6 +68,16 @@ public: bool bIsDeviceInternal = false) : TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal} { + switch (PSODesc.PipelineType) + { + // clang-format off + case PIPELINE_TYPE_GRAPHICS: + case PIPELINE_TYPE_MESH: ValidateGraphicsPipeline(); break; + case PIPELINE_TYPE_COMPUTE: ValidateComputePipeline(); break; + default: UNEXPECTED("unknown pipeline type"); + // clang-format on + } + const auto& SrcLayout = PSODesc.ResourceLayout; size_t StringPoolSize = 0; if (SrcLayout.Variables != nullptr) @@ -88,14 +98,11 @@ public: } } - switch (PSODesc.PipelineType) + if (PSODesc.IsAnyGraphicsPipeline()) { - // clang-format off - case PIPELINE_TYPE_GRAPHICS: - case PIPELINE_TYPE_MESH: ValidateGraphicsPipeline( StringPoolSize); break; - case PIPELINE_TYPE_COMPUTE: ValidateComputePipeline( StringPoolSize); break; - default: UNEXPECTED("unknown pipeline type"); - // clang-format on + const auto& InputLayout = this->m_Desc.GraphicsPipeline.InputLayout; + for (Uint32 i = 0; i < InputLayout.NumElements; ++i) + StringPoolSize += strlen(InputLayout.LayoutElements[i].HLSLSemantic) + 1; } m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); @@ -143,8 +150,8 @@ public: { // clang-format off case PIPELINE_TYPE_GRAPHICS: - case PIPELINE_TYPE_MESH: InitGraphicsPipeline(); break; - case PIPELINE_TYPE_COMPUTE: InitComputePipeline(); break; + case PIPELINE_TYPE_MESH: InitGraphicsPipeline(); break; + case PIPELINE_TYPE_COMPUTE: InitComputePipeline(); break; default: UNEXPECTED("unknown pipeline type"); // clang-format on } @@ -201,8 +208,8 @@ public: return m_BufferSlotsUsed; } - SHADER_TYPE const* GetShaderTypes() const { return m_pShaderTypes.data(); } - Uint32 GetNumShaderTypes() const { return m_NumShaderTypes; } + SHADER_TYPE GetShaderStageType(Uint32 Stage) const { return m_ShaderStageTypes[Stage]; } + Uint32 GetNumShaderStages() const { return m_NumShaderStages; } // This function only compares shader resource layout hashes, so // it can potentially give false negatives @@ -219,10 +226,12 @@ protected: RefCntAutoPtr m_pRenderPass; ///< Strong reference to the render pass object - Uint8 m_NumShaderTypes = 0; ///< Number of shader types that this PSO uses + 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 = {}; - std::array m_pShaderTypes = {}; ///< Array of shader types used by this PSO - size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout + size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout 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__) @@ -287,51 +296,50 @@ protected: return LayoutInd; } -public: - using ShaderStages_t = std::vector>; protected: - void ExtractShaders(ShaderStages_t& ShaderStages) + template + void ExtractShaders(TShaderStages& ShaderStages) { + 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; + + // Reset shader pointers in PSO desc because we don't keep strong references to shaders. + pShader = nullptr; + } + }; + auto& Desc = this->m_Desc; switch (Desc.PipelineType) { case PIPELINE_TYPE_COMPUTE: { - if (Desc.ComputePipeline.pCS) ShaderStages.push_back({SHADER_TYPE_COMPUTE, Desc.ComputePipeline.pCS}); - - // reset shader pointers because we don't keep strong references to shaders - Desc.ComputePipeline.pCS = nullptr; + AddShaderStage(Desc.ComputePipeline.pCS); break; } case PIPELINE_TYPE_GRAPHICS: { - if (Desc.GraphicsPipeline.pVS) ShaderStages.push_back({SHADER_TYPE_VERTEX, Desc.GraphicsPipeline.pVS}); - if (Desc.GraphicsPipeline.pHS) ShaderStages.push_back({SHADER_TYPE_HULL, Desc.GraphicsPipeline.pHS}); - if (Desc.GraphicsPipeline.pDS) ShaderStages.push_back({SHADER_TYPE_DOMAIN, Desc.GraphicsPipeline.pDS}); - if (Desc.GraphicsPipeline.pGS) ShaderStages.push_back({SHADER_TYPE_GEOMETRY, Desc.GraphicsPipeline.pGS}); - if (Desc.GraphicsPipeline.pPS) ShaderStages.push_back({SHADER_TYPE_PIXEL, Desc.GraphicsPipeline.pPS}); - - // reset shader pointers because we don't keep strong references to shaders - Desc.GraphicsPipeline.pVS = nullptr; - Desc.GraphicsPipeline.pHS = nullptr; - Desc.GraphicsPipeline.pDS = nullptr; - Desc.GraphicsPipeline.pGS = nullptr; - Desc.GraphicsPipeline.pPS = nullptr; + AddShaderStage(Desc.GraphicsPipeline.pVS); + AddShaderStage(Desc.GraphicsPipeline.pHS); + AddShaderStage(Desc.GraphicsPipeline.pDS); + AddShaderStage(Desc.GraphicsPipeline.pGS); + AddShaderStage(Desc.GraphicsPipeline.pPS); break; } case PIPELINE_TYPE_MESH: { - if (Desc.GraphicsPipeline.pAS) ShaderStages.push_back({SHADER_TYPE_AMPLIFICATION, Desc.GraphicsPipeline.pAS}); - if (Desc.GraphicsPipeline.pMS) ShaderStages.push_back({SHADER_TYPE_MESH, Desc.GraphicsPipeline.pMS}); - if (Desc.GraphicsPipeline.pPS) ShaderStages.push_back({SHADER_TYPE_PIXEL, Desc.GraphicsPipeline.pPS}); - - // reset shader pointers because we don't keep strong references to shaders - Desc.GraphicsPipeline.pAS = nullptr; - Desc.GraphicsPipeline.pMS = nullptr; - Desc.GraphicsPipeline.pPS = nullptr; + AddShaderStage(Desc.GraphicsPipeline.pAS); + AddShaderStage(Desc.GraphicsPipeline.pMS); + AddShaderStage(Desc.GraphicsPipeline.pPS); break; } @@ -339,14 +347,7 @@ protected: UNEXPECTED("unknown pipeline type"); } -#ifdef DILIGENT_DEVELOPMENT - VERIFY_EXPR(ShaderStages.size() == m_NumShaderTypes); - - for (Uint32 s = 0; s < m_NumShaderTypes; ++s) - { - VERIFY_EXPR(ShaderStages[s].first == m_pShaderTypes[s]); - } -#endif + VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); } @@ -448,7 +449,7 @@ private: } } - void ValidateGraphicsPipeline(size_t& StringPoolSize) + void ValidateGraphicsPipeline() { const auto& GraphicsPipeline = this->m_Desc.GraphicsPipeline; if (GraphicsPipeline.pRenderPass != nullptr) @@ -477,13 +478,9 @@ private: CheckAndCorrectBlendStateDesc(); CheckRasterizerStateDesc(); CheckAndCorrectDepthStencilDesc(); - - const auto& InputLayout = this->m_Desc.GraphicsPipeline.InputLayout; - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - StringPoolSize += strlen(InputLayout.LayoutElements[i].HLSLSemantic) + 1; } - void ValidateComputePipeline(size_t& StringPoolSize) + void ValidateComputePipeline() { if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr) { @@ -527,16 +524,6 @@ private: "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)"); } - if (GraphicsPipeline.pVS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_VERTEX; - if (GraphicsPipeline.pHS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_HULL; - if (GraphicsPipeline.pDS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_DOMAIN; - if (GraphicsPipeline.pGS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_GEOMETRY; - if (GraphicsPipeline.pAS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_AMPLIFICATION; - if (GraphicsPipeline.pMS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_MESH; - if (GraphicsPipeline.pPS) m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_PIXEL; - - DEV_CHECK_ERR(m_NumShaderTypes > 0, "There must be at least one shader in the Pipeline State"); - m_pRenderPass = PSODesc.GraphicsPipeline.pRenderPass; for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt) @@ -682,8 +669,6 @@ private: } VALIDATE_SHADER_TYPE(ComputePipeline.pCS, SHADER_TYPE_COMPUTE, "compute"); - - m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_COMPUTE; } #undef VALIDATE_SHADER_TYPE -- cgit v1.2.3 From b3fec8bd40e80115086281bce74774617aa95e23 Mon Sep 17 00:00:00 2001 From: assiduous Date: Wed, 14 Oct 2020 01:04:05 -0700 Subject: Added buffer mode validation when binding buffer views --- Graphics/GraphicsEngine/include/BufferBase.hpp | 10 +++++++++- Graphics/GraphicsEngine/include/TextureBase.hpp | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/BufferBase.hpp b/Graphics/GraphicsEngine/include/BufferBase.hpp index 9ae6db92..605bc2ed 100644 --- a/Graphics/GraphicsEngine/include/BufferBase.hpp +++ b/Graphics/GraphicsEngine/include/BufferBase.hpp @@ -30,12 +30,14 @@ /// \file /// Implementation of the Diligent::BufferBase template class +#include + #include "Buffer.h" #include "GraphicsTypes.h" #include "DeviceObjectBase.hpp" #include "GraphicsAccessories.hpp" #include "STDAllocator.hpp" -#include +#include "FormatString.hpp" namespace Diligent { @@ -232,6 +234,9 @@ void BufferBasem_Desc.Name, '\''); + ViewDesc.Name = UAVName.c_str(); + IBufferView* pUAV = nullptr; CreateViewInternal(ViewDesc, &pUAV, true); m_pDefaultUAV.reset(static_cast(pUAV)); @@ -242,6 +247,9 @@ void BufferBasem_Desc.Name, '\''); + ViewDesc.Name = SRVName.c_str(); + IBufferView* pSRV = nullptr; CreateViewInternal(ViewDesc, &pSRV, true); m_pDefaultSRV.reset(static_cast(pSRV)); diff --git a/Graphics/GraphicsEngine/include/TextureBase.hpp b/Graphics/GraphicsEngine/include/TextureBase.hpp index 1805f7d3..559df1ea 100644 --- a/Graphics/GraphicsEngine/include/TextureBase.hpp +++ b/Graphics/GraphicsEngine/include/TextureBase.hpp @@ -30,13 +30,14 @@ /// \file /// Implementation of the Diligent::TextureBase template class +#include + #include "Texture.h" #include "GraphicsTypes.h" #include "DeviceObjectBase.hpp" #include "GraphicsAccessories.hpp" #include "STDAllocator.hpp" #include "FormatString.hpp" -#include namespace Diligent { -- cgit v1.2.3 From 259a9d5897937dcaaca1b4b294bb8d5250371e76 Mon Sep 17 00:00:00 2001 From: azhirnov Date: Thu, 15 Oct 2020 20:55:38 +0300 Subject: Added GraphicsPipelineCreateInfo and ComputePipelineCreateInfo instead of single PipelineCreateInfo. Some optimizations for dynamic memory allocations in PipelineState. --- .../GraphicsEngine/include/DeviceContextBase.hpp | 2 +- .../GraphicsEngine/include/PipelineStateBase.hpp | 439 ++++++++++----------- Graphics/GraphicsEngine/interface/InputLayout.h | 2 +- Graphics/GraphicsEngine/interface/PipelineState.h | 89 +++-- Graphics/GraphicsEngine/interface/RenderDevice.h | 49 ++- Graphics/GraphicsEngine/src/APIInfo.cpp | 1 - 6 files changed, 296 insertions(+), 286 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 86cccc7b..90285834 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -1678,7 +1678,7 @@ inline void DeviceContextBase:: BoundDSVFormat = m_pBoundDepthStencil ? m_pBoundDepthStencil->GetDesc().Format : TEX_FORMAT_UNKNOWN; const auto& PSODesc = m_pPipelineState->GetDesc(); - const auto& GraphicsPipeline = PSODesc.GraphicsPipeline; + const auto& GraphicsPipeline = m_pPipelineState->GetGraphicsPipelineDesc(); if (GraphicsPipeline.NumRenderTargets != m_NumBoundRenderTargets) { LOG_WARNING_MESSAGE("The number of currently bound render targets (", m_NumBoundRenderTargets, diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index 09f1bddc..d8cb09bb 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -38,7 +38,7 @@ #include "STDAllocator.hpp" #include "EngineMemory.h" #include "GraphicsAccessories.hpp" -#include "StringPool.hpp" +#include "LinearAllocator.hpp" namespace Diligent { @@ -59,7 +59,7 @@ public: /// \param pRefCounters - reference counters object that controls the lifetime of this PSO /// \param pDevice - pointer to the device. - /// \param PSODesc - pipeline state description. + /// \param CreateInfo - graphics 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, @@ -68,96 +68,6 @@ public: bool bIsDeviceInternal = false) : TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal} { - switch (PSODesc.PipelineType) - { - // clang-format off - case PIPELINE_TYPE_GRAPHICS: - case PIPELINE_TYPE_MESH: ValidateGraphicsPipeline(); break; - case PIPELINE_TYPE_COMPUTE: ValidateComputePipeline(); break; - default: UNEXPECTED("unknown pipeline type"); - // clang-format on - } - - const auto& SrcLayout = PSODesc.ResourceLayout; - size_t StringPoolSize = 0; - if (SrcLayout.Variables != nullptr) - { - for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) - { - VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null"); - StringPoolSize += strlen(SrcLayout.Variables[i].Name) + 1; - } - } - - if (SrcLayout.StaticSamplers != nullptr) - { - for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) - { - VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null"); - StringPoolSize += strlen(SrcLayout.StaticSamplers[i].SamplerOrTextureName) + 1; - } - } - - if (PSODesc.IsAnyGraphicsPipeline()) - { - const auto& InputLayout = this->m_Desc.GraphicsPipeline.InputLayout; - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - StringPoolSize += strlen(InputLayout.LayoutElements[i].HLSLSemantic) + 1; - } - - m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); - - auto& DstLayout = this->m_Desc.ResourceLayout; - if (SrcLayout.Variables != nullptr) - { - ShaderResourceVariableDesc* Variables = - ALLOCATE(GetRawAllocator(), "Memory for ShaderResourceVariableDesc array", ShaderResourceVariableDesc, SrcLayout.NumVariables); - DstLayout.Variables = Variables; - for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) - { - Variables[i] = SrcLayout.Variables[i]; - Variables[i].Name = m_StringPool.CopyString(SrcLayout.Variables[i].Name); - } - } - - if (SrcLayout.StaticSamplers != nullptr) - { - StaticSamplerDesc* StaticSamplers = - ALLOCATE(GetRawAllocator(), "Memory for StaticSamplerDesc array", 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 = m_StringPool.CopyString(SrcLayout.StaticSamplers[i].SamplerOrTextureName); - } - } - - switch (PSODesc.PipelineType) - { - // clang-format off - case PIPELINE_TYPE_GRAPHICS: - case PIPELINE_TYPE_MESH: InitGraphicsPipeline(); break; - case PIPELINE_TYPE_COMPUTE: InitComputePipeline(); break; - default: UNEXPECTED("unknown pipeline type"); - // clang-format on - } - - VERIFY_EXPR(m_StringPool.GetRemainingSize() == 0); - Uint64 DeviceQueuesMask = pDevice->GetCommandQueueMask(); DEV_CHECK_ERR((this->m_Desc.CommandQueueMask & DeviceQueuesMask) != 0, "No bits in the command queue mask (0x", std::hex, this->m_Desc.CommandQueueMask, @@ -184,16 +94,6 @@ public: RasterizerStateRegistry.ReportDeletedObject(); DSSRegistry.ReportDeletedObject(); */ - - auto& RawAllocator = GetRawAllocator(); - if (this->m_Desc.ResourceLayout.Variables != nullptr) - RawAllocator.Free(const_cast(this->m_Desc.ResourceLayout.Variables)); - if (this->m_Desc.ResourceLayout.StaticSamplers != nullptr) - RawAllocator.Free(const_cast(this->m_Desc.ResourceLayout.StaticSamplers)); - if (this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements != nullptr) - RawAllocator.Free(const_cast(this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements)); - if (m_pStrides != nullptr) - RawAllocator.Free(m_pStrides); } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineState, TDeviceObjectBase) @@ -218,20 +118,28 @@ public: return m_ShaderResourceLayoutHash != ValidatedCast(pPSO)->m_ShaderResourceLayoutHash; } -protected: - Uint32 m_BufferSlotsUsed = 0; - Uint32* m_pStrides = nullptr; + const GraphicsPipelineDesc& GetGraphicsPipelineDesc() const override final + { + VERIFY_EXPR(this->m_Desc.IsAnyGraphicsPipeline()); + VERIFY_EXPR(m_pGraphicsPipelineDesc != nullptr); + return *m_pGraphicsPipelineDesc; + } - StringPool m_StringPool; - RefCntAutoPtr m_pRenderPass; ///< Strong reference to the render pass object +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 = {}; - size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout + 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__) @@ -296,74 +204,19 @@ protected: return LayoutInd; } - -protected: - template - void ExtractShaders(TShaderStages& ShaderStages) - { - 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; - - // Reset shader pointers in PSO desc because we don't keep strong references to shaders. - pShader = nullptr; - } - }; - - auto& Desc = this->m_Desc; - switch (Desc.PipelineType) - { - case PIPELINE_TYPE_COMPUTE: - { - AddShaderStage(Desc.ComputePipeline.pCS); - break; - } - - case PIPELINE_TYPE_GRAPHICS: - { - AddShaderStage(Desc.GraphicsPipeline.pVS); - AddShaderStage(Desc.GraphicsPipeline.pHS); - AddShaderStage(Desc.GraphicsPipeline.pDS); - AddShaderStage(Desc.GraphicsPipeline.pGS); - AddShaderStage(Desc.GraphicsPipeline.pPS); - break; - } - - case PIPELINE_TYPE_MESH: - { - AddShaderStage(Desc.GraphicsPipeline.pAS); - AddShaderStage(Desc.GraphicsPipeline.pMS); - AddShaderStage(Desc.GraphicsPipeline.pPS); - break; - } - - default: - UNEXPECTED("unknown pipeline type"); - } - - VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); - } - - private: - void CheckRasterizerStateDesc() const + void CheckRasterizerStateDesc(GraphicsPipelineDesc& GraphicsPipeline) const { - const auto& RSDesc = this->m_Desc.GraphicsPipeline.RasterizerDesc; + 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() + void CheckAndCorrectDepthStencilDesc(GraphicsPipelineDesc& GraphicsPipeline) const { - auto& DSSDesc = this->m_Desc.GraphicsPipeline.DepthStencilDesc; + auto& DSSDesc = GraphicsPipeline.DepthStencilDesc; if (DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN) { if (DSSDesc.DepthEnable) @@ -401,9 +254,9 @@ private: CheckAndCorrectStencilOpDesc(DSSDesc.BackFace, "BackFace"); } - void CheckAndCorrectBlendStateDesc() + void CheckAndCorrectBlendStateDesc(GraphicsPipelineDesc& GraphicsPipeline) const { - auto& BlendDesc = this->m_Desc.GraphicsPipeline.BlendDesc; + auto& BlendDesc = GraphicsPipeline.BlendDesc; for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt) { auto& RTDesc = BlendDesc.RenderTargets[rt]; @@ -449,9 +302,31 @@ private: } } - void ValidateGraphicsPipeline() + 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 { - const auto& GraphicsPipeline = this->m_Desc.GraphicsPipeline; if (GraphicsPipeline.pRenderPass != nullptr) { if (GraphicsPipeline.NumRenderTargets != 0) @@ -475,48 +350,182 @@ private: LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used"); } - CheckAndCorrectBlendStateDesc(); - CheckRasterizerStateDesc(); - CheckAndCorrectDepthStencilDesc(); + const auto& InputLayout = GraphicsPipeline.InputLayout; + Uint32 BufferSlotsUsed = 0; + MemPool.AddRequiredSize(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 ValidateComputePipeline() + void InitResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) const { - if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr) + if (SrcLayout.Variables != nullptr) { - LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null for compute pipelines"); + 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); + } } - DEV_CHECK_ERR(this->m_Desc.GraphicsPipeline.InputLayout.NumElements == 0, "Compute pipelines must not have input layout elements"); } +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"); \ } - void InitGraphicsPipeline() + void ValidateAndReserveSpace(const GraphicsPipelineStateCreateInfo& 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); + } + + 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, + TShaderStages& ShaderStages) + { + 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; + } + }; + + switch (CreateInfo.PSODesc.PipelineType) + { + case PIPELINE_TYPE_GRAPHICS: + { + AddShaderStage(CreateInfo.pVS); + AddShaderStage(CreateInfo.pHS); + AddShaderStage(CreateInfo.pDS); + AddShaderStage(CreateInfo.pGS); + AddShaderStage(CreateInfo.pPS); + break; + } + + case PIPELINE_TYPE_MESH: + { + AddShaderStage(CreateInfo.pAS); + AddShaderStage(CreateInfo.pMS); + AddShaderStage(CreateInfo.pPS); + break; + } + + default: + UNEXPECTED("unknown pipeline type"); + } + + VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); + } + + template + void ExtractShaders(const ComputePipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages) + { + 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(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); + } + + + void InitGraphicsPipeline(const GraphicsPipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) + { + this->m_pGraphicsPipelineDesc = MemPool.CopyArray(&CreateInfo.GraphicsPipeline, 1); + + InitResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool); + + auto& GraphicsPipeline = *this->m_pGraphicsPipelineDesc; const auto& PSODesc = this->m_Desc; - const auto& GraphicsPipeline = PSODesc.GraphicsPipeline; - VALIDATE_SHADER_TYPE(GraphicsPipeline.pVS, SHADER_TYPE_VERTEX, "vertex") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pPS, SHADER_TYPE_PIXEL, "pixel") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pGS, SHADER_TYPE_GEOMETRY, "geometry") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pHS, SHADER_TYPE_HULL, "hull") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pDS, SHADER_TYPE_DOMAIN, "domain") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pAS, SHADER_TYPE_AMPLIFICATION, "amplification") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pMS, SHADER_TYPE_MESH, "mesh") + CheckAndCorrectBlendStateDesc(GraphicsPipeline); + CheckRasterizerStateDesc(GraphicsPipeline); + CheckAndCorrectDepthStencilDesc(GraphicsPipeline); if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) { - DEV_CHECK_ERR(GraphicsPipeline.pVS, "Vertex shader must be defined"); - DEV_CHECK_ERR(!GraphicsPipeline.pAS && !GraphicsPipeline.pMS, "Mesh shaders are not supported in graphics pipeline"); + 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(GraphicsPipeline.pMS, "Mesh shader must be defined"); - DEV_CHECK_ERR(!GraphicsPipeline.pVS && !GraphicsPipeline.pGS && !GraphicsPipeline.pDS && !GraphicsPipeline.pHS, + 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 || @@ -524,7 +533,7 @@ private: "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)"); } - m_pRenderPass = PSODesc.GraphicsPipeline.pRenderPass; + m_pRenderPass = GraphicsPipeline.pRenderPass; for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt) { @@ -542,14 +551,14 @@ private: VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount); const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex]; - this->m_Desc.GraphicsPipeline.NumRenderTargets = static_cast(Subpass.RenderTargetAttachmentCount); + GraphicsPipeline.NumRenderTargets = static_cast(Subpass.RenderTargetAttachmentCount); for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt) { const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt]; if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) { VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); - this->m_Desc.GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; + GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; } } @@ -559,23 +568,19 @@ private: if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) { VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); - this->m_Desc.GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; + GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; } } } - const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout; - LayoutElement* pLayoutElements = nullptr; - if (InputLayout.NumElements > 0) - { - pLayoutElements = ALLOCATE(GetRawAllocator(), "Raw memory for input layout elements", LayoutElement, InputLayout.NumElements); - } + const auto& InputLayout = GraphicsPipeline.InputLayout; + LayoutElement* pLayoutElements = MemPool.Allocate(InputLayout.NumElements); for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem) { pLayoutElements[Elem] = InputLayout.LayoutElements[Elem]; - pLayoutElements[Elem].HLSLSemantic = m_StringPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic); + pLayoutElements[Elem].HLSLSemantic = MemPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic); } - this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements; + GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements; // Correct description and compute offsets and tight strides @@ -597,7 +602,7 @@ private: UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds maximum allowed value (", Strides.size() - 1, ")"); continue; } - m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, BuffSlot + 1); + m_BufferSlotsUsed = static_cast(std::max(m_BufferSlotsUsed, BuffSlot + 1)); auto& CurrAutoStride = TightStrides[BuffSlot]; // If offset is not explicitly specified, use current auto stride value @@ -647,28 +652,20 @@ private: LayoutElem.Stride = Strides[BuffSlot]; } - if (m_BufferSlotsUsed > 0) - { - m_pStrides = ALLOCATE(GetRawAllocator(), "Raw memory for buffer strides", Uint32, m_BufferSlotsUsed); + m_pStrides = MemPool.Allocate(m_BufferSlotsUsed); - // Set strides for all unused slots to 0 - for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i) - { - auto Stride = Strides[i]; - m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0; - } + // Set strides for all unused slots to 0 + for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i) + { + auto Stride = Strides[i]; + m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0; } } - void InitComputePipeline() + void InitComputePipeline(const ComputePipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) { - const auto& ComputePipeline = this->m_Desc.ComputePipeline; - if (ComputePipeline.pCS == nullptr) - { - LOG_ERROR_AND_THROW("Compute shader is not provided"); - } - - VALIDATE_SHADER_TYPE(ComputePipeline.pCS, SHADER_TYPE_COMPUTE, "compute"); + InitResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool); } #undef VALIDATE_SHADER_TYPE diff --git a/Graphics/GraphicsEngine/interface/InputLayout.h b/Graphics/GraphicsEngine/interface/InputLayout.h index 19904974..c7b18965 100644 --- a/Graphics/GraphicsEngine/interface/InputLayout.h +++ b/Graphics/GraphicsEngine/interface/InputLayout.h @@ -179,7 +179,7 @@ typedef struct LayoutElement LayoutElement; /// Layout description -/// This structure is used by IRenderDevice::CreatePipelineState(). +/// This structure is used by IRenderDevice::CreateGraphicsPipelineState(). struct InputLayoutDesc { /// Array of layout elements diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index 2d22c826..e5682e58 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -151,29 +151,6 @@ typedef struct PipelineResourceLayoutDesc PipelineResourceLayoutDesc; /// This structure describes the graphics pipeline state and is part of the PipelineStateDesc structure. struct GraphicsPipelineDesc { - /// Vertex shader to be used with the pipeline. - IShader* pVS DEFAULT_INITIALIZER(nullptr); - - /// Pixel shader to be used with the pipeline. - IShader* pPS DEFAULT_INITIALIZER(nullptr); - - /// Domain shader to be used with the pipeline. - IShader* pDS DEFAULT_INITIALIZER(nullptr); - - /// Hull shader to be used with the pipeline. - IShader* pHS DEFAULT_INITIALIZER(nullptr); - - /// Geometry shader to be used with the pipeline. - IShader* pGS DEFAULT_INITIALIZER(nullptr); - - /// Amplification shader to be used with the pipeline. - IShader* pAS DEFAULT_INITIALIZER(nullptr); - - /// Mesh shader to be used with the pipeline. - IShader* pMS DEFAULT_INITIALIZER(nullptr); - - //D3D12_STREAM_OUTPUT_DESC StreamOutput; - /// Blend state description. BlendStateDesc BlendDesc; @@ -234,17 +211,6 @@ struct GraphicsPipelineDesc typedef struct GraphicsPipelineDesc GraphicsPipelineDesc; -/// Compute pipeline state description - -/// This structure describes the compute pipeline state and is part of the PipelineStateDesc structure. -struct ComputePipelineDesc -{ - /// Compute shader to be used with the pipeline - IShader* pCS DEFAULT_INITIALIZER(nullptr); -}; -typedef struct ComputePipelineDesc ComputePipelineDesc; - - /// Pipeline type DILIGENT_TYPED_ENUM(PIPELINE_TYPE, Uint8) { @@ -278,12 +244,6 @@ struct PipelineStateDesc DILIGENT_DERIVE(DeviceObjectAttribs) /// Pipeline layout description PipelineResourceLayoutDesc ResourceLayout; - /// Graphics pipeline state description. This memeber is ignored if PipelineType is not PIPELINE_TYPE_GRAPHICS or PIPELINE_TYPE_MESH - GraphicsPipelineDesc GraphicsPipeline; - - /// Compute pipeline state description. This memeber is ignored if PipelineType is not PIPELINE_TYPE_COMPUTE - ComputePipelineDesc ComputePipeline; - #if DILIGENT_CPP_INTERFACE bool IsAnyGraphicsPipeline() const { return PipelineType == PIPELINE_TYPE_GRAPHICS || PipelineType == PIPELINE_TYPE_MESH; } bool IsComputePipeline() const { return PipelineType == PIPELINE_TYPE_COMPUTE; } @@ -324,10 +284,50 @@ struct PipelineStateCreateInfo PipelineStateDesc PSODesc; /// Pipeline state creation flags, see Diligent::PSO_CREATE_FLAGS. - PSO_CREATE_FLAGS Flags DEFAULT_INITIALIZER(PSO_CREATE_FLAG_NONE); + PSO_CREATE_FLAGS Flags DEFAULT_INITIALIZER(PSO_CREATE_FLAG_NONE); }; typedef struct PipelineStateCreateInfo PipelineStateCreateInfo; + +/// Graphics pipeline state creation attributes +struct GraphicsPipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo) + + /// Graphics pipeline state description. + GraphicsPipelineDesc GraphicsPipeline; + + /// Vertex shader to be used with the pipeline. + IShader* pVS DEFAULT_INITIALIZER(nullptr); + + /// Pixel shader to be used with the pipeline. + IShader* pPS DEFAULT_INITIALIZER(nullptr); + + /// Domain shader to be used with the pipeline. + IShader* pDS DEFAULT_INITIALIZER(nullptr); + + /// Hull shader to be used with the pipeline. + IShader* pHS DEFAULT_INITIALIZER(nullptr); + + /// Geometry shader to be used with the pipeline. + IShader* pGS DEFAULT_INITIALIZER(nullptr); + + /// Amplification shader to be used with the pipeline. + IShader* pAS DEFAULT_INITIALIZER(nullptr); + + /// Mesh shader to be used with the pipeline. + IShader* pMS DEFAULT_INITIALIZER(nullptr); +}; +typedef struct GraphicsPipelineStateCreateInfo GraphicsPipelineStateCreateInfo; + + +/// Compute pipeline state description. +struct ComputePipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo) + + /// Compute shader to be used with the pipeline + IShader* pCS DEFAULT_INITIALIZER(nullptr); +}; +typedef struct ComputePipelineStateCreateInfo ComputePipelineStateCreateInfo; + + // {06084AE5-6A71-4FE8-84B9-395DD489A28C} static const struct INTERFACE_ID IID_PipelineState = {0x6084ae5, 0x6a71, 0x4fe8, {0x84, 0xb9, 0x39, 0x5d, 0xd4, 0x89, 0xa2, 0x8c}}; @@ -345,10 +345,12 @@ static const struct INTERFACE_ID IID_PipelineState = DILIGENT_BEGIN_INTERFACE(IPipelineState, IDeviceObject) { #if DILIGENT_CPP_INTERFACE - /// Returns the blend state description used to create the object - virtual const PipelineStateDesc& METHOD(GetDesc)()const override = 0; + /// Returns the pipeline description used to create the object + virtual const PipelineStateDesc& METHOD(GetDesc)() const override = 0; #endif + /// Returns the graphics pipeline description used to create the object + VIRTUAL const GraphicsPipelineDesc REF METHOD(GetGraphicsPipelineDesc)(THIS) CONST PURE; /// Binds resources for all shaders in the pipeline state @@ -438,6 +440,7 @@ DILIGENT_END_INTERFACE # define IPipelineState_GetDesc(This) (const struct PipelineStateDesc*)IDeviceObject_GetDesc(This) +# define IPipelineState_GetGraphicsPipelineDesc(This) CALL_IFACE_METHOD(PipelineState, GetGraphicsPipelineDesc, This) # define IPipelineState_BindStaticResources(This, ...) CALL_IFACE_METHOD(PipelineState, BindStaticResources, This, __VA_ARGS__) # define IPipelineState_GetStaticVariableCount(This, ...) CALL_IFACE_METHOD(PipelineState, GetStaticVariableCount, This, __VA_ARGS__) # define IPipelineState_GetStaticVariableByName(This, ...) CALL_IFACE_METHOD(PipelineState, GetStaticVariableByName, This, __VA_ARGS__) diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h index 0cea79eb..ea4e05af 100644 --- a/Graphics/GraphicsEngine/interface/RenderDevice.h +++ b/Graphics/GraphicsEngine/interface/RenderDevice.h @@ -153,17 +153,27 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) const ResourceMappingDesc REF MappingDesc, IResourceMapping** ppMapping) PURE; - /// Creates a new pipeline state object + /// Creates a new graphics pipeline state object - /// \param [in] PSOCreateInfo - Pipeline state create info, see Diligent::PipelineStateCreateInfo for details. + /// \param [in] PSOCreateInfo - 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 /// one reference. - VIRTUAL void METHOD(CreatePipelineState)(THIS_ - const PipelineStateCreateInfo REF PSOCreateInfo, - IPipelineState** ppPipelineState) PURE; + VIRTUAL void METHOD(CreateGraphicsPipelineState)(THIS_ + const GraphicsPipelineStateCreateInfo REF PSOCreateInfo, + IPipelineState** ppPipelineState) PURE; + + /// Creates a new compute pipeline state object + /// \param [in] PSOCreateInfo - 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 + /// one reference. + VIRTUAL void METHOD(CreateComputePipelineState)(THIS_ + const ComputePipelineStateCreateInfo REF PSOCreateInfo, + IPipelineState** ppPipelineState) PURE; /// Creates a new fence object @@ -273,20 +283,21 @@ DILIGENT_END_INTERFACE // clang-format off -# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__) -# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__) -# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__) -# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__) -# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__) -# define IRenderDevice_CreatePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineState, This, __VA_ARGS__) -# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__) -# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__) -# define IRenderDevice_GetDeviceCaps(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceCaps, This) -# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__) -# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt,This, __VA_ARGS__) -# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__) -# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This) -# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This) +# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__) +# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__) +# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__) +# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__) +# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__) +# define IRenderDevice_CreateGraphicsPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateGraphicsPipelineState, This, __VA_ARGS__) +# define IRenderDevice_CreateComputePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateComputePipelineState, This, __VA_ARGS__) +# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__) +# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__) +# define IRenderDevice_GetDeviceCaps(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceCaps, This) +# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__) +# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt, This, __VA_ARGS__) +# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__) +# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This) +# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This) // clang-format on diff --git a/Graphics/GraphicsEngine/src/APIInfo.cpp b/Graphics/GraphicsEngine/src/APIInfo.cpp index f71b943e..05aef568 100644 --- a/Graphics/GraphicsEngine/src/APIInfo.cpp +++ b/Graphics/GraphicsEngine/src/APIInfo.cpp @@ -90,7 +90,6 @@ static APIInfo InitAPIInfo() INIT_STRUCTURE_SIZE(StaticSamplerDesc); INIT_STRUCTURE_SIZE(PipelineResourceLayoutDesc); INIT_STRUCTURE_SIZE(GraphicsPipelineDesc); - INIT_STRUCTURE_SIZE(ComputePipelineDesc); INIT_STRUCTURE_SIZE(PipelineStateDesc); INIT_STRUCTURE_SIZE(RasterizerStateDesc); INIT_STRUCTURE_SIZE(ResourceMappingEntry); -- cgit v1.2.3 From e7b18160a758b30dd6b701b4aa6f43c9c2061ccf Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 17 Oct 2020 09:56:34 -0700 Subject: All backends: added resource dimension validation when setting shader variables --- .../include/ShaderResourceVariableBase.hpp | 61 ++++++++++++++++++++-- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 20 +++---- 2 files changed, 68 insertions(+), 13 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp index f82f18cf..78c1832d 100644 --- a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp @@ -215,6 +215,28 @@ inline const char* GetResourceTypeName() return "buffer view"; } +inline RESOURCE_DIMENSION GetResourceViewDimension(const ITextureView* pTexView) +{ + VERIFY_EXPR(pTexView != nullptr); + return pTexView->GetDesc().TextureDim; +} + +inline RESOURCE_DIMENSION GetResourceViewDimension(const IBufferView* /*pBuffView*/) +{ + return RESOURCE_DIM_BUFFER; +} + +inline Uint32 GetResourceSampleCount(const ITextureView* pTexView) +{ + VERIFY_EXPR(pTexView != nullptr); + return const_cast(pTexView)->GetTexture()->GetDesc().SampleCount; +} + +inline Uint32 GetResourceSampleCount(const IBufferView* /*pBuffView*/) +{ + return 0; +} + template @@ -255,8 +277,6 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs, if (!IsExpectedViewType) { - std::string ExpectedViewTypeName; - std::stringstream ss; ss << "Error binding " << ExpectedResourceType << " '" << pViewImpl->GetDesc().Name << "' to variable '" << Attribs.GetPrintName(ArrayIndex) << '\''; @@ -280,11 +300,45 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs, BindingOK = false; } + + const auto ExpectedResourceDim = Attribs.GetResourceDimension(); + if (ExpectedResourceDim != RESOURCE_DIM_UNDEFINED) + { + auto ResourceDim = GetResourceViewDimension(pViewImpl); + if (ResourceDim != ExpectedResourceDim) + { + LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '", + Attribs.GetPrintName(ArrayIndex), "': incorrect resource dimension: ", + GetResourceDimString(ExpectedResourceDim), " is expected, but the actual dimension is ", + GetResourceDimString(ResourceDim)); + + BindingOK = false; + } + + if (ResourceDim == RESOURCE_DIM_TEX_2D || ResourceDim == RESOURCE_DIM_TEX_2D_ARRAY) + { + auto SampleCount = GetResourceSampleCount(pViewImpl); + auto IsMS = Attribs.IsMultisample(); + if (IsMS && SampleCount == 1) + { + LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '", + Attribs.GetPrintName(ArrayIndex), "': multisample texture is expected."); + BindingOK = false; + } + else if (!IsMS && SampleCount > 1) + { + LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '", + Attribs.GetPrintName(ArrayIndex), "': single-sample texture is expected."); + BindingOK = false; + } + } + } } if (VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && pCachedView != nullptr && pCachedView != pViewImpl) { - auto VarTypeStr = GetShaderVariableTypeLiteralName(VarType); + const auto* VarTypeStr = GetShaderVariableTypeLiteralName(VarType); + std::stringstream ss; ss << "Non-null resource '" << pCachedView->GetDesc().Name << "' is already bound to " << VarTypeStr << " shader variable '" << Attribs.GetPrintName(ArrayIndex) << '\''; @@ -306,6 +360,7 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs, BindingOK = false; } + return BindingOK; } diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index b681c498..74e16535 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -211,16 +211,16 @@ DEFINE_FLAG_ENUM_OPERATORS(MAP_FLAGS) /// - TextureViewDesc to describe texture view type DILIGENT_TYPED_ENUM(RESOURCE_DIMENSION, Uint8) { - RESOURCE_DIM_UNDEFINED = 0, ///< Texture type undefined - RESOURCE_DIM_BUFFER, ///< Buffer - RESOURCE_DIM_TEX_1D, ///< One-dimensional texture - RESOURCE_DIM_TEX_1D_ARRAY, ///< One-dimensional texture array - RESOURCE_DIM_TEX_2D, ///< Two-dimensional texture - RESOURCE_DIM_TEX_2D_ARRAY, ///< Two-dimensional texture array - RESOURCE_DIM_TEX_3D, ///< Three-dimensional texture - RESOURCE_DIM_TEX_CUBE, ///< Cube-map texture - RESOURCE_DIM_TEX_CUBE_ARRAY, ///< Cube-map array texture - RESOURCE_DIM_NUM_DIMENSIONS ///< Helper value that stores the total number of texture types in the enumeration + RESOURCE_DIM_UNDEFINED = 0, ///< Texture type undefined + RESOURCE_DIM_BUFFER, ///< Buffer + RESOURCE_DIM_TEX_1D, ///< One-dimensional texture + RESOURCE_DIM_TEX_1D_ARRAY, ///< One-dimensional texture array + RESOURCE_DIM_TEX_2D, ///< Two-dimensional texture + RESOURCE_DIM_TEX_2D_ARRAY, ///< Two-dimensional texture array + RESOURCE_DIM_TEX_3D, ///< Three-dimensional texture + RESOURCE_DIM_TEX_CUBE, ///< Cube-map texture + RESOURCE_DIM_TEX_CUBE_ARRAY, ///< Cube-map array texture + RESOURCE_DIM_NUM_DIMENSIONS ///< Helper value that stores the total number of texture types in the enumeration }; /// Texture view type -- cgit v1.2.3 From e8f439dc0f87f6820e3db53ecd8ee41cc878d90c Mon Sep 17 00:00:00 2001 From: azhirnov Date: Sat, 17 Oct 2020 20:02:58 +0300 Subject: Fixed compilation, some fixes after review --- Graphics/GraphicsEngine/include/PipelineStateBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index d8cb09bb..ef5b38c2 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -118,7 +118,7 @@ public: return m_ShaderResourceLayoutHash != ValidatedCast(pPSO)->m_ShaderResourceLayoutHash; } - const GraphicsPipelineDesc& GetGraphicsPipelineDesc() const override final + virtual const GraphicsPipelineDesc& DILIGENT_CALL_TYPE GetGraphicsPipelineDesc() const override final { VERIFY_EXPR(this->m_Desc.IsAnyGraphicsPipeline()); VERIFY_EXPR(m_pGraphicsPipelineDesc != nullptr); -- cgit v1.2.3 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 From a520bf4f9748d20e432bcf7994be3148d0b75d54 Mon Sep 17 00:00:00 2001 From: assiduous Date: Mon, 19 Oct 2020 10:21:30 -0700 Subject: Renamed static sampler to immutable sampler (API240076) --- .../GraphicsEngine/include/PipelineStateBase.hpp | 26 ++++++------ .../include/ShaderResourceVariableBase.hpp | 14 +++---- Graphics/GraphicsEngine/interface/APIInfo.h | 4 +- Graphics/GraphicsEngine/interface/PipelineState.h | 46 ++++++++++++---------- Graphics/GraphicsEngine/src/APIInfo.cpp | 2 +- 5 files changed, 48 insertions(+), 44 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index cda2247e..c108f663 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -460,13 +460,13 @@ private: } } - if (SrcLayout.StaticSamplers != nullptr) + if (SrcLayout.ImmutableSamplers != nullptr) { - MemPool.AddSpace(SrcLayout.NumStaticSamplers); - for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) + MemPool.AddSpace(SrcLayout.NumImmutableSamplers); + for (Uint32 i = 0; i < SrcLayout.NumImmutableSamplers; ++i) { - VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null"); - MemPool.AddSpaceForString(SrcLayout.StaticSamplers[i].SamplerOrTextureName); + VERIFY(SrcLayout.ImmutableSamplers[i].SamplerOrTextureName != nullptr, "Immutable sampler or texture name can't be null"); + MemPool.AddSpaceForString(SrcLayout.ImmutableSamplers[i].SamplerOrTextureName); } } } @@ -485,13 +485,13 @@ private: } } - if (SrcLayout.StaticSamplers != nullptr) + if (SrcLayout.ImmutableSamplers != nullptr) { - auto* StaticSamplers = MemPool.Allocate(SrcLayout.NumStaticSamplers); - DstLayout.StaticSamplers = StaticSamplers; - for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) + auto* ImmutableSamplers = MemPool.Allocate(SrcLayout.NumImmutableSamplers); + DstLayout.ImmutableSamplers = ImmutableSamplers; + for (Uint32 i = 0; i < SrcLayout.NumImmutableSamplers; ++i) { - const auto& SrcSmplr = SrcLayout.StaticSamplers[i]; + const auto& SrcSmplr = SrcLayout.ImmutableSamplers[i]; #ifdef DILIGENT_DEVELOPMENT { const auto& BorderColor = SrcSmplr.Desc.BorderColor; @@ -499,15 +499,15 @@ private: (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 (", + LOG_WARNING_MESSAGE("Immutable 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); + ImmutableSamplers[i] = SrcSmplr; + ImmutableSamplers[i].SamplerOrTextureName = MemPool.CopyString(SrcSmplr.SamplerOrTextureName); } } } diff --git a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp index 78c1832d..1130fbff 100644 --- a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp @@ -115,15 +115,15 @@ inline Uint32 GetAllowedTypeBits(const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVar return AllowedTypeBits; } -inline Int32 FindStaticSampler(const StaticSamplerDesc* StaticSamplers, - Uint32 NumStaticSamplers, - SHADER_TYPE ShaderType, - const char* ResourceName, - const char* SamplerSuffix) +inline Int32 FindImmutableSampler(const ImmutableSamplerDesc* ImtblSamplers, + Uint32 NumImtblSamplers, + SHADER_TYPE ShaderType, + const char* ResourceName, + const char* SamplerSuffix) { - for (Uint32 s = 0; s < NumStaticSamplers; ++s) + for (Uint32 s = 0; s < NumImtblSamplers; ++s) { - const auto& StSam = StaticSamplers[s]; + const auto& StSam = ImtblSamplers[s]; if (((StSam.ShaderStages & ShaderType) != 0) && StreqSuff(ResourceName, StSam.SamplerOrTextureName, SamplerSuffix)) return s; } diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index 10cf096e..a32511d2 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 240075 +#define DILIGENT_API_VERSION 240076 #include "../../../Primitives/interface/BasicTypes.h" @@ -77,7 +77,7 @@ struct APIInfo 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 ImmutableSamplerDescSize DEFAULT_INITIALIZER(0); size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0); size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0); size_t GraphicsPipelineStateCreateInfoSize DEFAULT_INITIALIZER(0); diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index cef07c66..2d889c61 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -96,32 +96,36 @@ struct ShaderResourceVariableDesc typedef struct ShaderResourceVariableDesc ShaderResourceVariableDesc; -/// Static sampler description -struct StaticSamplerDesc +/// Immutable sampler description. + +/// An immutable sampler is compiled into the pipeline state and can't be changed. +/// It is generally more efficient than a regular sampler and should be used +/// whenever possible. +struct ImmutableSamplerDesc { - /// Shader stages that this static sampler applies to. More than one shader stage can be specified. + /// Shader stages that this immutable sampler applies to. More than one shader stage can be specified. SHADER_TYPE ShaderStages DEFAULT_INITIALIZER(SHADER_TYPE_UNKNOWN); /// The name of the sampler itself or the name of the texture variable that - /// this static sampler is assigned to if combined texture samplers are used. + /// this immutable sampler is assigned to if combined texture samplers are used. const Char* SamplerOrTextureName DEFAULT_INITIALIZER(nullptr); /// Sampler description struct SamplerDesc Desc; #if DILIGENT_CPP_INTERFACE - StaticSamplerDesc()noexcept{} + ImmutableSamplerDesc()noexcept{} - StaticSamplerDesc(SHADER_TYPE _ShaderStages, - const Char* _SamplerOrTextureName, - const SamplerDesc& _Desc)noexcept : + ImmutableSamplerDesc(SHADER_TYPE _ShaderStages, + const Char* _SamplerOrTextureName, + const SamplerDesc& _Desc)noexcept : ShaderStages {_ShaderStages }, SamplerOrTextureName{_SamplerOrTextureName}, Desc {_Desc } {} #endif }; -typedef struct StaticSamplerDesc StaticSamplerDesc; +typedef struct ImmutableSamplerDesc ImmutableSamplerDesc; /// Pipeline layout description struct PipelineResourceLayoutDesc @@ -129,19 +133,19 @@ struct PipelineResourceLayoutDesc /// Default shader resource variable type. This type will be used if shader /// variable description is not found in the Variables array /// or if Variables == nullptr - SHADER_RESOURCE_VARIABLE_TYPE DefaultVariableType DEFAULT_INITIALIZER(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + SHADER_RESOURCE_VARIABLE_TYPE DefaultVariableType DEFAULT_INITIALIZER(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); /// Number of elements in Variables array - Uint32 NumVariables DEFAULT_INITIALIZER(0); + Uint32 NumVariables DEFAULT_INITIALIZER(0); /// Array of shader resource variable descriptions - const ShaderResourceVariableDesc* Variables DEFAULT_INITIALIZER(nullptr); + const ShaderResourceVariableDesc* Variables DEFAULT_INITIALIZER(nullptr); - /// Number of static samplers in StaticSamplers array - Uint32 NumStaticSamplers DEFAULT_INITIALIZER(0); + /// Number of immutable samplers in ImmutableSamplers array + Uint32 NumImmutableSamplers DEFAULT_INITIALIZER(0); - /// Array of static sampler descriptions - const StaticSamplerDesc* StaticSamplers DEFAULT_INITIALIZER(nullptr); + /// Array of immutable sampler descriptions + const ImmutableSamplerDesc* ImmutableSamplers DEFAULT_INITIALIZER(nullptr); }; typedef struct PipelineResourceLayoutDesc PipelineResourceLayoutDesc; @@ -256,7 +260,7 @@ typedef struct PipelineStateDesc PipelineStateDesc; DILIGENT_TYPED_ENUM(PSO_CREATE_FLAGS, Uint32) { /// Null flag. - PSO_CREATE_FLAG_NONE = 0x00, + PSO_CREATE_FLAG_NONE = 0x00, /// Ignore missing variables. @@ -264,15 +268,15 @@ DILIGENT_TYPED_ENUM(PSO_CREATE_FLAGS, Uint32) /// provided as part of the pipeline resource layout description /// that is not found in any of the designated shader stages. /// Use this flag to silence these warnings. - PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES = 0x01, + PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES = 0x01, - /// Ignore missing static samplers. + /// Ignore missing immutable samplers. - /// By default, the engine outputs a warning for every static sampler + /// By default, the engine outputs a warning for every immutable sampler /// provided as part of the pipeline resource layout description /// that is not found in any of the designated shader stages. /// Use this flag to silence these warnings. - PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS = 0x02, + PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS = 0x02, }; DEFINE_FLAG_ENUM_OPERATORS(PSO_CREATE_FLAGS); diff --git a/Graphics/GraphicsEngine/src/APIInfo.cpp b/Graphics/GraphicsEngine/src/APIInfo.cpp index aa2fb3d9..e4111327 100644 --- a/Graphics/GraphicsEngine/src/APIInfo.cpp +++ b/Graphics/GraphicsEngine/src/APIInfo.cpp @@ -87,7 +87,7 @@ static APIInfo InitAPIInfo() INIT_STRUCTURE_SIZE(InputLayoutDesc); INIT_STRUCTURE_SIZE(SampleDesc); INIT_STRUCTURE_SIZE(ShaderResourceVariableDesc); - INIT_STRUCTURE_SIZE(StaticSamplerDesc); + INIT_STRUCTURE_SIZE(ImmutableSamplerDesc); INIT_STRUCTURE_SIZE(PipelineResourceLayoutDesc); INIT_STRUCTURE_SIZE(GraphicsPipelineDesc); INIT_STRUCTURE_SIZE(GraphicsPipelineStateCreateInfo); -- cgit v1.2.3 From e5f36378de4a7258fcc9d6ca7a349df1136b7444 Mon Sep 17 00:00:00 2001 From: assiduous Date: Mon, 19 Oct 2020 12:08:40 -0700 Subject: Renamed USAGE_STATIC to USAGE_IMMUTABLE (API240077) --- Graphics/GraphicsEngine/interface/APIInfo.h | 2 +- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 4 ++-- Graphics/GraphicsEngine/interface/RenderDevice.h | 4 ++-- Graphics/GraphicsEngine/src/BufferBase.cpp | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index a32511d2..327f54c7 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 240076 +#define DILIGENT_API_VERSION 240077 #include "../../../Primitives/interface/BasicTypes.h" diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 74e16535..0f6b4b82 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -103,7 +103,7 @@ DILIGENT_TYPED_ENUM(USAGE, Uint8) /// when it is created, since it cannot be changed after creation. \n /// D3D11 Counterpart: D3D11_USAGE_IMMUTABLE. OpenGL counterpart: GL_STATIC_DRAW /// \remarks Static buffers do not allow CPU access and must use CPU_ACCESS_NONE flag. - USAGE_STATIC = 0, + USAGE_IMMUTABLE = 0, /// A resource that requires read and write access by the GPU and can also be occasionally /// written by the CPU. \n @@ -1706,7 +1706,7 @@ struct GraphicsAdapterInfo /// The amount of local video memory that is inaccessible by CPU, in bytes. - /// \note Device-local memory is where USAGE_DEFAULT and USAGE_STATIC resources + /// \note Device-local memory is where USAGE_DEFAULT and USAGE_IMMUTABLE resources /// are typically allocated. /// /// On some devices it may not be possible to query the memory size, diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h index 5c72c81a..252daf1a 100644 --- a/Graphics/GraphicsEngine/interface/RenderDevice.h +++ b/Graphics/GraphicsEngine/interface/RenderDevice.h @@ -75,7 +75,7 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) /// \param [in] BuffDesc - Buffer description, see Diligent::BufferDesc for details. /// \param [in] pBuffData - Pointer to Diligent::BufferData structure that describes /// initial buffer data or nullptr if no data is provided. - /// Static buffers (USAGE_STATIC) must be initialized at creation time. + /// Immutable buffers (USAGE_IMMUTABLE) must be initialized at creation time. /// \param [out] ppBuffer - Address of the memory location where the pointer to the /// buffer interface will be stored. The function calls AddRef(), /// so that the new buffer will contain one reference and must be @@ -106,7 +106,7 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) /// \param [in] TexDesc - Texture description, see Diligent::TextureDesc for details. /// \param [in] pData - Pointer to Diligent::TextureData structure that describes /// initial texture data or nullptr if no data is provided. - /// Static textures (USAGE_STATIC) must be initialized at creation time. + /// Immutable textures (USAGE_IMMUTABLE) must be initialized at creation time. /// /// \param [out] ppTexture - Address of the memory location where the pointer to the /// texture interface will be stored. diff --git a/Graphics/GraphicsEngine/src/BufferBase.cpp b/Graphics/GraphicsEngine/src/BufferBase.cpp index 4aff91a0..0239ed92 100644 --- a/Graphics/GraphicsEngine/src/BufferBase.cpp +++ b/Graphics/GraphicsEngine/src/BufferBase.cpp @@ -71,7 +71,7 @@ void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps) switch (Desc.Usage) { - case USAGE_STATIC: + case USAGE_IMMUTABLE: case USAGE_DEFAULT: VERIFY_BUFFER(Desc.CPUAccessFlags == CPU_ACCESS_NONE, "static and default buffers can't have any CPU access flags set."); break; @@ -114,8 +114,8 @@ void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps) void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData) { - if (Desc.Usage == USAGE_STATIC && (pBuffData == nullptr || pBuffData->pData == nullptr)) - LOG_BUFFER_ERROR_AND_THROW("initial data must not be null as static buffers must be initialized at creation time."); + if (Desc.Usage == USAGE_IMMUTABLE && (pBuffData == nullptr || pBuffData->pData == nullptr)) + LOG_BUFFER_ERROR_AND_THROW("initial data must not be null as immutable buffers must be initialized at creation time."); if (Desc.Usage == USAGE_DYNAMIC && pBuffData != nullptr && pBuffData->pData != nullptr) LOG_BUFFER_ERROR_AND_THROW("initial data must be null for dynamic buffers."); -- cgit v1.2.3 From 13b0b54987db2684e46e337d2e5be5b81366083b Mon Sep 17 00:00:00 2001 From: assiduous Date: Tue, 20 Oct 2020 13:26:21 -0700 Subject: Improved exception safety of pipeline state object construction --- Graphics/GraphicsEngine/include/PipelineStateBase.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index c108f663..1effd32f 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -222,7 +222,7 @@ protected: void ReserveSpaceForPipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo, - LinearAllocator& MemPool) + LinearAllocator& MemPool) noexcept { MemPool.AddSpace(); ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool); @@ -240,7 +240,7 @@ protected: } void ReserveSpaceForPipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo, - LinearAllocator& MemPool) const + LinearAllocator& MemPool) const noexcept { ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool); } @@ -448,7 +448,7 @@ protected: } private: - void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) const + static void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) noexcept { if (SrcLayout.Variables != nullptr) { @@ -471,7 +471,7 @@ private: } } - void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) const + static void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) { if (SrcLayout.Variables != nullptr) { -- cgit v1.2.3 From b9d1a84943f61d1b48ffb1847cd0b3f7b8c60fb2 Mon Sep 17 00:00:00 2001 From: assiduous Date: Tue, 20 Oct 2020 18:05:02 -0700 Subject: Added ShaderResourceQueries device feature and EngineGLCreateInfo::ForceNonSeparablePrograms parameter (API 240078) --- Graphics/GraphicsEngine/interface/APIInfo.h | 2 +- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index 327f54c7..0ecbd92b 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 240077 +#define DILIGENT_API_VERSION 240078 #include "../../../Primitives/interface/BasicTypes.h" diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 0f6b4b82..b05519c5 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1515,6 +1515,17 @@ struct DeviceFeatures /// Indicates if device supports separable programs DEVICE_FEATURE_STATE SeparablePrograms DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + /// Indicates if device supports resource queries from shader objects. + + /// \ note This feature indicates if IShader::GetResourceCount() and IShader::GetResourceDesc() methods + /// can be used to query the list of resources of individual shader objects. + /// Shader variable queries from pipeline state and shader resource binding objects are always + /// available. + /// + /// The feature is always enabled in Direct3D11, Direct3D12 and Vulkan. It is enabled in + /// OpenGL when separable programs are available, and it is always disabled in Metal. + DEVICE_FEATURE_STATE ShaderResourceQueries DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + /// Indicates if device supports indirect draw commands DEVICE_FEATURE_STATE IndirectRendering DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); @@ -1616,6 +1627,7 @@ struct DeviceFeatures explicit DeviceFeatures(DEVICE_FEATURE_STATE State) noexcept : SeparablePrograms {State}, + ShaderResourceQueries {State}, IndirectRendering {State}, WireframeFill {State}, MultithreadedResourceCreation {State}, @@ -1647,7 +1659,7 @@ struct DeviceFeatures UniformBuffer8BitAccess {State} { # if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(*this) == 30, "Did you add a new feature to DeviceFeatures? Please handle its status above."); + static_assert(sizeof(*this) == 31, "Did you add a new feature to DeviceFeatures? Please handle its status above."); # endif } #endif @@ -1875,6 +1887,11 @@ struct EngineGLCreateInfo DILIGENT_DERIVE(EngineCreateInfo) /// provide additional runtime checking, validation, and logging /// functionality while possibly incurring performance penalties bool CreateDebugContext DEFAULT_INITIALIZER(false); + + /// Force using non-separable programs. + + /// Setting this to true is typically needed for testing purposes only. + bool ForceNonSeparablePrograms DEFAULT_INITIALIZER(false); }; typedef struct EngineGLCreateInfo EngineGLCreateInfo; -- cgit v1.2.3