diff options
| author | azhirnov <zh1dron@gmail.com> | 2020-10-08 18:45:01 +0000 |
|---|---|---|
| committer | azhirnov <zh1dron@gmail.com> | 2020-10-08 18:46:35 +0000 |
| commit | 2b396d236ab33dfe9c0defbe401d354ed3fb34f9 (patch) | |
| tree | 575243bb9aa6215725a8b16a7747c103c1eda852 /Graphics | |
| parent | Updated PipelineState[D3D11,D3D12,Vk]Impl to allocate single chunk of memory ... (diff) | |
| download | DiligentCore-2b396d236ab33dfe9c0defbe401d354ed3fb34f9.tar.gz DiligentCore-2b396d236ab33dfe9c0defbe401d354ed3fb34f9.zip | |
removed strong references to shaders in PSO
Diffstat (limited to 'Graphics')
21 files changed, 1055 insertions, 925 deletions
diff --git a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp index af77319a..29e5aff3 100644 --- a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp +++ b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp @@ -1316,7 +1316,7 @@ Int32 GetShaderTypePipelineIndex(SHADER_TYPE ShaderType, PIPELINE_TYPE PipelineT { VERIFY(IsConsistentShaderType(ShaderType, PipelineType), "Shader type ", GetShaderTypeLiteralName(ShaderType), " is inconsistent with pipeline type ", GetPipelineTypeString(PipelineType)); - VERIFY(IsPowerOfTwo(Uint32{ShaderType}), "Only single shader stage should be provided"); + VERIFY((ShaderType & (ShaderType - 1)) == 0, "More than one shader type specified"); static_assert(SHADER_TYPE_LAST == 0x080, "Please update the switch below to handle the new shader type"); switch (ShaderType) 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<Uint8>(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<Uint32, MAX_BUFFER_SLOTS> 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 <typename ShaderType> - ShaderType* GetShader(Uint32 ShaderInd) - { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return ValidatedCast<ShaderType>(m_ppShaders[ShaderInd]); - } - template <typename ShaderType> - ShaderType* GetShader(Uint32 ShaderInd) const - { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return ValidatedCast<ShaderType>(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<IShader> m_pVS; ///< Strong reference to the vertex shader - RefCntAutoPtr<IShader> m_pPS; ///< Strong reference to the pixel shader - RefCntAutoPtr<IShader> m_pGS; ///< Strong reference to the geometry shader - RefCntAutoPtr<IShader> m_pDS; ///< Strong reference to the domain shader - RefCntAutoPtr<IShader> m_pHS; ///< Strong reference to the hull shader - RefCntAutoPtr<IShader> m_pCS; ///< Strong reference to the compute shader - RefCntAutoPtr<IShader> m_pAS; ///< Strong reference to the amplification shader - RefCntAutoPtr<IShader> m_pMS; ///< Strong reference to the mesh shader - RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object - std::array<IShader*, MAX_SHADERS_IN_PIPELINE> 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<SHADER_TYPE, MAX_SHADERS_IN_PIPELINE> 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<Int8, MAX_SHADERS_IN_PIPELINE>& 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<std::pair<SHADER_TYPE, IShader*>>; - 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<Uint8>(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<Uint32, MAX_BUFFER_SLOTS> 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; diff --git a/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp index 02f922a6..7acb15f0 100644 --- a/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp @@ -36,6 +36,7 @@ #include "ShaderResourceLayoutD3D11.hpp" #include "SRBMemoryAllocator.hpp" #include "RenderDeviceD3D11Impl.hpp" +#include "ShaderD3D11Impl.hpp" namespace Diligent { @@ -117,16 +118,19 @@ public: const ShaderResourceLayoutD3D11& GetStaticResourceLayout(Uint32 s) const { - VERIFY_EXPR(s < m_NumShaders); + VERIFY_EXPR(s < GetNumShaderTypes()); return m_pStaticResourceLayouts[s]; } ShaderResourceCacheD3D11& GetStaticResourceCache(Uint32 s) { - VERIFY_EXPR(s < m_NumShaders); + VERIFY_EXPR(s < GetNumShaderTypes()); return m_pStaticResourceCaches[s]; } + const ShaderD3D11Impl* GetShaderByType(SHADER_TYPE ShaderType) const; + const ShaderD3D11Impl* GetShader(Uint32 Index) const; + void SetStaticSamplers(ShaderResourceCacheD3D11& ResourceCache, Uint32 ShaderInd) const; private: @@ -135,6 +139,13 @@ private: CComPtr<ID3D11DepthStencilState> m_pd3d11DepthStencilState; CComPtr<ID3D11InputLayout> m_pd3d11InputLayout; + RefCntAutoPtr<ShaderD3D11Impl> m_pVS; + RefCntAutoPtr<ShaderD3D11Impl> m_pPS; + RefCntAutoPtr<ShaderD3D11Impl> m_pGS; + RefCntAutoPtr<ShaderD3D11Impl> m_pDS; + RefCntAutoPtr<ShaderD3D11Impl> m_pHS; + RefCntAutoPtr<ShaderD3D11Impl> m_pCS; + // The caches are indexed by the shader order in the PSO, not shader index ShaderResourceCacheD3D11* m_pStaticResourceCaches = nullptr; ShaderResourceLayoutD3D11* m_pStaticResourceLayouts = nullptr; diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index 6af8b502..cd942aed 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -179,9 +179,9 @@ void DeviceContextD3D11Impl::TransitionAndCommitShaderResources(IPipelineState* { #ifdef DILIGENT_DEVELOPMENT bool ResourcesPresent = false; - for (Uint32 s = 0; s < pPipelineStateD3D11->GetNumShaders(); ++s) + for (Uint32 s = 0; s < pPipelineStateD3D11->GetNumShaderTypes(); ++s) { - auto* pShaderD3D11 = pPipelineStateD3D11->GetShader<ShaderD3D11Impl>(s); + auto* pShaderD3D11 = pPipelineStateD3D11->GetShader(s); if (pShaderD3D11->GetD3D11Resources()->GetTotalResources() > 0) ResourcesPresent = true; } @@ -206,7 +206,7 @@ void DeviceContextD3D11Impl::TransitionAndCommitShaderResources(IPipelineState* #endif auto NumShaders = pShaderResBindingD3D11->GetNumActiveShaders(); - VERIFY(NumShaders == pPipelineStateD3D11->GetNumShaders(), "Number of active shaders in shader resource binding is not consistent with the number of shaders in the pipeline state"); + VERIFY(NumShaders == pPipelineStateD3D11->GetNumShaderTypes(), "Number of active shaders in shader resource binding is not consistent with the number of shaders in the pipeline state"); #ifdef DILIGENT_DEVELOPMENT { @@ -233,7 +233,7 @@ void DeviceContextD3D11Impl::TransitionAndCommitShaderResources(IPipelineState* const auto ShaderTypeInd = GetShaderTypeIndex(ShaderType); #ifdef DILIGENT_DEVELOPMENT - auto* pShaderD3D11 = pPipelineStateD3D11->GetShader<ShaderD3D11Impl>(s); + auto* pShaderD3D11 = pPipelineStateD3D11->GetShader(s); VERIFY_EXPR(ShaderType == pShaderD3D11->GetDesc().ShaderType); #endif @@ -380,7 +380,7 @@ void DeviceContextD3D11Impl::TransitionAndCommitShaderResources(IPipelineState* const auto ShaderTypeInd = GetShaderTypeIndex(ShaderType); #ifdef DILIGENT_DEVELOPMENT - auto* pShaderD3D11 = pPipelineStateD3D11->GetShader<ShaderD3D11Impl>(s); + auto* pShaderD3D11 = pPipelineStateD3D11->GetShader(s); VERIFY_EXPR(ShaderType == pShaderD3D11->GetDesc().ShaderType); #endif diff --git a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp index fb93f90d..0e312740 100644 --- a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp @@ -31,7 +31,6 @@ #include "RenderDeviceD3D11Impl.hpp" #include "ShaderResourceBindingD3D11Impl.hpp" #include "EngineMemory.h" -#include "ShaderD3D11Impl.hpp" namespace Diligent { @@ -136,24 +135,24 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR static_assert((sizeof(ShaderResourceLayoutD3D11) % sizeof(void*)) == 0, "sizeof(ShaderResourceLayoutD3D11) is expected to be a multiple of sizeof(void*)"); static_assert((sizeof(ShaderResourceCacheD3D11) % sizeof(void*)) == 0, "sizeof(ShaderResourceCacheD3D11) is expected to be a multiple of sizeof(void*)"); // clang-format on - const auto MemSize = (sizeof(ShaderResourceLayoutD3D11) + sizeof(ShaderResourceCacheD3D11)) * m_NumShaders; + const auto MemSize = (sizeof(ShaderResourceLayoutD3D11) + sizeof(ShaderResourceCacheD3D11)) * GetNumShaderTypes(); auto* const pRawMem = ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutD3D11 and ShaderResourceCacheD3D11 arrays", MemSize); m_pStaticResourceLayouts = reinterpret_cast<ShaderResourceLayoutD3D11*>(pRawMem); - m_pStaticResourceCaches = reinterpret_cast<ShaderResourceCacheD3D11*>(m_pStaticResourceLayouts + m_NumShaders); + m_pStaticResourceCaches = reinterpret_cast<ShaderResourceCacheD3D11*>(m_pStaticResourceLayouts + GetNumShaderTypes()); const auto& ResourceLayout = m_Desc.ResourceLayout; #ifdef DILIGENT_DEVELOPMENT { const ShaderResources* pResources[MAX_SHADERS_IN_PIPELINE] = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { - auto* pShader = GetShader<const ShaderD3D11Impl>(s); + auto* pShader = GetShader(s); pResources[s] = &(*pShader->GetD3D11Resources()); } - ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, m_NumShaders, + ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, GetNumShaderTypes(), (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); } @@ -162,9 +161,9 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR decltype(m_StaticSamplers) StaticSamplers(STD_ALLOCATOR_RAW_MEM(StaticSamplerInfo, GetRawAllocator(), "Allocator for vector<StaticSamplerInfo>")); std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderResLayoutDataSizes = {}; std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderResCacheDataSizes = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { - const auto* pShader = GetShader<const ShaderD3D11Impl>(s); + const auto* pShader = GetShader(s); const auto& ShaderDesc = pShader->GetDesc(); const auto& ShaderResources = *pShader->GetD3D11Resources(); VERIFY_EXPR(ShaderDesc.ShaderType == ShaderResources.GetShaderType()); @@ -222,14 +221,14 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR if (m_Desc.SRBAllocationGranularity > 1) { - m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, m_NumShaders, ShaderResLayoutDataSizes.data(), m_NumShaders, ShaderResCacheDataSizes.data()); + m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderTypes(), ShaderResLayoutDataSizes.data(), GetNumShaderTypes(), ShaderResCacheDataSizes.data()); } m_StaticSamplers.reserve(StaticSamplers.size()); for (auto& Sam : StaticSamplers) m_StaticSamplers.emplace_back(std::move(Sam)); - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { // Initialize static samplers in the static resource cache to avoid warning messages SetStaticSamplers(m_pStaticResourceCaches[s], s); @@ -239,13 +238,13 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR PipelineStateD3D11Impl::~PipelineStateD3D11Impl() { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { m_pStaticResourceCaches[s].Destroy(GetRawAllocator()); m_pStaticResourceCaches[s].~ShaderResourceCacheD3D11(); } - for (Uint32 l = 0; l < m_NumShaders; ++l) + for (Uint32 l = 0; l < GetNumShaderTypes(); ++l) { m_pStaticResourceLayouts[l].~ShaderResourceLayoutD3D11(); } @@ -298,13 +297,13 @@ bool PipelineStateD3D11Impl::IsCompatibleWith(const IPipelineState* pPSO) const if (m_ShaderResourceLayoutHash != pPSOD3D11->m_ShaderResourceLayoutHash) return false; - if (m_NumShaders != pPSOD3D11->m_NumShaders) + if (GetNumShaderTypes() != pPSOD3D11->GetNumShaderTypes()) return false; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { - auto* pShader0 = GetShader<const ShaderD3D11Impl>(s); - auto* pShader1 = pPSOD3D11->GetShader<const ShaderD3D11Impl>(s); + auto* pShader0 = GetShader(s); + auto* pShader1 = pPSOD3D11->GetShader(s); if (pShader0->GetDesc().ShaderType != pShader1->GetDesc().ShaderType) return false; const auto& Res0 = *pShader0->GetD3D11Resources(); @@ -361,7 +360,7 @@ ID3D11ComputeShader* PipelineStateD3D11Impl::GetD3D11ComputeShader() void PipelineStateD3D11Impl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { auto& StaticResLayout = m_pStaticResourceLayouts[s]; if ((ShaderFlags & StaticResLayout.GetShaderType()) != 0) @@ -375,7 +374,7 @@ Uint32 PipelineStateD3D11Impl::GetStaticVariableCount(SHADER_TYPE ShaderType) co if (LayoutInd < 0) return 0; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= GetNumShaderTypes()); return m_pStaticResourceLayouts[LayoutInd].GetTotalResourceCount(); } @@ -385,7 +384,7 @@ IShaderResourceVariable* PipelineStateD3D11Impl::GetStaticVariableByName(SHADER_ if (LayoutInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= GetNumShaderTypes()); return m_pStaticResourceLayouts[LayoutInd].GetShaderVariable(Name); } @@ -395,7 +394,7 @@ IShaderResourceVariable* PipelineStateD3D11Impl::GetStaticVariableByIndex(SHADER if (LayoutInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= GetNumShaderTypes()); return m_pStaticResourceLayouts[LayoutInd].GetShaderVariable(Index); } @@ -414,4 +413,29 @@ void PipelineStateD3D11Impl::SetStaticSamplers(ShaderResourceCacheD3D11& Resourc } } +const ShaderD3D11Impl* PipelineStateD3D11Impl::GetShaderByType(SHADER_TYPE ShaderType) const +{ + switch (ShaderType) + { + // clang-format off + case SHADER_TYPE_VERTEX: return m_pVS; + case SHADER_TYPE_PIXEL: return m_pPS; + case SHADER_TYPE_GEOMETRY: return m_pGS; + case SHADER_TYPE_HULL: return m_pHS; + case SHADER_TYPE_DOMAIN: return m_pDS; + case SHADER_TYPE_COMPUTE: return m_pCS; + default: UNEXPECTED("unsupported shader type"); return nullptr; + // clang-format on + } +} + +const ShaderD3D11Impl* PipelineStateD3D11Impl::GetShader(Uint32 Index) const +{ + if (Index < GetNumShaderTypes()) + return GetShaderByType(GetShaderTypes()[Index]); + + UNEXPECTED("Shader index is out of range"); + return nullptr; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp index 62fd2df7..17083bbc 100644 --- a/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp @@ -50,7 +50,7 @@ ShaderResourceBindingD3D11Impl::ShaderResourceBindingD3D11Impl(IReferenceCounter // clang-format on { m_ResourceLayoutIndex.fill(-1); - m_NumActiveShaders = static_cast<Uint8>(pPSO->GetNumShaders()); + m_NumActiveShaders = static_cast<Uint8>(pPSO->GetNumShaderTypes()); // clang-format off m_pResourceLayouts = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceLayoutD3D11", ShaderResourceLayoutD3D11, m_NumActiveShaders); @@ -62,7 +62,7 @@ ShaderResourceBindingD3D11Impl::ShaderResourceBindingD3D11Impl(IReferenceCounter // Reserve memory for resource layouts for (Uint8 s = 0; s < m_NumActiveShaders; ++s) { - auto* pShaderD3D11 = pPSO->GetShader<ShaderD3D11Impl>(s); + auto* pShaderD3D11 = pPSO->GetShader(s); auto& SRBMemAllocator = pPSO->GetSRBMemoryAllocator(); auto& ResCacheDataAllocator = SRBMemAllocator.GetResourceCacheDataAllocator(s); @@ -151,14 +151,13 @@ void ShaderResourceBindingD3D11Impl::InitializeStaticResources(const IPipelineSt } const auto* pPSOD3D11 = ValidatedCast<const PipelineStateD3D11Impl>(pPipelineState); - auto ppShaders = pPSOD3D11->GetShaders(); - auto NumShaders = pPSOD3D11->GetNumShaders(); + auto NumShaders = pPSOD3D11->GetNumShaderTypes(); VERIFY_EXPR(NumShaders == m_NumActiveShaders); for (Uint32 shader = 0; shader < NumShaders; ++shader) { const auto& StaticResLayout = pPSOD3D11->GetStaticResourceLayout(shader); - auto* pShaderD3D11 = ValidatedCast<ShaderD3D11Impl>(ppShaders[shader]); + auto* pShaderD3D11 = pPSOD3D11->GetShader(shader); #ifdef DILIGENT_DEVELOPMENT if (!StaticResLayout.dvpVerifyBindings()) { diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp index a53a625d..1ce53c24 100644 --- a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp @@ -95,19 +95,19 @@ public: const ShaderResourceLayoutD3D12& GetShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < GetNumShaderTypes()); return m_pShaderResourceLayouts[ShaderInd]; } const ShaderResourceLayoutD3D12& GetStaticShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return m_pShaderResourceLayouts[m_NumShaders + ShaderInd]; + VERIFY_EXPR(ShaderInd < GetNumShaderTypes()); + return m_pShaderResourceLayouts[GetNumShaderTypes() + ShaderInd]; } ShaderResourceCacheD3D12& GetStaticShaderResCache(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < GetNumShaderTypes()); return m_pStaticResourceCaches[ShaderInd]; } diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index e9c313a5..d5958ea8 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -106,6 +106,9 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR { m_ResourceLayoutIndex.fill(-1); + ShaderStages_t ShaderStages; + ExtractShaders(ShaderStages); + auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); const auto& ResourceLayout = m_Desc.ResourceLayout; m_RootSig.AllocateStaticSamplers(ResourceLayout); @@ -115,31 +118,31 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR static_assert((sizeof(ShaderResourceCacheD3D12) % sizeof(void*)) == 0, "sizeof(ShaderResourceCacheD3D12) is expected to be a multiple of sizeof(void*)"); static_assert((sizeof(ShaderVariableManagerD3D12) % sizeof(void*)) == 0, "sizeof(ShaderVariableManagerD3D12) is expected to be a multiple of sizeof(void*)"); // clang-format on - const auto MemSize = (sizeof(ShaderResourceLayoutD3D12) * 2 + sizeof(ShaderResourceCacheD3D12) + sizeof(ShaderVariableManagerD3D12)) * m_NumShaders; + const auto MemSize = (sizeof(ShaderResourceLayoutD3D12) * 2 + sizeof(ShaderResourceCacheD3D12) + sizeof(ShaderVariableManagerD3D12)) * GetNumShaderTypes(); auto* const pRawMem = ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutD3D12, ShaderResourceCacheD3D12, and ShaderVariableManagerD3D12 arrays", MemSize); m_pShaderResourceLayouts = reinterpret_cast<ShaderResourceLayoutD3D12*>(pRawMem); - m_pStaticResourceCaches = reinterpret_cast<ShaderResourceCacheD3D12*>(m_pShaderResourceLayouts + m_NumShaders * 2); - m_pStaticVarManagers = reinterpret_cast<ShaderVariableManagerD3D12*>(m_pStaticResourceCaches + m_NumShaders); + m_pStaticResourceCaches = reinterpret_cast<ShaderResourceCacheD3D12*>(m_pShaderResourceLayouts + GetNumShaderTypes() * 2); + m_pStaticVarManagers = reinterpret_cast<ShaderVariableManagerD3D12*>(m_pStaticResourceCaches + GetNumShaderTypes()); #ifdef DILIGENT_DEVELOPMENT { const ShaderResources* pResources[MAX_SHADERS_IN_PIPELINE] = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - const auto* pShader = GetShader<const ShaderD3D12Impl>(s); + const auto* pShader = ValidatedCast<ShaderD3D12Impl>(ShaderStages[s].second); pResources[s] = &(*pShader->GetShaderResources()); } - ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, m_NumShaders, + ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, GetNumShaderTypes(), (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); } #endif - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto* pShaderD3D12 = GetShader<ShaderD3D12Impl>(s); + auto* pShaderD3D12 = ValidatedCast<ShaderD3D12Impl>(ShaderStages[s].second); auto ShaderType = pShaderD3D12->GetDesc().ShaderType; auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); @@ -163,7 +166,7 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR new (m_pStaticResourceCaches + s) ShaderResourceCacheD3D12{ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources}; const SHADER_RESOURCE_VARIABLE_TYPE StaticVarType[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; - new (m_pShaderResourceLayouts + m_NumShaders + s) + new (m_pShaderResourceLayouts + GetNumShaderTypes() + s) ShaderResourceLayoutD3D12 // { *this, @@ -182,11 +185,11 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR ShaderVariableManagerD3D12 // { *this, - GetStaticShaderResLayout(s), + GetStaticShaderResLayout(static_cast<Uint32>(s)), GetRawAllocator(), nullptr, 0, - GetStaticShaderResCache(s) // + GetStaticShaderResCache(static_cast<Uint32>(s)) // }; } m_RootSig.Finalize(pd3d12Device); @@ -195,14 +198,9 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR { case PIPELINE_TYPE_COMPUTE: { - auto& ComputePipeline = m_Desc.ComputePipeline; - - if (ComputePipeline.pCS == nullptr) - LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc"); - D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {}; - auto* pByteCode = ValidatedCast<ShaderD3D12Impl>(ComputePipeline.pCS)->GetShaderByteCode(); + auto* pByteCode = ValidatedCast<ShaderD3D12Impl>(ShaderStages[0].second)->GetShaderByteCode(); d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); @@ -231,9 +229,9 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR D3D12_GRAPHICS_PIPELINE_STATE_DESC d3d12PSODesc = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto* pShaderD3D12 = GetShader<ShaderD3D12Impl>(s); + auto* pShaderD3D12 = ValidatedCast<ShaderD3D12Impl>(ShaderStages[s].second); auto ShaderType = pShaderD3D12->GetDesc().ShaderType; D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; @@ -335,9 +333,9 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR }; MESH_SHADER_PIPELINE_STATE_DESC d3d12PSODesc = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto* pShaderD3D12 = GetShader<ShaderD3D12Impl>(s); + auto* pShaderD3D12 = ValidatedCast<ShaderD3D12Impl>(ShaderStages[s].second); auto ShaderType = pShaderD3D12->GetDesc().ShaderType; D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; @@ -412,7 +410,7 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR if (m_Desc.SRBAllocationGranularity > 1) { std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVarMgrDataSizes = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { std::array<SHADER_RESOURCE_VARIABLE_TYPE, 2> AllowedVarTypes = { @@ -425,7 +423,7 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR } auto CacheMemorySize = m_RootSig.GetResourceCacheRequiredMemSize(); - m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, m_NumShaders, ShaderVarMgrDataSizes.data(), 1, &CacheMemorySize); + m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderTypes(), ShaderVarMgrDataSizes.data(), 1, &CacheMemorySize); } m_ShaderResourceLayoutHash = m_RootSig.GetHash(); @@ -434,13 +432,13 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR PipelineStateD3D12Impl::~PipelineStateD3D12Impl() { auto& ShaderResLayoutAllocator = GetRawAllocator(); - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { m_pStaticVarManagers[s].Destroy(GetRawAllocator()); m_pStaticVarManagers[s].~ShaderVariableManagerD3D12(); m_pStaticResourceCaches[s].~ShaderResourceCacheD3D12(); m_pShaderResourceLayouts[s].~ShaderResourceLayoutD3D12(); - m_pShaderResourceLayouts[m_NumShaders + s].~ShaderResourceLayoutD3D12(); + m_pShaderResourceLayouts[GetNumShaderTypes() + s].~ShaderResourceLayoutD3D12(); } // m_pShaderResourceLayouts, m_pStaticResourceCaches, and m_pShaderResourceLayouts are allocated in // contiguous chunks of memory. @@ -479,27 +477,26 @@ bool PipelineStateD3D12Impl::IsCompatibleWith(const IPipelineState* pPSO) const #ifdef DILIGENT_DEBUG { bool IsCompatibleShaders = true; - if (m_NumShaders != pPSOD3D12->m_NumShaders) + if (GetNumShaderTypes() != pPSOD3D12->GetNumShaderTypes()) IsCompatibleShaders = false; if (IsCompatibleShaders) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { - auto* pShader0 = GetShader<const ShaderD3D12Impl>(s); - auto* pShader1 = pPSOD3D12->GetShader<const ShaderD3D12Impl>(s); - if (pShader0->GetDesc().ShaderType != pShader1->GetDesc().ShaderType) + if (GetShaderTypes()[s] != pPSOD3D12->GetShaderTypes()[s]) { IsCompatibleShaders = false; break; } - const ShaderResourcesD3D12* pRes0 = pShader0->GetShaderResources().get(); + // AZ TODO + /*const ShaderResourcesD3D12* pRes0 = pShader0->GetShaderResources().get(); const ShaderResourcesD3D12* pRes1 = pShader1->GetShaderResources().get(); if (!pRes0->IsCompatibleWith(*pRes1)) { IsCompatibleShaders = false; break; - } + }*/ } } @@ -606,7 +603,7 @@ bool PipelineStateD3D12Impl::ContainsShaderResources() const void PipelineStateD3D12Impl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { auto ShaderType = GetStaticShaderResLayout(s).GetShaderType(); if ((ShaderFlags & ShaderType) != 0) @@ -620,7 +617,7 @@ Uint32 PipelineStateD3D12Impl::GetStaticVariableCount(SHADER_TYPE ShaderType) co if (LayoutInd < 0) return 0; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderTypes()); return m_pStaticVarManagers[LayoutInd].GetVariableCount(); } @@ -630,7 +627,7 @@ IShaderResourceVariable* PipelineStateD3D12Impl::GetStaticVariableByName(SHADER_ if (LayoutInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderTypes()); return m_pStaticVarManagers[LayoutInd].GetVariable(Name); } @@ -640,7 +637,7 @@ IShaderResourceVariable* PipelineStateD3D12Impl::GetStaticVariableByIndex(SHADER if (LayoutInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderTypes()); return m_pStaticVarManagers[LayoutInd].GetVariable(Index); } diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp index 257a4688..17387138 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp @@ -45,11 +45,10 @@ ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounter IsPSOInternal }, m_ShaderResourceCache{ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources}, - m_NumShaders {static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaders())} + m_NumShaders {static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaderTypes())} // clang-format on { m_ResourceLayoutIndex.fill(-1); - auto* ppShaders = pPSO->GetShaders(); auto* pRenderDeviceD3D12Impl = ValidatedCast<RenderDeviceD3D12Impl>(pPSO->GetDevice()); auto& ResCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0); @@ -59,9 +58,8 @@ ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounter for (Uint32 s = 0; s < m_NumShaders; ++s) { - auto* pShader = ppShaders[s]; - auto ShaderType = pShader->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPSO->GetDesc().PipelineType); + auto ShaderType = pPSO->GetShaderTypes()[s]; + auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPSO->GetDesc().PipelineType); auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); @@ -189,20 +187,20 @@ void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const IPipelineSt } auto* pPSO12 = ValidatedCast<const PipelineStateD3D12Impl>(pPSO); - auto NumShaders = pPSO12->GetNumShaders(); + auto NumShaders = pPSO12->GetNumShaderTypes(); // Copy static resources for (Uint32 s = 0; s < NumShaders; ++s) { const auto& ShaderResLayout = pPSO12->GetShaderResLayout(s); auto& StaticResLayout = pPSO12->GetStaticShaderResLayout(s); auto& StaticResCache = pPSO12->GetStaticShaderResCache(s); + #ifdef DILIGENT_DEVELOPMENT if (!StaticResLayout.dvpVerifyBindings(StaticResCache)) { - auto* pShader = pPSO12->GetShader<ShaderD3D12Impl>(s); LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", pPSO12->GetDesc().Name, - "' will not be successfully initialized because not all static resource bindings in shader '", - pShader->GetDesc().Name, + "' will not be successfully initialized because not all static resource bindings in shader type '", + GetShaderTypeLiteralName(pPSO12->GetShaderTypes()[s]), "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method."); } diff --git a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp index 399983c9..c61ead8c 100644 --- a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp @@ -52,7 +52,9 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun m_StaticResourceLayout{*this} // clang-format on { - if (m_Desc.IsAnyGraphicsPipeline() && m_pPS == nullptr) + RefCntAutoPtr<IShader> pTempPS; + + if (m_Desc.IsAnyGraphicsPipeline() && m_Desc.GraphicsPipeline.pPS == nullptr) { // Some OpenGL implementations fail if fragment shader is not present, so // create a dummy one. @@ -61,9 +63,16 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun ShaderCI.Source = "void main(){}"; ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL; ShaderCI.Desc.Name = "Dummy fragment shader"; - pDeviceGL->CreateShader(ShaderCI, &m_pPS); - m_Desc.GraphicsPipeline.pPS = m_pPS; - m_ppShaders[m_NumShaders++] = m_pPS; + pDeviceGL->CreateShader(ShaderCI, &pTempPS); + } + + ShaderStages_t ShaderStages; + ExtractShaders(ShaderStages); + + if (pTempPS) + { + m_pShaderTypes[m_NumShaderTypes++] = SHADER_TYPE_PIXEL; + ShaderStages.push_back({SHADER_TYPE_PIXEL, pTempPS}); } auto& DeviceCaps = pDeviceGL->GetDeviceCaps(); @@ -83,13 +92,14 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun // Program pipelines are not shared between GL contexts, so we cannot create // it now m_ShaderResourceLayoutHash = 0; - m_ProgramResources.resize(m_NumShaders); - m_GLPrograms.reserve(m_NumShaders); - for (Uint32 i = 0; i < m_NumShaders; ++i) + m_ProgramResources.resize(ShaderStages.size()); + m_GLPrograms.reserve(ShaderStages.size()); + for (size_t i = 0; i < ShaderStages.size(); ++i) { - auto* pShaderGL = GetShader<ShaderGLImpl>(i); + auto* pShader = ShaderStages[i].second; + auto* pShaderGL = ValidatedCast<ShaderGLImpl>(pShader); const auto& ShaderDesc = pShaderGL->GetDesc(); - m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(&m_ppShaders[i], 1, true)); + m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(&pShader, 1, true)); // Load uniforms and assign bindings m_ProgramResources[i].LoadUniforms(ShaderDesc.ShaderType, m_GLPrograms[i], GLState, m_TotalUniformBufferBindings, @@ -102,10 +112,12 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun } else { - m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(m_ppShaders.data(), m_NumShaders, false)); + UNEXPECTED("TODO"); + // AZ TODO + /*m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(m_ppShaders.data(), ShaderStages.size(), false)); m_ProgramResources.resize(1); SHADER_TYPE ShaderStages = SHADER_TYPE_UNKNOWN; - for (Uint32 i = 0; i < m_NumShaders; ++i) + for (size_t i = 0; i < ShaderStages.size(); ++i) { const auto& ShaderDesc = m_ppShaders[i]->GetDesc(); ShaderStages |= ShaderDesc.ShaderType; @@ -116,7 +128,7 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun m_TotalImageBindings, m_TotalStorageBufferBindings); - m_ShaderResourceLayoutHash = m_ProgramResources[0].GetHash(); + m_ShaderResourceLayoutHash = m_ProgramResources[0].GetHash();*/ } // Initialize master resource layout that keeps all variable types and does not reference a resource cache @@ -214,10 +226,9 @@ GLObjectWrappers::GLPipelineObj& PipelineStateGLImpl::GetGLProgramPipeline(GLCon m_GLProgPipelines.emplace_back(Context, true); auto& ctx_pipeline = m_GLProgPipelines.back(); GLuint Pipeline = ctx_pipeline.second; - for (Uint32 i = 0; i < m_NumShaders; ++i) + for (Uint32 i = 0; i < GetNumShaderTypes(); ++i) { - auto* pCurrShader = GetShader<ShaderGLImpl>(i); - auto GLShaderBit = ShaderTypeToGLShaderBit(pCurrShader->GetDesc().ShaderType); + auto GLShaderBit = ShaderTypeToGLShaderBit(GetShaderTypes()[i]); // If the program has an active code for each stage mentioned in set flags, // then that code will be used by the pipeline. If program is 0, then the given // stages are cleared from the pipeline. diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp index d1732211..303496bb 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp @@ -56,6 +56,7 @@ class PipelineStateVkImpl final : public PipelineStateBase<IPipelineStateVk, Ren { public: using TPipelineStateBase = PipelineStateBase<IPipelineStateVk, RenderDeviceVkImpl>; + using ShaderSPIRVs_t = std::vector<std::vector<uint32_t>>; PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const PipelineStateCreateInfo& CreateInfo); ~PipelineStateVkImpl(); @@ -104,7 +105,7 @@ public: const ShaderResourceLayoutVk& GetShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < m_NumShaderTypes); return m_ShaderResourceLayouts[ShaderInd]; } @@ -127,19 +128,19 @@ public: private: const ShaderResourceLayoutVk& GetStaticShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return m_ShaderResourceLayouts[m_NumShaders + ShaderInd]; + VERIFY_EXPR(ShaderInd < m_NumShaderTypes); + return m_ShaderResourceLayouts[m_NumShaderTypes + ShaderInd]; } const ShaderResourceCacheVk& GetStaticResCache(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < m_NumShaderTypes); return m_StaticResCaches[ShaderInd]; } ShaderVariableManagerVk& GetStaticVarMgr(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < m_NumShaderTypes); return m_StaticVarsMgrs[ShaderInd]; } @@ -150,14 +151,12 @@ private: // SRB memory allocator must be declared before m_pDefaultShaderResBinding SRBMemoryAllocator m_SRBMemAllocator; - std::array<VulkanUtilities::ShaderModuleWrapper, MAX_SHADERS_IN_PIPELINE> m_ShaderModules = {}; - VulkanUtilities::PipelineWrapper m_Pipeline; PipelineLayout m_PipelineLayout; // Resource layout index in m_ShaderResourceLayouts array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; + std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex; bool m_HasStaticResources = false; bool m_HasNonStaticResources = false; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp index 026bb9da..85230b02 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp @@ -81,7 +81,7 @@ private: // Resource layout index in m_ShaderResourceCache array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; + std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex; bool m_bStaticResourcesInitialized = false; Uint8 m_NumShaders = 0; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp index a6d20641..28defd0f 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp @@ -115,6 +115,9 @@ namespace Diligent class ShaderResourceLayoutVk { public: + using ShaderStages_t = std::vector<std::pair<SHADER_TYPE, IShader*>>; + using ShaderSPIRVs_t = std::vector<std::vector<uint32_t>>; + ShaderResourceLayoutVk(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) : m_LogicalDevice{LogicalDevice} { @@ -131,23 +134,22 @@ public: // This method is called by PipelineStateVkImpl class instance to initialize static // shader resource layout and the cache - void InitializeStaticResourceLayout(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - ShaderResourceCacheVk& StaticResourceCache); + void InitializeStaticResourceLayout(IShader* pShader, + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderResourceCacheVk& StaticResourceCache); // This method is called by PipelineStateVkImpl class instance to initialize resource // layouts for all shader stages in the pipeline. - static void Initialize(IRenderDevice* pRenderDevice, - Uint32 NumShaders, - ShaderResourceLayoutVk Layouts[], - std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - std::vector<uint32_t> SPIRVs[], - class PipelineLayout& PipelineLayout, - bool VerifyVariables, - bool VerifyStaticSamplers); + static void Initialize(IRenderDevice* pRenderDevice, + const ShaderStages_t& ShaderStages, + ShaderResourceLayoutVk Layouts[], + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderSPIRVs_t& SPIRVs, + class PipelineLayout& PipelineLayout, + bool VerifyVariables, + bool VerifyStaticSamplers); // sizeof(VkResource) == 24 (x64) struct VkResource @@ -175,33 +177,21 @@ public: /* 7.5 */ const Uint32 VariableType : VariableTypeBits; /* 7.7 */ const Uint32 ImmutableSamplerAssigned : ImmutableSamplerFlagBits; -/* 8 */ const SPIRVShaderResourceAttribs& SpirvAttribs; -/* 16 */ const ShaderResourceLayoutVk& ParentResLayout; - - VkResource(const ShaderResourceLayoutVk& _ParentLayout, - const SPIRVShaderResourceAttribs& _SpirvAttribs, - SHADER_RESOURCE_VARIABLE_TYPE _VariableType, - uint32_t _Binding, - uint32_t _DescriptorSet, - Uint32 _CacheOffset, - Uint32 _SamplerInd, - bool _ImmutableSamplerAssigned = false)noexcept : - Binding {static_cast<decltype(Binding)>(_Binding) }, - DescriptorSet {static_cast<decltype(DescriptorSet)>(_DescriptorSet)}, - CacheOffset {_CacheOffset }, - SamplerInd {_SamplerInd }, - VariableType {_VariableType }, - ImmutableSamplerAssigned {_ImmutableSamplerAssigned ? 1U : 0U}, - SpirvAttribs {_SpirvAttribs }, - ParentResLayout {_ParentLayout } - { - VERIFY(_CacheOffset < (1 << CacheOffsetBits), "Cache offset (", _CacheOffset, ") exceeds max representable value ", (1 << CacheOffsetBits) ); - VERIFY(_SamplerInd < (1 << SamplerIndBits), "Sampler index (", _SamplerInd, ") exceeds max representable value ", (1 << SamplerIndBits) ); - VERIFY(_Binding <= std::numeric_limits<decltype(Binding)>::max(), "Binding (", _Binding, ") exceeds max representable value ", std::numeric_limits<decltype(Binding)>::max() ); - VERIFY(_DescriptorSet <= std::numeric_limits<decltype(DescriptorSet)>::max(), "Descriptor set (", _DescriptorSet, ") exceeds max representable value ", std::numeric_limits<decltype(DescriptorSet)>::max()); - } +/* 8 */ const SPIRVShaderResourceAttribs SpirvAttribs; +/* 16 */ const ShaderResourceLayoutVk& ParentResLayout; // clang-format on + VkResource(const ShaderResourceLayoutVk& _ParentLayout, + const SPIRVShaderResourceAttribs& _SpirvAttribs, + SHADER_RESOURCE_VARIABLE_TYPE _VariableType, + uint32_t _Binding, + uint32_t _DescriptorSet, + Uint32 _CacheOffset, + Uint32 _SamplerInd, + bool _ImmutableSamplerAssigned = false) noexcept; + + ~VkResource(); + // Checks if a resource is bound in ResourceCache at the given ArrayIndex bool IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const; @@ -279,11 +269,10 @@ public: #ifdef DILIGENT_DEVELOPMENT bool dvpVerifyBindings(const ShaderResourceCacheVk& ResourceCache) const; - static void dvpVerifyResourceLayoutDesc(Uint32 NumShaders, - const std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - bool VerifyVariables, - bool VerifyStaticSamplers); + static void dvpVerifyResourceLayoutDesc(const ShaderStages_t& ShaderStages, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + bool VerifyVariables, + bool VerifyStaticSamplers); #endif Uint32 GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE VarType) const @@ -300,13 +289,10 @@ public: const Char* GetShaderName() const { - return m_pResources->GetShaderName(); + return ""; // AZ TODO } - SHADER_TYPE GetShaderType() const - { - return m_pResources->GetShaderType(); - } + SHADER_TYPE GetShaderType() const { return m_ShaderType; } const VkResource& GetResource(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const { @@ -315,7 +301,7 @@ public: return Resources[GetResourceOffset(VarType, r)]; } - bool IsUsingSeparateSamplers() const { return !m_pResources->IsUsingCombinedSamplers(); } + bool IsUsingSeparateSamplers() const { return m_IsUsingSeparateSamplers; } private: Uint32 GetResourceOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const @@ -346,16 +332,12 @@ private: return m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES]; } - void AllocateMemory(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers); - - Uint32 FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, - Uint32 CurrResourceCount, - SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) const; + void AllocateMemory(IShader* pShader, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + bool AllocateImmutableSamplers); using ImmutableSamplerPtrType = RefCntAutoPtr<ISampler>; ImmutableSamplerPtrType& GetImmutableSampler(Uint32 n) noexcept @@ -366,16 +348,16 @@ private: } // clang-format off -/* 0 */ const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice; -/* 8 */ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer; +/* 0 */ const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice; +/* 8 */ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer; + +/*24 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES+1> m_NumResources = {}; - // We must use shared_ptr to reference ShaderResources instance, because - // there may be multiple objects referencing the same set of resources -/*24 */ std::shared_ptr<const SPIRVShaderResources> m_pResources; +/*32 */ Uint32 m_NumImmutableSamplers = 0; +/*36 */ bool m_IsUsingSeparateSamplers = false; +/*37 */ SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN; -/*40 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES+1> m_NumResources = {}; -/*48 */ Uint32 m_NumImmutableSamplers = 0; -/*56*/ // End of class +/*40 */ // End of class // clang-format on }; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp index dbba5b7e..1e6749f1 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp @@ -82,4 +82,7 @@ ATTACHMENT_STORE_OP VkAttachmentStoreOpToAttachmentStoreOp(VkAttachmentStoreOp V VkPipelineStageFlags PipelineStageFlagsToVkPipelineStageFlags(PIPELINE_STAGE_FLAGS PipelineStageFlags); VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags); + +VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType); + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp index 2fd063c9..6ed84171 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -40,28 +40,6 @@ namespace Diligent { - -static VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType) -{ - static_assert(SHADER_TYPE_LAST == 0x080, "Please update the switch below to handle the new shader type"); - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; - case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; - case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; - case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; - case SHADER_TYPE_AMPLIFICATION: return VK_SHADER_STAGE_TASK_BIT_NV; - case SHADER_TYPE_MESH: return VK_SHADER_STAGE_MESH_BIT_NV; - // clang-format on - default: - UNEXPECTED("Unknown shader type"); - return VK_SHADER_STAGE_VERTEX_BIT; - } -} - class ResourceTypeToVkDescriptorType { public: diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 75dd3263..29d16239 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -129,352 +129,376 @@ RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc( return RPDesc; } -static std::vector<uint32_t> StripReflection(const std::vector<uint32_t>& OriginalSPIRV) +static bool StripReflection(std::vector<uint32_t>& SPIRV) { #if DILIGENT_NO_HLSL - return OriginalSPIRV; + return false; #else std::vector<uint32_t> StrippedSPIRV; spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); // Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions // removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation. SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); - auto res = SpirvOptimizer.Run(OriginalSPIRV.data(), OriginalSPIRV.size(), &StrippedSPIRV); - if (!res) + if (SpirvOptimizer.Run(SPIRV.data(), SPIRV.size(), &StrippedSPIRV)) { - // Optimized SPIRV may be invalid - StrippedSPIRV.clear(); + SPIRV = std::move(StrippedSPIRV); + return true; } - return StrippedSPIRV; + else + return false; #endif } -PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pDeviceVk, - const PipelineStateCreateInfo& CreateInfo) : - TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, - m_SRBMemAllocator{GetRawAllocator()} +static void InitializeShaderStages(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, + const PipelineStateVkImpl::ShaderStages_t& ShaderStages, + PipelineStateVkImpl::ShaderSPIRVs_t& ShaderSPIRVs, + std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules, + std::vector<VkPipelineShaderStageCreateInfo>& Stages) { - m_ResourceLayoutIndex.fill(-1); - - const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + VERIFY_EXPR(ShaderStages.size() == ShaderSPIRVs.size()); - std::array<std::shared_ptr<const SPIRVShaderResources>, MAX_SHADERS_IN_PIPELINE> ShaderResources; - std::array<std::vector<uint32_t>, MAX_SHADERS_IN_PIPELINE> ShaderSPIRVs; - - // clang-format off - static_assert((sizeof(ShaderResourceLayoutVk) % sizeof(void*)) == 0, "sizeof(ShaderResourceLayoutVk) is expected to be a multiple of sizeof(void*)"); - static_assert((sizeof(ShaderResourceCacheVk) % sizeof(void*)) == 0, "sizeof(ShaderResourceCacheVk) is expected to be a multiple of sizeof(void*)"); - static_assert((sizeof(ShaderVariableManagerVk) % sizeof(void*)) == 0, "sizeof(ShaderVariableManagerVk) is expected to be a multiple of sizeof(void*)"); - // clang-format on - const auto MemSize = (sizeof(ShaderResourceLayoutVk) * 2 + sizeof(ShaderResourceCacheVk) + sizeof(ShaderVariableManagerVk)) * m_NumShaders; - auto* const pRawMem = - ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutVk, ShaderResourceCacheVk, and ShaderVariableManagerVk arrays", MemSize); - - m_ShaderResourceLayouts = reinterpret_cast<ShaderResourceLayoutVk*>(pRawMem); - m_StaticResCaches = reinterpret_cast<ShaderResourceCacheVk*>(m_ShaderResourceLayouts + m_NumShaders * 2); - m_StaticVarsMgrs = reinterpret_cast<ShaderVariableManagerVk*>(m_StaticResCaches + m_NumShaders); - - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk{LogicalDevice}; - auto* pShaderVk = GetShader<const ShaderVkImpl>(s); - ShaderResources[s] = pShaderVk->GetShaderResources(); - ShaderSPIRVs[s] = pShaderVk->GetSPIRV(); - - const auto ShaderType = pShaderVk->GetDesc().ShaderType; - const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); - m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s); - - auto* pStaticResLayout = new (m_ShaderResourceLayouts + m_NumShaders + s) ShaderResourceLayoutVk{LogicalDevice}; - auto* pStaticResCache = new (m_StaticResCaches + s) ShaderResourceCacheVk{ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources}; - pStaticResLayout->InitializeStaticResourceLayout(ShaderResources[s], GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]); - - new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, *pStaticResLayout, GetRawAllocator(), nullptr, 0, *pStaticResCache}; - } - ShaderResourceLayoutVk::Initialize(pDeviceVk, m_NumShaders, m_ShaderResourceLayouts, ShaderResources.data(), GetRawAllocator(), - m_Desc.ResourceLayout, ShaderSPIRVs.data(), m_PipelineLayout, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); - m_PipelineLayout.Finalize(LogicalDevice); + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(ShaderStages[s].second); + auto& SPIRV = ShaderSPIRVs[s]; + const auto ShaderType = ShaderStages[s].first; - if (m_Desc.SRBAllocationGranularity > 1) - { - std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + VkPipelineShaderStageCreateInfo StageCI = {}; - Uint32 UnusedNumVars = 0; - ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(m_ShaderResourceLayouts[s], AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars); - } - - Uint32 NumSets = 0; - auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets); - auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data()); - - m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, m_NumShaders, ShaderVariableDataSizes.data(), 1, &CacheMemorySize); - } - - // Create shader modules and initialize shader stages - std::array<VkPipelineShaderStageCreateInfo, MAX_SHADERS_IN_PIPELINE> ShaderStages = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - auto* pShaderVk = GetShader<const ShaderVkImpl>(s); - auto ShaderType = pShaderVk->GetDesc().ShaderType; - - auto& StageCI = ShaderStages[s]; StageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; StageCI.pNext = nullptr; StageCI.flags = 0; // reserved for future use - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: StageCI.stage = VK_SHADER_STAGE_VERTEX_BIT; break; - case SHADER_TYPE_HULL: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; break; - case SHADER_TYPE_DOMAIN: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; break; - case SHADER_TYPE_GEOMETRY: StageCI.stage = VK_SHADER_STAGE_GEOMETRY_BIT; break; - case SHADER_TYPE_PIXEL: StageCI.stage = VK_SHADER_STAGE_FRAGMENT_BIT; break; - case SHADER_TYPE_COMPUTE: StageCI.stage = VK_SHADER_STAGE_COMPUTE_BIT; break; - case SHADER_TYPE_AMPLIFICATION: StageCI.stage = VK_SHADER_STAGE_TASK_BIT_NV; break; - case SHADER_TYPE_MESH: StageCI.stage = VK_SHADER_STAGE_MESH_BIT_NV; break; - default: UNEXPECTED("Unknown shader type"); - // clang-format on - } + StageCI.stage = ShaderTypeToVkShaderStageFlagBit(ShaderType); VkShaderModuleCreateInfo ShaderModuleCI = {}; ShaderModuleCI.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; ShaderModuleCI.pNext = nullptr; ShaderModuleCI.flags = 0; - const auto& SPIRV = ShaderSPIRVs[s]; // We have to strip reflection instructions to fix the follownig validation error: // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string // Optimizer also performs validation and may catch problems with the byte code. - auto StrippedSPIRV = StripReflection(SPIRV); - if (!StrippedSPIRV.empty()) - { - ShaderModuleCI.codeSize = StrippedSPIRV.size() * sizeof(uint32_t); - ShaderModuleCI.pCode = StrippedSPIRV.data(); - } - else - { + if (!StripReflection(SPIRV)) LOG_ERROR("Failed to strip reflection information from shader '", pShaderVk->GetDesc().Name, "'. This may indicate a problem with the byte code."); - ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); - ShaderModuleCI.pCode = SPIRV.data(); - } - m_ShaderModules[s] = LogicalDevice.CreateShaderModule(ShaderModuleCI, pShaderVk->GetDesc().Name); + ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); + ShaderModuleCI.pCode = SPIRV.data(); + + ShaderModules.push_back(LogicalDevice.CreateShaderModule(ShaderModuleCI, pShaderVk->GetDesc().Name)); - StageCI.module = m_ShaderModules[s]; + StageCI.module = ShaderModules.back(); StageCI.pName = pShaderVk->GetEntryPoint(); StageCI.pSpecializationInfo = nullptr; + + Stages.push_back(StageCI); } - // Create pipeline - if (m_Desc.IsComputePipeline()) - { - auto& ComputePipeline = m_Desc.ComputePipeline; + VERIFY_EXPR(ShaderModules.size() == Stages.size()); +} + + +static void CreateComputePipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector<VkPipelineShaderStageCreateInfo>& Stages, + const PipelineLayout& Layout, + const PipelineStateDesc& Desc, + VulkanUtilities::PipelineWrapper& Pipeline) +{ + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + + VkComputePipelineCreateInfo PipelineCI = {}; + + PipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + PipelineCI.pNext = nullptr; +#ifdef DILIGENT_DEBUG + PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; +#endif + PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from + PipelineCI.basePipelineIndex = -1; // an index into the pCreateInfos parameter to use as a pipeline to derive from - if (ComputePipeline.pCS == nullptr) - LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc"); + PipelineCI.stage = Stages[0]; + PipelineCI.layout = Layout.GetVkPipelineLayout(); - VkComputePipelineCreateInfo PipelineCI = {}; + Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, Desc.Name); +} + + +static void CreateGraphicsPipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector<VkPipelineShaderStageCreateInfo>& Stages, + const PipelineLayout& Layout, + const PipelineStateDesc& Desc, + VulkanUtilities::PipelineWrapper& Pipeline, + RefCntAutoPtr<IRenderPass>& pRenderPass) +{ + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); + auto& GraphicsPipeline = Desc.GraphicsPipeline; + auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); + + if (pRenderPass == nullptr) + { + RenderPassCache::RenderPassCacheKey Key{ + GraphicsPipeline.NumRenderTargets, + GraphicsPipeline.SmplDesc.Count, + GraphicsPipeline.RTVFormats, + GraphicsPipeline.DSVFormat}; + pRenderPass = RPCache.GetRenderPass(Key); + } + + VkGraphicsPipelineCreateInfo PipelineCI = {}; - PipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - PipelineCI.pNext = nullptr; + PipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + PipelineCI.pNext = nullptr; #ifdef DILIGENT_DEBUG - PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; + PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; #endif - PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from - PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from - PipelineCI.stage = ShaderStages[0]; - PipelineCI.layout = m_PipelineLayout.GetVkPipelineLayout(); + PipelineCI.stageCount = static_cast<Uint32>(Stages.size()); + PipelineCI.pStages = Stages.data(); + PipelineCI.layout = Layout.GetVkPipelineLayout(); + + VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {}; + + std::array<VkVertexInputBindingDescription, MAX_LAYOUT_ELEMENTS> BindingDescriptions; + std::array<VkVertexInputAttributeDescription, MAX_LAYOUT_ELEMENTS> AttributeDescription; + InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, VertexInputStateCI, BindingDescriptions, AttributeDescription); + PipelineCI.pVertexInputState = &VertexInputStateCI; - m_Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); + + VkPipelineInputAssemblyStateCreateInfo InputAssemblyCI = {}; + + InputAssemblyCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + InputAssemblyCI.pNext = nullptr; + InputAssemblyCI.flags = 0; // reserved for future use + InputAssemblyCI.primitiveRestartEnable = VK_FALSE; + PipelineCI.pInputAssemblyState = &InputAssemblyCI; + + + VkPipelineTessellationStateCreateInfo TessStateCI = {}; + + TessStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + TessStateCI.pNext = nullptr; + TessStateCI.flags = 0; // reserved for future use + PipelineCI.pTessellationState = &TessStateCI; + + if (Desc.PipelineType == PIPELINE_TYPE_MESH) + { + // Input assembly is not used in the mesh pipeline, so topology may contain any value. + // Validation layers may generate a warning if point_list topology is used, so use MAX_ENUM value. + InputAssemblyCI.topology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + + // Vertex input state and tessellation state are ignored in a mesh pipeline and should be null. + PipelineCI.pVertexInputState = nullptr; + PipelineCI.pTessellationState = nullptr; } else { - const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); - auto& GraphicsPipeline = m_Desc.GraphicsPipeline; - auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); + PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(GraphicsPipeline.PrimitiveTopology, InputAssemblyCI.topology, TessStateCI.patchControlPoints); + } - if (m_pRenderPass == nullptr) + VkPipelineViewportStateCreateInfo ViewPortStateCI = {}; + + ViewPortStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + ViewPortStateCI.pNext = nullptr; + ViewPortStateCI.flags = 0; // reserved for future use + ViewPortStateCI.viewportCount = + GraphicsPipeline.NumViewports; // Even though we use dynamic viewports, the number of viewports used + // by the pipeline is still specified by the viewportCount member (23.5) + ViewPortStateCI.pViewports = nullptr; // We will be using dynamic viewport & scissor states + ViewPortStateCI.scissorCount = ViewPortStateCI.viewportCount; // the number of scissors must match the number of viewports (23.5) + // (why the hell it is in the struct then?) + VkRect2D ScissorRect = {}; + if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + { + ViewPortStateCI.pScissors = nullptr; // Ignored if the scissor state is dynamic + } + else + { + const auto& Props = PhysicalDevice.GetProperties(); + // There are limitiations on the viewport width and height (23.5), but + // it is not clear if there are limitations on the scissor rect width and + // height + ScissorRect.extent.width = Props.limits.maxViewportDimensions[0]; + ScissorRect.extent.height = Props.limits.maxViewportDimensions[1]; + ViewPortStateCI.pScissors = &ScissorRect; + } + PipelineCI.pViewportState = &ViewPortStateCI; + + VkPipelineRasterizationStateCreateInfo RasterizerStateCI = + RasterizerStateDesc_To_VkRasterizationStateCI(GraphicsPipeline.RasterizerDesc); + PipelineCI.pRasterizationState = &RasterizerStateCI; + + // Multisample state (24) + VkPipelineMultisampleStateCreateInfo MSStateCI = {}; + + MSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + MSStateCI.pNext = nullptr; + MSStateCI.flags = 0; // reserved for future use + // If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of + // pMultisampleState must be the same as the sample count for those subpass attachments + MSStateCI.rasterizationSamples = static_cast<VkSampleCountFlagBits>(GraphicsPipeline.SmplDesc.Count); + MSStateCI.sampleShadingEnable = VK_FALSE; + MSStateCI.minSampleShading = 0; // a minimum fraction of sample shading if sampleShadingEnable is set to VK_TRUE. + uint32_t SampleMask[] = {GraphicsPipeline.SampleMask, 0}; // Vulkan spec allows up to 64 samples + MSStateCI.pSampleMask = SampleMask; // an array of static coverage information that is ANDed with + // the coverage information generated during rasterization (25.3) + MSStateCI.alphaToCoverageEnable = VK_FALSE; // whether a temporary coverage value is generated based on + // the alpha component of the fragment's first color output + MSStateCI.alphaToOneEnable = VK_FALSE; // whether the alpha component of the fragment's first color output is replaced with one + PipelineCI.pMultisampleState = &MSStateCI; + + VkPipelineDepthStencilStateCreateInfo DepthStencilStateCI = + DepthStencilStateDesc_To_VkDepthStencilStateCI(GraphicsPipeline.DepthStencilDesc); + PipelineCI.pDepthStencilState = &DepthStencilStateCI; + + const auto& RPDesc = pRenderPass->GetDesc(); + const auto NumRTAttachments = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex].RenderTargetAttachmentCount; + VERIFY_EXPR(GraphicsPipeline.pRenderPass != nullptr || GraphicsPipeline.NumRenderTargets == NumRTAttachments); + std::vector<VkPipelineColorBlendAttachmentState> ColorBlendAttachmentStates(NumRTAttachments); + + VkPipelineColorBlendStateCreateInfo BlendStateCI = {}; + + BlendStateCI.pAttachments = !ColorBlendAttachmentStates.empty() ? ColorBlendAttachmentStates.data() : nullptr; + BlendStateCI.attachmentCount = NumRTAttachments; // must equal the colorAttachmentCount for the subpass + // in which this pipeline is used. + BlendStateDesc_To_VkBlendStateCI(GraphicsPipeline.BlendDesc, BlendStateCI, ColorBlendAttachmentStates); + PipelineCI.pColorBlendState = &BlendStateCI; + + + VkPipelineDynamicStateCreateInfo DynamicStateCI = {}; + + DynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + DynamicStateCI.pNext = nullptr; + DynamicStateCI.flags = 0; // reserved for future use + std::vector<VkDynamicState> DynamicStates = { - RenderPassCache::RenderPassCacheKey Key{ - GraphicsPipeline.NumRenderTargets, - GraphicsPipeline.SmplDesc.Count, - GraphicsPipeline.RTVFormats, - GraphicsPipeline.DSVFormat}; - m_pRenderPass = RPCache.GetRenderPass(Key); - } + VK_DYNAMIC_STATE_VIEWPORT, // pViewports state in VkPipelineViewportStateCreateInfo will be ignored and must be + // set dynamically with vkCmdSetViewport before any draw commands. The number of viewports + // used by a pipeline is still specified by the viewportCount member of + // VkPipelineViewportStateCreateInfo. - VkGraphicsPipelineCreateInfo PipelineCI = {}; + VK_DYNAMIC_STATE_BLEND_CONSTANTS, // blendConstants state in VkPipelineColorBlendStateCreateInfo will be ignored + // and must be set dynamically with vkCmdSetBlendConstants - PipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - PipelineCI.pNext = nullptr; -#ifdef DILIGENT_DEBUG - PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; -#endif + VK_DYNAMIC_STATE_STENCIL_REFERENCE // pecifies that the reference state in VkPipelineDepthStencilStateCreateInfo + // for both front and back will be ignored and must be set dynamically + // with vkCmdSetStencilReference + }; - PipelineCI.stageCount = m_NumShaders; - PipelineCI.pStages = ShaderStages.data(); - PipelineCI.layout = m_PipelineLayout.GetVkPipelineLayout(); + if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + { + // pScissors state in VkPipelineViewportStateCreateInfo will be ignored and must be set + // dynamically with vkCmdSetScissor before any draw commands. The number of scissor rectangles + // used by a pipeline is still specified by the scissorCount member of + // VkPipelineViewportStateCreateInfo. + DynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR); + } + DynamicStateCI.dynamicStateCount = static_cast<uint32_t>(DynamicStates.size()); + DynamicStateCI.pDynamicStates = DynamicStates.data(); + PipelineCI.pDynamicState = &DynamicStateCI; - VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {}; - std::array<VkVertexInputBindingDescription, MAX_LAYOUT_ELEMENTS> BindingDescriptions; - std::array<VkVertexInputAttributeDescription, MAX_LAYOUT_ELEMENTS> AttributeDescription; - InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, VertexInputStateCI, BindingDescriptions, AttributeDescription); - PipelineCI.pVertexInputState = &VertexInputStateCI; + PipelineCI.renderPass = pRenderPass.RawPtr<IRenderPassVk>()->GetVkRenderPass(); + PipelineCI.subpass = Desc.GraphicsPipeline.SubpassIndex; + PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from + PipelineCI.basePipelineIndex = -1; // an index into the pCreateInfos parameter to use as a pipeline to derive from + Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, Desc.Name); +} - VkPipelineInputAssemblyStateCreateInfo InputAssemblyCI = {}; - InputAssemblyCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - InputAssemblyCI.pNext = nullptr; - InputAssemblyCI.flags = 0; // reserved for future use - InputAssemblyCI.primitiveRestartEnable = VK_FALSE; - PipelineCI.pInputAssemblyState = &InputAssemblyCI; +PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVk, + const PipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + m_ResourceLayoutIndex.fill(-1); + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); - VkPipelineTessellationStateCreateInfo TessStateCI = {}; + ShaderStages_t ShaderStages; + ShaderSPIRVs_t ShaderSPIRVs; + ExtractShaders(ShaderStages); - TessStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - TessStateCI.pNext = nullptr; - TessStateCI.flags = 0; // reserved for future use - PipelineCI.pTessellationState = &TessStateCI; + ShaderSPIRVs.resize(ShaderStages.size()); + for (size_t s = 0; s < ShaderSPIRVs.size(); ++s) + { + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(ShaderStages[s].second); + ShaderSPIRVs[s] = pShaderVk->GetSPIRV(); + } - if (m_Desc.PipelineType == PIPELINE_TYPE_MESH) - { - // Input assembly is not used in the mesh pipeline, so topology may contain any value. - // Validation layers may generate a warning if point_list topology is used, so use MAX_ENUM value. - InputAssemblyCI.topology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + // clang-format off + static_assert((sizeof(ShaderResourceLayoutVk) % sizeof(void*)) == 0, "sizeof(ShaderResourceLayoutVk) is expected to be a multiple of sizeof(void*)"); + static_assert((sizeof(ShaderResourceCacheVk) % sizeof(void*)) == 0, "sizeof(ShaderResourceCacheVk) is expected to be a multiple of sizeof(void*)"); + static_assert((sizeof(ShaderVariableManagerVk) % sizeof(void*)) == 0, "sizeof(ShaderVariableManagerVk) is expected to be a multiple of sizeof(void*)"); + // clang-format on + const auto MemSize = (sizeof(ShaderResourceLayoutVk) * 2 + sizeof(ShaderResourceCacheVk) + sizeof(ShaderVariableManagerVk)) * GetNumShaderTypes(); + auto* const pRawMem = + ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutVk, ShaderResourceCacheVk, and ShaderVariableManagerVk arrays", MemSize); - // Vertex input state and tessellation state are ignored in a mesh pipeline and should be null. - PipelineCI.pVertexInputState = nullptr; - PipelineCI.pTessellationState = nullptr; - } - else - { - PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(GraphicsPipeline.PrimitiveTopology, InputAssemblyCI.topology, TessStateCI.patchControlPoints); - } + m_ShaderResourceLayouts = reinterpret_cast<ShaderResourceLayoutVk*>(pRawMem); + m_StaticResCaches = reinterpret_cast<ShaderResourceCacheVk*>(m_ShaderResourceLayouts + GetNumShaderTypes() * 2); + m_StaticVarsMgrs = reinterpret_cast<ShaderVariableManagerVk*>(m_StaticResCaches + GetNumShaderTypes()); - VkPipelineViewportStateCreateInfo ViewPortStateCI = {}; - - ViewPortStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - ViewPortStateCI.pNext = nullptr; - ViewPortStateCI.flags = 0; // reserved for future use - ViewPortStateCI.viewportCount = - GraphicsPipeline.NumViewports; // Even though we use dynamic viewports, the number of viewports used - // by the pipeline is still specified by the viewportCount member (23.5) - ViewPortStateCI.pViewports = nullptr; // We will be using dynamic viewport & scissor states - ViewPortStateCI.scissorCount = ViewPortStateCI.viewportCount; // the number of scissors must match the number of viewports (23.5) - // (why the hell it is in the struct then?) - VkRect2D ScissorRect = {}; - if (GraphicsPipeline.RasterizerDesc.ScissorEnable) - { - ViewPortStateCI.pScissors = nullptr; // Ignored if the scissor state is dynamic - } - else - { - const auto& Props = PhysicalDevice.GetProperties(); - // There are limitiations on the viewport width and height (23.5), but - // it is not clear if there are limitations on the scissor rect width and - // height - ScissorRect.extent.width = Props.limits.maxViewportDimensions[0]; - ScissorRect.extent.height = Props.limits.maxViewportDimensions[1]; - ViewPortStateCI.pScissors = &ScissorRect; - } - PipelineCI.pViewportState = &ViewPortStateCI; - - VkPipelineRasterizationStateCreateInfo RasterizerStateCI = - RasterizerStateDesc_To_VkRasterizationStateCI(GraphicsPipeline.RasterizerDesc); - PipelineCI.pRasterizationState = &RasterizerStateCI; - - // Multisample state (24) - VkPipelineMultisampleStateCreateInfo MSStateCI = {}; - - MSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - MSStateCI.pNext = nullptr; - MSStateCI.flags = 0; // reserved for future use - // If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of - // pMultisampleState must be the same as the sample count for those subpass attachments - MSStateCI.rasterizationSamples = static_cast<VkSampleCountFlagBits>(GraphicsPipeline.SmplDesc.Count); - MSStateCI.sampleShadingEnable = VK_FALSE; - MSStateCI.minSampleShading = 0; // a minimum fraction of sample shading if sampleShadingEnable is set to VK_TRUE. - uint32_t SampleMask[] = {GraphicsPipeline.SampleMask, 0}; // Vulkan spec allows up to 64 samples - MSStateCI.pSampleMask = SampleMask; // an array of static coverage information that is ANDed with - // the coverage information generated during rasterization (25.3) - MSStateCI.alphaToCoverageEnable = VK_FALSE; // whether a temporary coverage value is generated based on - // the alpha component of the fragment's first color output - MSStateCI.alphaToOneEnable = VK_FALSE; // whether the alpha component of the fragment's first color output is replaced with one - PipelineCI.pMultisampleState = &MSStateCI; - - VkPipelineDepthStencilStateCreateInfo DepthStencilStateCI = - DepthStencilStateDesc_To_VkDepthStencilStateCI(GraphicsPipeline.DepthStencilDesc); - PipelineCI.pDepthStencilState = &DepthStencilStateCI; - - const auto& RPDesc = m_pRenderPass->GetDesc(); - const auto NumRTAttachments = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex].RenderTargetAttachmentCount; - VERIFY_EXPR(GraphicsPipeline.pRenderPass != nullptr || GraphicsPipeline.NumRenderTargets == NumRTAttachments); - std::vector<VkPipelineColorBlendAttachmentState> ColorBlendAttachmentStates(NumRTAttachments); - - VkPipelineColorBlendStateCreateInfo BlendStateCI = {}; - - BlendStateCI.pAttachments = !ColorBlendAttachmentStates.empty() ? ColorBlendAttachmentStates.data() : nullptr; - BlendStateCI.attachmentCount = NumRTAttachments; // must equal the colorAttachmentCount for the subpass - // in which this pipeline is used. - BlendStateDesc_To_VkBlendStateCI(GraphicsPipeline.BlendDesc, BlendStateCI, ColorBlendAttachmentStates); - PipelineCI.pColorBlendState = &BlendStateCI; - - - VkPipelineDynamicStateCreateInfo DynamicStateCI = {}; - - DynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - DynamicStateCI.pNext = nullptr; - DynamicStateCI.flags = 0; // reserved for future use - std::vector<VkDynamicState> DynamicStates = - { - VK_DYNAMIC_STATE_VIEWPORT, // pViewports state in VkPipelineViewportStateCreateInfo will be ignored and must be - // set dynamically with vkCmdSetViewport before any draw commands. The number of viewports - // used by a pipeline is still specified by the viewportCount member of - // VkPipelineViewportStateCreateInfo. + for (size_t s = 0; s < ShaderStages.size(); ++s) + { + new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk{LogicalDevice}; + + const auto ShaderType = ShaderStages[s].first; + auto& Shaders = ShaderStages[s].second; + const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); + m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s); - VK_DYNAMIC_STATE_BLEND_CONSTANTS, // blendConstants state in VkPipelineColorBlendStateCreateInfo will be ignored - // and must be set dynamically with vkCmdSetBlendConstants + auto* pStaticResLayout = new (m_ShaderResourceLayouts + ShaderStages.size() + s) ShaderResourceLayoutVk{LogicalDevice}; + auto* pStaticResCache = new (m_StaticResCaches + s) ShaderResourceCacheVk{ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources}; + pStaticResLayout->InitializeStaticResourceLayout(Shaders, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]); - VK_DYNAMIC_STATE_STENCIL_REFERENCE // pecifies that the reference state in VkPipelineDepthStencilStateCreateInfo - // for both front and back will be ignored and must be set dynamically - // with vkCmdSetStencilReference - }; + new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, *pStaticResLayout, GetRawAllocator(), nullptr, 0, *pStaticResCache}; + } + ShaderResourceLayoutVk::Initialize(pDeviceVk, ShaderStages, m_ShaderResourceLayouts, GetRawAllocator(), + m_Desc.ResourceLayout, ShaderSPIRVs, m_PipelineLayout, + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); + m_PipelineLayout.Finalize(LogicalDevice); - if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + if (m_Desc.SRBAllocationGranularity > 1) + { + std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {}; + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { - // pScissors state in VkPipelineViewportStateCreateInfo will be ignored and must be set - // dynamically with vkCmdSetScissor before any draw commands. The number of scissor rectangles - // used by a pipeline is still specified by the scissorCount member of - // VkPipelineViewportStateCreateInfo. - DynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR); + const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + + Uint32 UnusedNumVars = 0; + ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(m_ShaderResourceLayouts[s], AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars); } - DynamicStateCI.dynamicStateCount = static_cast<uint32_t>(DynamicStates.size()); - DynamicStateCI.pDynamicStates = DynamicStates.data(); - PipelineCI.pDynamicState = &DynamicStateCI; + Uint32 NumSets = 0; + auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets); + auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data()); + + m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderTypes(), ShaderVariableDataSizes.data(), 1, &CacheMemorySize); + } - PipelineCI.renderPass = GetRenderPass()->GetVkRenderPass(); - PipelineCI.subpass = m_Desc.GraphicsPipeline.SubpassIndex; - PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from - PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from + // Create shader modules and initialize shader stages + std::vector<VkPipelineShaderStageCreateInfo> VkShaderStages; + std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules; + InitializeShaderStages(LogicalDevice, ShaderStages, ShaderSPIRVs, ShaderModules, VkShaderStages); - m_Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); + // Create pipeline + switch (m_Desc.PipelineType) + { + // clang-format off + case PIPELINE_TYPE_GRAPHICS: + case PIPELINE_TYPE_MESH: CreateGraphicsPipeline( pDeviceVk, VkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline, m_pRenderPass); break; + case PIPELINE_TYPE_COMPUTE: CreateComputePipeline( pDeviceVk, VkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline); break; + default: UNEXPECTED("unknown pipeline type"); + // clang-format on } m_HasStaticResources = false; m_HasNonStaticResources = false; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) != 0) @@ -493,21 +517,13 @@ PipelineStateVkImpl::~PipelineStateVkImpl() m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask); m_PipelineLayout.Release(m_pDevice, m_Desc.CommandQueueMask); - for (auto& ShaderModule : m_ShaderModules) - { - if (ShaderModule != VK_NULL_HANDLE) - { - m_pDevice->SafeReleaseDeviceObject(std::move(ShaderModule), m_Desc.CommandQueueMask); - } - } - auto& RawAllocator = GetRawAllocator(); - for (Uint32 s = 0; s < m_NumShaders * 2; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes() * 2; ++s) { m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk(); } - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { m_StaticResCaches[s].~ShaderResourceCacheVk(); m_StaticVarsMgrs[s].DestroyVariables(GetRawAllocator()); @@ -547,27 +563,27 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const #ifdef DILIGENT_DEBUG { bool IsCompatibleShaders = true; - if (m_NumShaders != pPSOVk->m_NumShaders) + if (GetNumShaderTypes() != pPSOVk->GetNumShaderTypes()) IsCompatibleShaders = false; if (IsCompatibleShaders) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { - auto* pShader0 = GetShader<const ShaderVkImpl>(s); - auto* pShader1 = pPSOVk->GetShader<const ShaderVkImpl>(s); - if (pShader0->GetDesc().ShaderType != pShader1->GetDesc().ShaderType) + if (GetShaderTypes()[s] != pPSOVk->GetShaderTypes()[s]) { IsCompatibleShaders = false; break; } - const auto* pRes0 = pShader0->GetShaderResources().get(); + + // AZ TODO + /*const auto* pRes0 = pShader0->GetShaderResources().get(); const auto* pRes1 = pShader1->GetShaderResources().get(); if (!pRes0->IsCompatibleWith(*pRes1)) { IsCompatibleShaders = false; break; - } + }*/ } } @@ -621,7 +637,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind auto& ResourceCache = pResBindingVkImpl->GetResourceCache(); #ifdef DILIGENT_DEVELOPMENT - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { m_ShaderResourceLayouts[s].dvpVerifyBindings(ResourceCache); } @@ -656,7 +672,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind // Allocate vulkan descriptor set for dynamic resources DynamicDescrSet = pCtxVkImpl->AllocateDynamicDescriptorSet(DynamicDescriptorSetVkLayout, DynamicDescrSetName); // Commit all dynamic resource descriptors - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) != 0) @@ -673,7 +689,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind void PipelineStateVkImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { auto ShaderType = GetStaticShaderResLayout(s).GetShaderType(); if ((ShaderType & ShaderFlags) != 0) @@ -717,17 +733,17 @@ IShaderResourceVariable* PipelineStateVkImpl::GetStaticVariableByIndex(SHADER_TY void PipelineStateVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { const auto& StaticResLayout = GetStaticShaderResLayout(s); const auto& StaticResCache = GetStaticResCache(s); + #ifdef DILIGENT_DEVELOPMENT if (!StaticResLayout.dvpVerifyBindings(StaticResCache)) { - const auto* pShaderVk = GetShader<const ShaderVkImpl>(s); LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", GetDesc().Name, "' will not be successfully initialized because not all static resource bindings in shader '", - pShaderVk->GetDesc().Name, + GetShaderTypeLiteralName(GetShaderTypes()[s]), "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method."); } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp index 53a92a59..75f3bb37 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp @@ -49,8 +49,8 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pR { m_ResourceLayoutIndex.fill(-1); - auto* ppShaders = pPSO->GetShaders(); - m_NumShaders = static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaders()); + auto* pShaderTypes = pPSO->GetShaderTypes(); + m_NumShaders = static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaderTypes()); auto* pRenderDeviceVkImpl = pPSO->GetDevice(); // This will only allocate memory and initialize descriptor sets in the resource cache @@ -62,9 +62,7 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pR for (Uint32 s = 0; s < m_NumShaders; ++s) { - auto* pShader = ppShaders[s]; - auto ShaderType = pShader->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPSO->GetDesc().PipelineType); + auto ShaderInd = GetShaderTypePipelineIndex(pShaderTypes[s], pPSO->GetDesc().PipelineType); m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index 4f28af80..1f798eb9 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -103,36 +103,40 @@ ShaderResourceLayoutVk::~ShaderResourceLayoutVk() GetImmutableSampler(s).~ImmutableSamplerPtrType(); } -void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers) +void ShaderResourceLayoutVk::AllocateMemory(IShader* pShader, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + bool AllocateImmutableSamplers) { VERIFY(!m_ResourceBuffer, "Memory has already been initialized"); - VERIFY_EXPR(!m_pResources); - VERIFY_EXPR(pSrcResources); + VERIFY_EXPR(pShader != nullptr); + VERIFY_EXPR(m_ShaderType == SHADER_TYPE_UNKNOWN); - m_pResources = std::move(pSrcResources); - - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - const auto ShaderType = m_pResources->GetShaderType(); - const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + m_ShaderType = pShader->GetDesc().ShaderType; // Count the number of resources to allocate all needed memory - m_pResources->ProcessResources( - [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) // - { - auto VarType = FindShaderVariableType(ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); - if (IsAllowedType(VarType, AllowedTypeBits)) + { + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto pResources = pShaderVk->GetShaderResources(); + const auto* CombinedSamplerSuffix = pResources->GetCombinedSamplerSuffix(); + VERIFY_EXPR(pResources->GetShaderType() == m_ShaderType); + pResources->ProcessResources( + [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) // { - // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app + auto VarType = FindShaderVariableType(m_ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); + if (IsAllowedType(VarType, AllowedTypeBits)) + { + // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app - VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits<Uint16>::max()}, "Number of resources exceeds Uint16 maximum representable value"); - ++m_NumResources[VarType]; - } - } // - ); + VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits<Uint16>::max()}, "Number of resources exceeds Uint16 maximum representable value"); + ++m_NumResources[VarType]; + } + } // + ); + m_IsUsingSeparateSamplers = !pResources->IsUsingCombinedSamplers(); + } Uint32 TotalResources = 0; for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) @@ -148,7 +152,7 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderRes for (Uint32 s = 0; s < ResourceLayoutDesc.NumStaticSamplers; ++s) { const auto& StSamDesc = ResourceLayoutDesc.StaticSamplers[s]; - if ((StSamDesc.ShaderStages & ShaderType) != 0) + if ((StSamDesc.ShaderStages & m_ShaderType) != 0) ++m_NumImmutableSamplers; } } @@ -169,56 +173,99 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderRes } -void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - ShaderResourceCacheVk& StaticResourceCache) +Uint32 FindAssignedSampler(const ShaderResourceLayoutVk& Layout, + const SPIRVShaderResources& Resources, + const SPIRVShaderResourceAttribs& SepImg, + Uint32 CurrResourceCount, + SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) +{ + using VkResource = ShaderResourceLayoutVk::VkResource; + VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + + Uint32 SamplerInd = VkResource::InvalidSamplerInd; + if (Resources.IsUsingCombinedSamplers() && SepImg.IsValidSepSamplerAssigned()) + { + const auto& SepSampler = Resources.GetAssignedSepSampler(SepImg); + for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) + { + const auto& Res = Layout.GetResource(ImgVarType, SamplerInd); + if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) + { + VERIFY(ImgVarType == Res.GetVariableType(), + "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name, + "' is not consistent with the type (", GetShaderVariableTypeLiteralName(Res.GetVariableType()), + ") of the separate sampler '", SepSampler.Name, + "' that is assigned to it. " + "This should never happen as when HLSL-style combined texture samplers are used, the type of the sampler " + "is derived from the type of the corresponding separate image."); + break; + } + } + if (SamplerInd == CurrResourceCount) + { + LOG_ERROR("Unable to find separate sampler '", SepSampler.Name, "' assigned to separate image '", SepImg.Name, "' in the list of already created resources. This seems to be a bug."); + SamplerInd = VkResource::InvalidSamplerInd; + } + } + return SamplerInd; +} + + +void ShaderResourceLayoutVk::InitializeStaticResourceLayout(IShader* pShader, + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderResourceCacheVk& StaticResourceCache) { const auto AllowedVarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; // We do not need immutable samplers in static shader resource layout as they // are relevant only when the main layout is initialized constexpr bool AllocateImmutableSamplers = false; - AllocateMemory(std::move(pSrcResources), LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, AllocateImmutableSamplers); + AllocateMemory(pShader, LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, AllocateImmutableSamplers); std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrResInd = {}; Uint32 StaticResCacheSize = 0; - const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1); - const auto ShaderType = m_pResources->GetShaderType(); - const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); + const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1); - m_pResources->ProcessResources( - [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) // - { - auto VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix); - if (!IsAllowedType(VarType, AllowedTypeBits)) - return; + { + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto pResources = pShaderVk->GetShaderResources(); + const auto* CombinedSamplerSuffix = pResources->GetCombinedSamplerSuffix(); - Int32 SrcImmutableSamplerInd = -1; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || - Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) + pResources->ProcessResources( + [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) // { - // Only search for the immutable sampler for combined image samplers and separate samplers - SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, CombinedSamplerSuffix); - // For immutable separate samplers we allocate VkResource instances, but they are never exposed to the app - } + auto VarType = FindShaderVariableType(m_ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix); + if (!IsAllowedType(VarType, AllowedTypeBits)) + return; - Uint32 Binding = Attribs.Type; - Uint32 DescriptorSet = 0; - Uint32 CacheOffset = StaticResCacheSize; - StaticResCacheSize += Attribs.ArraySize; + Int32 SrcImmutableSamplerInd = -1; + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || + Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) + { + // Only search for the immutable sampler for combined image samplers and separate samplers + SrcImmutableSamplerInd = FindImmutableSampler(m_ShaderType, ResourceLayoutDesc, Attribs, CombinedSamplerSuffix); + // For immutable separate samplers we allocate VkResource instances, but they are never exposed to the app + } - Uint32 SamplerInd = VkResource::InvalidSamplerInd; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) - { - // Separate samplers are enumerated before separate images, so the sampler - // assigned to this separate image must have already been created. - SamplerInd = FindAssignedSampler(Attribs, CurrResInd[VarType], VarType); - } - ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource(*this, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, SrcImmutableSamplerInd >= 0); - } // - ); + Uint32 Binding = Attribs.Type; + Uint32 DescriptorSet = 0; + Uint32 CacheOffset = StaticResCacheSize; + StaticResCacheSize += Attribs.ArraySize; + + Uint32 SamplerInd = VkResource::InvalidSamplerInd; + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) + { + // Separate samplers are enumerated before separate images, so the sampler + // assigned to this separate image must have already been created. + SamplerInd = FindAssignedSampler(*this, *pResources, Attribs, CurrResInd[VarType], VarType); + } + ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource(*this, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, SrcImmutableSamplerInd >= 0); + } // + ); + } #ifdef DILIGENT_DEBUG for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) @@ -235,25 +282,24 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr<cons } #ifdef DILIGENT_DEVELOPMENT -void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 NumShaders, - const std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - bool VerifyVariables, - bool VerifyStaticSamplers) +void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const ShaderStages_t& ShaderStages, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + bool VerifyVariables, + bool VerifyStaticSamplers) { - auto GetAllowedShadersString = [&](SHADER_TYPE ShaderStages) // + auto GetAllowedShadersString = [&](SHADER_TYPE Stages) // { std::string ShadersStr; - while (ShaderStages != SHADER_TYPE_UNKNOWN) + while (Stages != SHADER_TYPE_UNKNOWN) { - const auto ShaderType = ShaderStages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(ShaderStages) - 1)); + const auto ShaderType = Stages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(Stages) - 1)); const char* ShaderName = nullptr; - for (Uint32 s = 0; s < NumShaders; ++s) + + for (size_t s = 0; s < ShaderStages.size(); ++s) { - const auto& Resources = *pShaderResources[s]; - if ((ShaderStages & Resources.GetShaderType()) != 0) + if ((Stages & ShaderStages[s].first) != 0) { - ShaderName = Resources.GetShaderName(); + ShaderName = ShaderStages[s].second->GetDesc().Name; break; } } @@ -274,7 +320,7 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } ShadersStr.append(")"); - ShaderStages &= ~ShaderType; + Stages &= ~ShaderType; } return ShadersStr; }; @@ -291,9 +337,10 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } bool VariableFound = false; - for (Uint32 s = 0; s < NumShaders && !VariableFound; ++s) + for (size_t s = 0; s < ShaderStages.size() && !VariableFound; ++s) { - const auto& Resources = *pShaderResources[s]; + const auto* pShaderVk = ValidatedCast<ShaderVkImpl>(ShaderStages[s].second); + const auto& Resources = *pShaderVk->GetShaderResources(); if ((VarDesc.ShaderStages & Resources.GetShaderType()) != 0) { for (Uint32 res = 0; res < Resources.GetTotalResources() && !VariableFound; ++res) @@ -324,9 +371,10 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } bool SamplerFound = false; - for (Uint32 s = 0; s < NumShaders && !SamplerFound; ++s) + for (size_t s = 0; s < ShaderStages.size() && !SamplerFound; ++s) { - const auto& Resources = *pShaderResources[s]; + const auto* pShaderVk = ValidatedCast<ShaderVkImpl>(ShaderStages[s].second); + const auto& Resources = *pShaderVk->GetShaderResources(); if ((StSamDesc.ShaderStages & Resources.GetShaderType()) == 0) continue; @@ -363,32 +411,31 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } #endif -void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice, - Uint32 NumShaders, - ShaderResourceLayoutVk Layouts[], - std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - std::vector<uint32_t> SPIRVs[], - class PipelineLayout& PipelineLayout, - bool VerifyVariables, - bool VerifyStaticSamplers) +void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice, + const ShaderStages_t& ShaderStages, + ShaderResourceLayoutVk Layouts[], + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderSPIRVs_t& SPIRVs, + class PipelineLayout& PipelineLayout, + bool VerifyVariables, + bool VerifyStaticSamplers) { #ifdef DILIGENT_DEVELOPMENT - dvpVerifyResourceLayoutDesc(NumShaders, pShaderResources, ResourceLayoutDesc, VerifyVariables, VerifyStaticSamplers); + dvpVerifyResourceLayoutDesc(ShaderStages, ResourceLayoutDesc, VerifyVariables, VerifyStaticSamplers); #endif - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr; - const Uint32 NumAllowedTypes = 0; - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr; + const Uint32 NumAllowedTypes = 0; + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + constexpr bool AllocateImmutableSamplers = true; - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - constexpr bool AllocateImmutableSamplers = true; - Layouts[s].AllocateMemory(std::move(pShaderResources[s]), LayoutDataAllocator, ResourceLayoutDesc, AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers); + Layouts[s].AllocateMemory(ShaderStages[s].second, LayoutDataAllocator, ResourceLayoutDesc, AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers); } - VERIFY_EXPR(NumShaders <= MAX_SHADERS_IN_PIPELINE); + //VERIFY_EXPR(NumShaders <= MAX_SHADERS_IN_PIPELINE); std::array<std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>, MAX_SHADERS_IN_PIPELINE> CurrResInd = {}; std::array<Uint32, MAX_SHADERS_IN_PIPELINE> CurrImmutableSamplerInd = {}; #ifdef DILIGENT_DEBUG @@ -414,7 +461,7 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* { // Separate samplers are enumerated before separate images, so the sampler // assigned to this separate image must have already been created. - SamplerInd = ResLayout.FindAssignedSampler(Attribs, CurrResInd[ShaderInd][VarType], VarType); + SamplerInd = FindAssignedSampler(ResLayout, Resources, Attribs, CurrResInd[ShaderInd][VarType], VarType); } VkSampler vkImmutableSampler = VK_NULL_HANDLE; @@ -454,42 +501,48 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* }; // First process uniform buffers for all shader stages to make sure all UBs go first in every descriptor set - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& pShader = ShaderStages[s].second; + auto& Layout = Layouts[s]; + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto& Resources = *pShaderVk->GetShaderResources(); for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n) { const auto& UB = Resources.GetUB(n); auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc); if (IsAllowedType(VarType, AllowedTypeBits)) { - AddResource(s, Layout, Resources, UB); + AddResource(static_cast<Uint32>(s), Layout, Resources, UB); } } } // Second, process all storage buffers - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& pShader = ShaderStages[s].second; + auto& Layout = Layouts[s]; + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto& Resources = *pShaderVk->GetShaderResources(); for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n) { const auto& SB = Resources.GetSB(n); auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc); if (IsAllowedType(VarType, AllowedTypeBits)) { - AddResource(s, Layout, Resources, SB); + AddResource(static_cast<Uint32>(s), Layout, Resources, SB); } } } // Finally, process all other resource types - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& pShader = ShaderStages[s].second; + auto& Layout = Layouts[s]; + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto& Resources = *pShaderVk->GetShaderResources(); // clang-format off Resources.ProcessResources( [&](const SPIRVShaderResourceAttribs& UB, Uint32) @@ -505,39 +558,39 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* [&](const SPIRVShaderResourceAttribs& Img, Uint32) { VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer); - AddResource(s, Layout, Resources, Img); + AddResource(static_cast<Uint32>(s), Layout, Resources, Img); }, [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32) { VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); - AddResource(s, Layout, Resources, SmplImg); + AddResource(static_cast<Uint32>(s), Layout, Resources, SmplImg); }, [&](const SPIRVShaderResourceAttribs& AC, Uint32) { VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter); - AddResource(s, Layout, Resources, AC); + AddResource(static_cast<Uint32>(s), Layout, Resources, AC); }, [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32) { VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); - AddResource(s, Layout, Resources, SepSmpl); + AddResource(static_cast<Uint32>(s), Layout, Resources, SepSmpl); }, [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) { VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); - AddResource(s, Layout, Resources, SepImg); + AddResource(static_cast<Uint32>(s), Layout, Resources, SepImg); }, [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32) { VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment); - AddResource(s, Layout, Resources, InputAtt); + AddResource(static_cast<Uint32>(s), Layout, Resources, InputAtt); } ); // clang-format on } #ifdef DILIGENT_DEBUG - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { auto& Layout = Layouts[s]; for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) @@ -551,41 +604,40 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* } -Uint32 ShaderResourceLayoutVk::FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, - Uint32 CurrResourceCount, - SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) const +ShaderResourceLayoutVk::VkResource::VkResource(const ShaderResourceLayoutVk& _ParentLayout, + const SPIRVShaderResourceAttribs& _SpirvAttribs, + SHADER_RESOURCE_VARIABLE_TYPE _VariableType, + uint32_t _Binding, + uint32_t _DescriptorSet, + Uint32 _CacheOffset, + Uint32 _SamplerInd, + bool _ImmutableSamplerAssigned) noexcept : + // clang-format off + Binding {static_cast<decltype(Binding)>(_Binding) }, + DescriptorSet {static_cast<decltype(DescriptorSet)>(_DescriptorSet)}, + CacheOffset {_CacheOffset }, + SamplerInd {_SamplerInd }, + VariableType {_VariableType }, + ImmutableSamplerAssigned {_ImmutableSamplerAssigned ? 1U : 0U}, + SpirvAttribs {_SpirvAttribs }, + ParentResLayout {_ParentLayout } +// clang-format on { - VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); - - Uint32 SamplerInd = VkResource::InvalidSamplerInd; - if (m_pResources->IsUsingCombinedSamplers() && SepImg.IsValidSepSamplerAssigned()) - { - const auto& SepSampler = m_pResources->GetAssignedSepSampler(SepImg); - for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) - { - const auto& Res = GetResource(ImgVarType, SamplerInd); - if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && - strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) - { - VERIFY(ImgVarType == Res.GetVariableType(), - "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name, - "' is not consistent with the type (", GetShaderVariableTypeLiteralName(Res.GetVariableType()), - ") of the separate sampler '", SepSampler.Name, - "' that is assigned to it. " - "This should never happen as when HLSL-style combined texture samplers are used, the type of the sampler " - "is derived from the type of the corresponding separate image."); - break; - } - } - if (SamplerInd == CurrResourceCount) - { - LOG_ERROR("Unable to find separate sampler '", SepSampler.Name, "' assigned to separate image '", SepImg.Name, "' in the list of already created resources. This seems to be a bug."); - SamplerInd = VkResource::InvalidSamplerInd; - } - } - return SamplerInd; + VERIFY(_CacheOffset < (1 << CacheOffsetBits), "Cache offset (", _CacheOffset, ") exceeds max representable value ", (1 << CacheOffsetBits)); + VERIFY(_SamplerInd < (1 << SamplerIndBits), "Sampler index (", _SamplerInd, ") exceeds max representable value ", (1 << SamplerIndBits)); + VERIFY(_Binding <= std::numeric_limits<decltype(Binding)>::max(), "Binding (", _Binding, ") exceeds max representable value ", std::numeric_limits<decltype(Binding)>::max()); + VERIFY(_DescriptorSet <= std::numeric_limits<decltype(DescriptorSet)>::max(), "Descriptor set (", _DescriptorSet, ") exceeds max representable value ", std::numeric_limits<decltype(DescriptorSet)>::max()); + + const size_t Size = strlen(SpirvAttribs.Name) + 1; + char* NameCopy = ALLOCATE(GetRawAllocator(), "SPIRV Attribs Name", char, Size); + std::memcpy(NameCopy, SpirvAttribs.Name, Size); + const_cast<SPIRVShaderResourceAttribs&>(SpirvAttribs).Name = NameCopy; } +ShaderResourceLayoutVk::VkResource::~VkResource() +{ + FREE(GetRawAllocator(), const_cast<char*>(SpirvAttribs.Name)); +} void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, uint32_t ArrayElement, @@ -1017,7 +1069,7 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou { auto NumStaticResources = m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC]; VERIFY(NumStaticResources == SrcLayout.m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC], "Inconsistent number of static resources"); - VERIFY(SrcLayout.m_pResources->GetShaderType() == m_pResources->GetShaderType(), "Incosistent shader types"); + VERIFY(SrcLayout.GetShaderType() == GetShaderType(), "Incosistent shader types"); // Static shader resources are stored in one large continuous descriptor set for (Uint32 r = 0; r < NumStaticResources; ++r) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index fb151407..95261295 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -1511,4 +1511,27 @@ VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags) } #undef ASSERT_SAME + +VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType) +{ + static_assert(SHADER_TYPE_LAST == SHADER_TYPE_MESH, "Please update the switch below to handle the new shader type"); + VERIFY((ShaderType & (ShaderType - 1)) == 0, "More than one shader type specified"); + switch (ShaderType) + { + // clang-format off + case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; + case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; + case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; + case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; + case SHADER_TYPE_AMPLIFICATION: return VK_SHADER_STAGE_TASK_BIT_NV; + case SHADER_TYPE_MESH: return VK_SHADER_STAGE_MESH_BIT_NV; + // clang-format on + default: + UNEXPECTED("Unknown shader type"); + return VK_SHADER_STAGE_VERTEX_BIT; + } +} + } // namespace Diligent diff --git a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp index 5c35de33..b7c96523 100644 --- a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp +++ b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp @@ -78,7 +78,7 @@ struct SPIRVShaderResourceAttribs static constexpr const Uint32 InvalidSepSmplrOrImgInd = static_cast<Uint32>(-1); -/* 0 */const char* const Name; +/* 0 */const char* Name; /* 8 */const Uint16 ArraySize; /* 10 */const ResourceType Type; /* 11 */ // unused |
