From 259a9d5897937dcaaca1b4b294bb8d5250371e76 Mon Sep 17 00:00:00 2001 From: azhirnov Date: Thu, 15 Oct 2020 20:55:38 +0300 Subject: Added GraphicsPipelineCreateInfo and ComputePipelineCreateInfo instead of single PipelineCreateInfo. Some optimizations for dynamic memory allocations in PipelineState. --- .../GraphicsEngine/include/DeviceContextBase.hpp | 2 +- .../GraphicsEngine/include/PipelineStateBase.hpp | 439 ++++++++-------- Graphics/GraphicsEngine/interface/InputLayout.h | 2 +- Graphics/GraphicsEngine/interface/PipelineState.h | 89 ++-- Graphics/GraphicsEngine/interface/RenderDevice.h | 49 +- Graphics/GraphicsEngine/src/APIInfo.cpp | 1 - .../include/PipelineStateD3D11Impl.hpp | 17 +- .../include/RenderDeviceD3D11Impl.hpp | 10 +- .../src/DeviceContextD3D11Impl.cpp | 10 +- .../src/PipelineStateD3D11Impl.cpp | 229 ++++---- .../src/RenderDeviceD3D11Impl.cpp | 13 +- .../include/PipelineStateD3D12Impl.hpp | 24 +- .../include/RenderDeviceD3D12Impl.hpp | 7 +- .../src/DeviceContextD3D12Impl.cpp | 65 ++- .../src/PipelineStateD3D12Impl.cpp | 575 +++++++++++---------- .../src/RenderDeviceD3D12Impl.cpp | 13 +- .../include/PipelineStateGLImpl.hpp | 35 +- .../include/RenderDeviceGLImpl.hpp | 20 +- .../src/DeviceContextGLImpl.cpp | 6 +- .../src/PipelineStateGLImpl.cpp | 140 +++-- .../src/RenderDeviceGLImpl.cpp | 25 +- .../GraphicsEngineOpenGL/src/TexRegionRender.cpp | 17 +- Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp | 2 +- .../include/PipelineStateVkImpl.hpp | 14 +- .../include/RenderDeviceVkImpl.hpp | 7 +- .../src/DeviceContextVkImpl.cpp | 68 +-- .../src/GenerateMipsVkHelper.cpp | 12 +- .../src/PipelineStateVkImpl.cpp | 147 ++++-- .../src/RenderDeviceVkImpl.cpp | 16 +- 29 files changed, 1198 insertions(+), 856 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 86cccc7b..90285834 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -1678,7 +1678,7 @@ inline void DeviceContextBase:: BoundDSVFormat = m_pBoundDepthStencil ? m_pBoundDepthStencil->GetDesc().Format : TEX_FORMAT_UNKNOWN; const auto& PSODesc = m_pPipelineState->GetDesc(); - const auto& GraphicsPipeline = PSODesc.GraphicsPipeline; + const auto& GraphicsPipeline = m_pPipelineState->GetGraphicsPipelineDesc(); if (GraphicsPipeline.NumRenderTargets != m_NumBoundRenderTargets) { LOG_WARNING_MESSAGE("The number of currently bound render targets (", m_NumBoundRenderTargets, diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index 09f1bddc..d8cb09bb 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -38,7 +38,7 @@ #include "STDAllocator.hpp" #include "EngineMemory.h" #include "GraphicsAccessories.hpp" -#include "StringPool.hpp" +#include "LinearAllocator.hpp" namespace Diligent { @@ -59,7 +59,7 @@ public: /// \param pRefCounters - reference counters object that controls the lifetime of this PSO /// \param pDevice - pointer to the device. - /// \param PSODesc - pipeline state description. + /// \param CreateInfo - graphics pipeline state create info. /// \param bIsDeviceInternal - flag indicating if the pipeline state is an internal device object and /// must not keep a strong reference to the device. PipelineStateBase(IReferenceCounters* pRefCounters, @@ -68,96 +68,6 @@ public: bool bIsDeviceInternal = false) : TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal} { - switch (PSODesc.PipelineType) - { - // clang-format off - case PIPELINE_TYPE_GRAPHICS: - case PIPELINE_TYPE_MESH: ValidateGraphicsPipeline(); break; - case PIPELINE_TYPE_COMPUTE: ValidateComputePipeline(); break; - default: UNEXPECTED("unknown pipeline type"); - // clang-format on - } - - const auto& SrcLayout = PSODesc.ResourceLayout; - size_t StringPoolSize = 0; - if (SrcLayout.Variables != nullptr) - { - for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) - { - VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null"); - StringPoolSize += strlen(SrcLayout.Variables[i].Name) + 1; - } - } - - if (SrcLayout.StaticSamplers != nullptr) - { - for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) - { - VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null"); - StringPoolSize += strlen(SrcLayout.StaticSamplers[i].SamplerOrTextureName) + 1; - } - } - - if (PSODesc.IsAnyGraphicsPipeline()) - { - const auto& InputLayout = this->m_Desc.GraphicsPipeline.InputLayout; - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - StringPoolSize += strlen(InputLayout.LayoutElements[i].HLSLSemantic) + 1; - } - - m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); - - auto& DstLayout = this->m_Desc.ResourceLayout; - if (SrcLayout.Variables != nullptr) - { - ShaderResourceVariableDesc* Variables = - ALLOCATE(GetRawAllocator(), "Memory for ShaderResourceVariableDesc array", ShaderResourceVariableDesc, SrcLayout.NumVariables); - DstLayout.Variables = Variables; - for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) - { - Variables[i] = SrcLayout.Variables[i]; - Variables[i].Name = m_StringPool.CopyString(SrcLayout.Variables[i].Name); - } - } - - if (SrcLayout.StaticSamplers != nullptr) - { - StaticSamplerDesc* StaticSamplers = - ALLOCATE(GetRawAllocator(), "Memory for StaticSamplerDesc array", StaticSamplerDesc, SrcLayout.NumStaticSamplers); - DstLayout.StaticSamplers = StaticSamplers; - for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) - { -#ifdef DILIGENT_DEVELOPMENT - { - const auto& BorderColor = SrcLayout.StaticSamplers[i].Desc.BorderColor; - if (!((BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 0) || - (BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 1) || - (BorderColor[0] == 1 && BorderColor[1] == 1 && BorderColor[2] == 1 && BorderColor[3] == 1))) - { - LOG_WARNING_MESSAGE("Static sampler for variable \"", SrcLayout.StaticSamplers[i].SamplerOrTextureName, "\" specifies border color (", - BorderColor[0], ", ", BorderColor[1], ", ", BorderColor[2], ", ", BorderColor[3], - "). D3D12 static samplers only allow transparent black (0,0,0,0), opaque black (0,0,0,1) or opaque white (1,1,1,1) as border colors"); - } - } -#endif - - StaticSamplers[i] = SrcLayout.StaticSamplers[i]; - StaticSamplers[i].SamplerOrTextureName = m_StringPool.CopyString(SrcLayout.StaticSamplers[i].SamplerOrTextureName); - } - } - - switch (PSODesc.PipelineType) - { - // clang-format off - case PIPELINE_TYPE_GRAPHICS: - case PIPELINE_TYPE_MESH: InitGraphicsPipeline(); break; - case PIPELINE_TYPE_COMPUTE: InitComputePipeline(); break; - default: UNEXPECTED("unknown pipeline type"); - // clang-format on - } - - VERIFY_EXPR(m_StringPool.GetRemainingSize() == 0); - Uint64 DeviceQueuesMask = pDevice->GetCommandQueueMask(); DEV_CHECK_ERR((this->m_Desc.CommandQueueMask & DeviceQueuesMask) != 0, "No bits in the command queue mask (0x", std::hex, this->m_Desc.CommandQueueMask, @@ -184,16 +94,6 @@ public: RasterizerStateRegistry.ReportDeletedObject(); DSSRegistry.ReportDeletedObject(); */ - - auto& RawAllocator = GetRawAllocator(); - if (this->m_Desc.ResourceLayout.Variables != nullptr) - RawAllocator.Free(const_cast(this->m_Desc.ResourceLayout.Variables)); - if (this->m_Desc.ResourceLayout.StaticSamplers != nullptr) - RawAllocator.Free(const_cast(this->m_Desc.ResourceLayout.StaticSamplers)); - if (this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements != nullptr) - RawAllocator.Free(const_cast(this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements)); - if (m_pStrides != nullptr) - RawAllocator.Free(m_pStrides); } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineState, TDeviceObjectBase) @@ -218,20 +118,28 @@ public: return m_ShaderResourceLayoutHash != ValidatedCast(pPSO)->m_ShaderResourceLayoutHash; } -protected: - Uint32 m_BufferSlotsUsed = 0; - Uint32* m_pStrides = nullptr; + const GraphicsPipelineDesc& GetGraphicsPipelineDesc() const override final + { + VERIFY_EXPR(this->m_Desc.IsAnyGraphicsPipeline()); + VERIFY_EXPR(m_pGraphicsPipelineDesc != nullptr); + return *m_pGraphicsPipelineDesc; + } - StringPool m_StringPool; - RefCntAutoPtr m_pRenderPass; ///< Strong reference to the render pass object +protected: + size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout + + Uint32* m_pStrides = nullptr; + Uint8 m_BufferSlotsUsed = 0; Uint8 m_NumShaderStages = 0; ///< Number of shader stages in this PSO /// Array of shader types for every shader stage used by this PSO std::array m_ShaderStageTypes = {}; - size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout + RefCntAutoPtr m_pRenderPass; ///< Strong reference to the render pass object + + GraphicsPipelineDesc* m_pGraphicsPipelineDesc = nullptr; protected: #define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ", GetPipelineTypeString(this->m_Desc.PipelineType), " PSO '", this->m_Desc.Name, "' is invalid: ", ##__VA_ARGS__) @@ -296,74 +204,19 @@ protected: return LayoutInd; } - -protected: - template - void ExtractShaders(TShaderStages& ShaderStages) - { - VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once."); - - ShaderStages.clear(); - auto AddShaderStage = [&](IShader*& pShader) { - if (pShader != nullptr) - { - auto ShaderType = pShader->GetDesc().ShaderType; - ShaderStages.emplace_back(ShaderType, ValidatedCast(pShader)); - m_ShaderStageTypes[m_NumShaderStages++] = ShaderType; - - // Reset shader pointers in PSO desc because we don't keep strong references to shaders. - pShader = nullptr; - } - }; - - auto& Desc = this->m_Desc; - switch (Desc.PipelineType) - { - case PIPELINE_TYPE_COMPUTE: - { - AddShaderStage(Desc.ComputePipeline.pCS); - break; - } - - case PIPELINE_TYPE_GRAPHICS: - { - AddShaderStage(Desc.GraphicsPipeline.pVS); - AddShaderStage(Desc.GraphicsPipeline.pHS); - AddShaderStage(Desc.GraphicsPipeline.pDS); - AddShaderStage(Desc.GraphicsPipeline.pGS); - AddShaderStage(Desc.GraphicsPipeline.pPS); - break; - } - - case PIPELINE_TYPE_MESH: - { - AddShaderStage(Desc.GraphicsPipeline.pAS); - AddShaderStage(Desc.GraphicsPipeline.pMS); - AddShaderStage(Desc.GraphicsPipeline.pPS); - break; - } - - default: - UNEXPECTED("unknown pipeline type"); - } - - VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); - } - - private: - void CheckRasterizerStateDesc() const + void CheckRasterizerStateDesc(GraphicsPipelineDesc& GraphicsPipeline) const { - const auto& RSDesc = this->m_Desc.GraphicsPipeline.RasterizerDesc; + const auto& RSDesc = GraphicsPipeline.RasterizerDesc; if (RSDesc.FillMode == FILL_MODE_UNDEFINED) LOG_PSO_ERROR_AND_THROW("RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED"); if (RSDesc.CullMode == CULL_MODE_UNDEFINED) LOG_PSO_ERROR_AND_THROW("RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED"); } - void CheckAndCorrectDepthStencilDesc() + void CheckAndCorrectDepthStencilDesc(GraphicsPipelineDesc& GraphicsPipeline) const { - auto& DSSDesc = this->m_Desc.GraphicsPipeline.DepthStencilDesc; + auto& DSSDesc = GraphicsPipeline.DepthStencilDesc; if (DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN) { if (DSSDesc.DepthEnable) @@ -401,9 +254,9 @@ private: CheckAndCorrectStencilOpDesc(DSSDesc.BackFace, "BackFace"); } - void CheckAndCorrectBlendStateDesc() + void CheckAndCorrectBlendStateDesc(GraphicsPipelineDesc& GraphicsPipeline) const { - auto& BlendDesc = this->m_Desc.GraphicsPipeline.BlendDesc; + auto& BlendDesc = GraphicsPipeline.BlendDesc; for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt) { auto& RTDesc = BlendDesc.RenderTargets[rt]; @@ -449,9 +302,31 @@ private: } } - void ValidateGraphicsPipeline() + void ValidateResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) const + { + if (SrcLayout.Variables != nullptr) + { + MemPool.AddRequiredSize(SrcLayout.NumVariables); + for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) + { + VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null"); + MemPool.AddRequiredSize(strlen(SrcLayout.Variables[i].Name) + 1); + } + } + + if (SrcLayout.StaticSamplers != nullptr) + { + MemPool.AddRequiredSize(SrcLayout.NumStaticSamplers); + for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) + { + VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null"); + MemPool.AddRequiredSize(strlen(SrcLayout.StaticSamplers[i].SamplerOrTextureName) + 1); + } + } + } + + void ValidateGraphicsPipeline(const GraphicsPipelineDesc& GraphicsPipeline, LinearAllocator& MemPool) const { - const auto& GraphicsPipeline = this->m_Desc.GraphicsPipeline; if (GraphicsPipeline.pRenderPass != nullptr) { if (GraphicsPipeline.NumRenderTargets != 0) @@ -475,48 +350,182 @@ private: LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used"); } - CheckAndCorrectBlendStateDesc(); - CheckRasterizerStateDesc(); - CheckAndCorrectDepthStencilDesc(); + const auto& InputLayout = GraphicsPipeline.InputLayout; + Uint32 BufferSlotsUsed = 0; + MemPool.AddRequiredSize(InputLayout.NumElements); + for (Uint32 i = 0; i < InputLayout.NumElements; ++i) + { + auto& LayoutElem = InputLayout.LayoutElements[i]; + MemPool.AddRequiredSize(strlen(LayoutElem.HLSLSemantic) + 1); + BufferSlotsUsed = std::max(BufferSlotsUsed, LayoutElem.BufferSlot + 1); + } + + MemPool.AddRequiredSize(BufferSlotsUsed); } - void ValidateComputePipeline() + void InitResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) const { - if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr) + if (SrcLayout.Variables != nullptr) { - LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null for compute pipelines"); + auto* Variables = MemPool.Allocate(SrcLayout.NumVariables); + DstLayout.Variables = Variables; + for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) + { + Variables[i] = SrcLayout.Variables[i]; + Variables[i].Name = MemPool.CopyString(SrcLayout.Variables[i].Name); + } + } + + if (SrcLayout.StaticSamplers != nullptr) + { + auto* StaticSamplers = MemPool.Allocate(SrcLayout.NumStaticSamplers); + DstLayout.StaticSamplers = StaticSamplers; + for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) + { +#ifdef DILIGENT_DEVELOPMENT + { + const auto& BorderColor = SrcLayout.StaticSamplers[i].Desc.BorderColor; + if (!((BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 0) || + (BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 1) || + (BorderColor[0] == 1 && BorderColor[1] == 1 && BorderColor[2] == 1 && BorderColor[3] == 1))) + { + LOG_WARNING_MESSAGE("Static sampler for variable \"", SrcLayout.StaticSamplers[i].SamplerOrTextureName, "\" specifies border color (", + BorderColor[0], ", ", BorderColor[1], ", ", BorderColor[2], ", ", BorderColor[3], + "). D3D12 static samplers only allow transparent black (0,0,0,0), opaque black (0,0,0,1) or opaque white (1,1,1,1) as border colors"); + } + } +#endif + + StaticSamplers[i] = SrcLayout.StaticSamplers[i]; + StaticSamplers[i].SamplerOrTextureName = MemPool.CopyString(SrcLayout.StaticSamplers[i].SamplerOrTextureName); + } } - DEV_CHECK_ERR(this->m_Desc.GraphicsPipeline.InputLayout.NumElements == 0, "Compute pipelines must not have input layout elements"); } +protected: #define VALIDATE_SHADER_TYPE(Shader, ExpectedType, ShaderName) \ if (Shader && Shader->GetDesc().ShaderType != ExpectedType) \ { \ LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(Shader->GetDesc().ShaderType), " is not a valid type for ", ShaderName, " shader"); \ } - void InitGraphicsPipeline() + void ValidateAndReserveSpace(const GraphicsPipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) const + { + VALIDATE_SHADER_TYPE(CreateInfo.pVS, SHADER_TYPE_VERTEX, "vertex") + VALIDATE_SHADER_TYPE(CreateInfo.pPS, SHADER_TYPE_PIXEL, "pixel") + VALIDATE_SHADER_TYPE(CreateInfo.pGS, SHADER_TYPE_GEOMETRY, "geometry") + VALIDATE_SHADER_TYPE(CreateInfo.pHS, SHADER_TYPE_HULL, "hull") + VALIDATE_SHADER_TYPE(CreateInfo.pDS, SHADER_TYPE_DOMAIN, "domain") + VALIDATE_SHADER_TYPE(CreateInfo.pAS, SHADER_TYPE_AMPLIFICATION, "amplification") + VALIDATE_SHADER_TYPE(CreateInfo.pMS, SHADER_TYPE_MESH, "mesh") + + MemPool.AddRequiredSize(1); + ValidateResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool); + + ValidateGraphicsPipeline(CreateInfo.GraphicsPipeline, MemPool); + } + + void ValidateAndReserveSpace(const ComputePipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) const { + if (CreateInfo.pCS == nullptr) + { + LOG_ERROR_AND_THROW("Compute shader is not provided"); + } + VALIDATE_SHADER_TYPE(CreateInfo.pCS, SHADER_TYPE_COMPUTE, "compute"); + + ValidateResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool); + } + + template + void ExtractShaders(const GraphicsPipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages) + { + VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once."); + + ShaderStages.clear(); + auto AddShaderStage = [&](IShader* pShader) { + if (pShader != nullptr) + { + auto ShaderType = pShader->GetDesc().ShaderType; + ShaderStages.emplace_back(ShaderType, ValidatedCast(pShader)); + m_ShaderStageTypes[m_NumShaderStages++] = ShaderType; + } + }; + + switch (CreateInfo.PSODesc.PipelineType) + { + case PIPELINE_TYPE_GRAPHICS: + { + AddShaderStage(CreateInfo.pVS); + AddShaderStage(CreateInfo.pHS); + AddShaderStage(CreateInfo.pDS); + AddShaderStage(CreateInfo.pGS); + AddShaderStage(CreateInfo.pPS); + break; + } + + case PIPELINE_TYPE_MESH: + { + AddShaderStage(CreateInfo.pAS); + AddShaderStage(CreateInfo.pMS); + AddShaderStage(CreateInfo.pPS); + break; + } + + default: + UNEXPECTED("unknown pipeline type"); + } + + VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); + } + + template + void ExtractShaders(const ComputePipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages) + { + VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once."); + + ShaderStages.clear(); + auto AddShaderStage = [&](IShader* pShader) { + if (pShader != nullptr) + { + auto ShaderType = pShader->GetDesc().ShaderType; + ShaderStages.emplace_back(ShaderType, ValidatedCast(pShader)); + m_ShaderStageTypes[m_NumShaderStages++] = ShaderType; + } + }; + + AddShaderStage(CreateInfo.pCS); + + VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); + } + + + void InitGraphicsPipeline(const GraphicsPipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) + { + this->m_pGraphicsPipelineDesc = MemPool.CopyArray(&CreateInfo.GraphicsPipeline, 1); + + InitResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool); + + auto& GraphicsPipeline = *this->m_pGraphicsPipelineDesc; const auto& PSODesc = this->m_Desc; - const auto& GraphicsPipeline = PSODesc.GraphicsPipeline; - VALIDATE_SHADER_TYPE(GraphicsPipeline.pVS, SHADER_TYPE_VERTEX, "vertex") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pPS, SHADER_TYPE_PIXEL, "pixel") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pGS, SHADER_TYPE_GEOMETRY, "geometry") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pHS, SHADER_TYPE_HULL, "hull") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pDS, SHADER_TYPE_DOMAIN, "domain") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pAS, SHADER_TYPE_AMPLIFICATION, "amplification") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pMS, SHADER_TYPE_MESH, "mesh") + CheckAndCorrectBlendStateDesc(GraphicsPipeline); + CheckRasterizerStateDesc(GraphicsPipeline); + CheckAndCorrectDepthStencilDesc(GraphicsPipeline); if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) { - DEV_CHECK_ERR(GraphicsPipeline.pVS, "Vertex shader must be defined"); - DEV_CHECK_ERR(!GraphicsPipeline.pAS && !GraphicsPipeline.pMS, "Mesh shaders are not supported in graphics pipeline"); + DEV_CHECK_ERR(CreateInfo.pVS, "Vertex shader must be defined"); + DEV_CHECK_ERR(!CreateInfo.pAS && !CreateInfo.pMS, "Mesh shaders are not supported in graphics pipeline"); } else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH) { - DEV_CHECK_ERR(GraphicsPipeline.pMS, "Mesh shader must be defined"); - DEV_CHECK_ERR(!GraphicsPipeline.pVS && !GraphicsPipeline.pGS && !GraphicsPipeline.pDS && !GraphicsPipeline.pHS, + DEV_CHECK_ERR(CreateInfo.pMS, "Mesh shader must be defined"); + DEV_CHECK_ERR(!CreateInfo.pVS && !CreateInfo.pGS && !CreateInfo.pDS && !CreateInfo.pHS, "Vertex, geometry and tessellation shaders are not supported in a mesh pipeline"); DEV_CHECK_ERR(GraphicsPipeline.InputLayout.NumElements == 0, "Input layout ignored in mesh shader"); DEV_CHECK_ERR(GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_TRIANGLE_LIST || @@ -524,7 +533,7 @@ private: "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)"); } - m_pRenderPass = PSODesc.GraphicsPipeline.pRenderPass; + m_pRenderPass = GraphicsPipeline.pRenderPass; for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt) { @@ -542,14 +551,14 @@ private: VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount); const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex]; - this->m_Desc.GraphicsPipeline.NumRenderTargets = static_cast(Subpass.RenderTargetAttachmentCount); + GraphicsPipeline.NumRenderTargets = static_cast(Subpass.RenderTargetAttachmentCount); for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt) { const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt]; if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) { VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); - this->m_Desc.GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; + GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; } } @@ -559,23 +568,19 @@ private: if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) { VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); - this->m_Desc.GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; + GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; } } } - const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout; - LayoutElement* pLayoutElements = nullptr; - if (InputLayout.NumElements > 0) - { - pLayoutElements = ALLOCATE(GetRawAllocator(), "Raw memory for input layout elements", LayoutElement, InputLayout.NumElements); - } + const auto& InputLayout = GraphicsPipeline.InputLayout; + LayoutElement* pLayoutElements = MemPool.Allocate(InputLayout.NumElements); for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem) { pLayoutElements[Elem] = InputLayout.LayoutElements[Elem]; - pLayoutElements[Elem].HLSLSemantic = m_StringPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic); + pLayoutElements[Elem].HLSLSemantic = MemPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic); } - this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements; + GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements; // Correct description and compute offsets and tight strides @@ -597,7 +602,7 @@ private: UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds maximum allowed value (", Strides.size() - 1, ")"); continue; } - m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, BuffSlot + 1); + m_BufferSlotsUsed = static_cast(std::max(m_BufferSlotsUsed, BuffSlot + 1)); auto& CurrAutoStride = TightStrides[BuffSlot]; // If offset is not explicitly specified, use current auto stride value @@ -647,28 +652,20 @@ private: LayoutElem.Stride = Strides[BuffSlot]; } - if (m_BufferSlotsUsed > 0) - { - m_pStrides = ALLOCATE(GetRawAllocator(), "Raw memory for buffer strides", Uint32, m_BufferSlotsUsed); + m_pStrides = MemPool.Allocate(m_BufferSlotsUsed); - // Set strides for all unused slots to 0 - for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i) - { - auto Stride = Strides[i]; - m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0; - } + // Set strides for all unused slots to 0 + for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i) + { + auto Stride = Strides[i]; + m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0; } } - void InitComputePipeline() + void InitComputePipeline(const ComputePipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) { - const auto& ComputePipeline = this->m_Desc.ComputePipeline; - if (ComputePipeline.pCS == nullptr) - { - LOG_ERROR_AND_THROW("Compute shader is not provided"); - } - - VALIDATE_SHADER_TYPE(ComputePipeline.pCS, SHADER_TYPE_COMPUTE, "compute"); + InitResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool); } #undef VALIDATE_SHADER_TYPE diff --git a/Graphics/GraphicsEngine/interface/InputLayout.h b/Graphics/GraphicsEngine/interface/InputLayout.h index 19904974..c7b18965 100644 --- a/Graphics/GraphicsEngine/interface/InputLayout.h +++ b/Graphics/GraphicsEngine/interface/InputLayout.h @@ -179,7 +179,7 @@ typedef struct LayoutElement LayoutElement; /// Layout description -/// This structure is used by IRenderDevice::CreatePipelineState(). +/// This structure is used by IRenderDevice::CreateGraphicsPipelineState(). struct InputLayoutDesc { /// Array of layout elements diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index 2d22c826..e5682e58 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -151,29 +151,6 @@ typedef struct PipelineResourceLayoutDesc PipelineResourceLayoutDesc; /// This structure describes the graphics pipeline state and is part of the PipelineStateDesc structure. struct GraphicsPipelineDesc { - /// Vertex shader to be used with the pipeline. - IShader* pVS DEFAULT_INITIALIZER(nullptr); - - /// Pixel shader to be used with the pipeline. - IShader* pPS DEFAULT_INITIALIZER(nullptr); - - /// Domain shader to be used with the pipeline. - IShader* pDS DEFAULT_INITIALIZER(nullptr); - - /// Hull shader to be used with the pipeline. - IShader* pHS DEFAULT_INITIALIZER(nullptr); - - /// Geometry shader to be used with the pipeline. - IShader* pGS DEFAULT_INITIALIZER(nullptr); - - /// Amplification shader to be used with the pipeline. - IShader* pAS DEFAULT_INITIALIZER(nullptr); - - /// Mesh shader to be used with the pipeline. - IShader* pMS DEFAULT_INITIALIZER(nullptr); - - //D3D12_STREAM_OUTPUT_DESC StreamOutput; - /// Blend state description. BlendStateDesc BlendDesc; @@ -234,17 +211,6 @@ struct GraphicsPipelineDesc typedef struct GraphicsPipelineDesc GraphicsPipelineDesc; -/// Compute pipeline state description - -/// This structure describes the compute pipeline state and is part of the PipelineStateDesc structure. -struct ComputePipelineDesc -{ - /// Compute shader to be used with the pipeline - IShader* pCS DEFAULT_INITIALIZER(nullptr); -}; -typedef struct ComputePipelineDesc ComputePipelineDesc; - - /// Pipeline type DILIGENT_TYPED_ENUM(PIPELINE_TYPE, Uint8) { @@ -278,12 +244,6 @@ struct PipelineStateDesc DILIGENT_DERIVE(DeviceObjectAttribs) /// Pipeline layout description PipelineResourceLayoutDesc ResourceLayout; - /// Graphics pipeline state description. This memeber is ignored if PipelineType is not PIPELINE_TYPE_GRAPHICS or PIPELINE_TYPE_MESH - GraphicsPipelineDesc GraphicsPipeline; - - /// Compute pipeline state description. This memeber is ignored if PipelineType is not PIPELINE_TYPE_COMPUTE - ComputePipelineDesc ComputePipeline; - #if DILIGENT_CPP_INTERFACE bool IsAnyGraphicsPipeline() const { return PipelineType == PIPELINE_TYPE_GRAPHICS || PipelineType == PIPELINE_TYPE_MESH; } bool IsComputePipeline() const { return PipelineType == PIPELINE_TYPE_COMPUTE; } @@ -324,10 +284,50 @@ struct PipelineStateCreateInfo PipelineStateDesc PSODesc; /// Pipeline state creation flags, see Diligent::PSO_CREATE_FLAGS. - PSO_CREATE_FLAGS Flags DEFAULT_INITIALIZER(PSO_CREATE_FLAG_NONE); + PSO_CREATE_FLAGS Flags DEFAULT_INITIALIZER(PSO_CREATE_FLAG_NONE); }; typedef struct PipelineStateCreateInfo PipelineStateCreateInfo; + +/// Graphics pipeline state creation attributes +struct GraphicsPipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo) + + /// Graphics pipeline state description. + GraphicsPipelineDesc GraphicsPipeline; + + /// Vertex shader to be used with the pipeline. + IShader* pVS DEFAULT_INITIALIZER(nullptr); + + /// Pixel shader to be used with the pipeline. + IShader* pPS DEFAULT_INITIALIZER(nullptr); + + /// Domain shader to be used with the pipeline. + IShader* pDS DEFAULT_INITIALIZER(nullptr); + + /// Hull shader to be used with the pipeline. + IShader* pHS DEFAULT_INITIALIZER(nullptr); + + /// Geometry shader to be used with the pipeline. + IShader* pGS DEFAULT_INITIALIZER(nullptr); + + /// Amplification shader to be used with the pipeline. + IShader* pAS DEFAULT_INITIALIZER(nullptr); + + /// Mesh shader to be used with the pipeline. + IShader* pMS DEFAULT_INITIALIZER(nullptr); +}; +typedef struct GraphicsPipelineStateCreateInfo GraphicsPipelineStateCreateInfo; + + +/// Compute pipeline state description. +struct ComputePipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo) + + /// Compute shader to be used with the pipeline + IShader* pCS DEFAULT_INITIALIZER(nullptr); +}; +typedef struct ComputePipelineStateCreateInfo ComputePipelineStateCreateInfo; + + // {06084AE5-6A71-4FE8-84B9-395DD489A28C} static const struct INTERFACE_ID IID_PipelineState = {0x6084ae5, 0x6a71, 0x4fe8, {0x84, 0xb9, 0x39, 0x5d, 0xd4, 0x89, 0xa2, 0x8c}}; @@ -345,10 +345,12 @@ static const struct INTERFACE_ID IID_PipelineState = DILIGENT_BEGIN_INTERFACE(IPipelineState, IDeviceObject) { #if DILIGENT_CPP_INTERFACE - /// Returns the blend state description used to create the object - virtual const PipelineStateDesc& METHOD(GetDesc)()const override = 0; + /// Returns the pipeline description used to create the object + virtual const PipelineStateDesc& METHOD(GetDesc)() const override = 0; #endif + /// Returns the graphics pipeline description used to create the object + VIRTUAL const GraphicsPipelineDesc REF METHOD(GetGraphicsPipelineDesc)(THIS) CONST PURE; /// Binds resources for all shaders in the pipeline state @@ -438,6 +440,7 @@ DILIGENT_END_INTERFACE # define IPipelineState_GetDesc(This) (const struct PipelineStateDesc*)IDeviceObject_GetDesc(This) +# define IPipelineState_GetGraphicsPipelineDesc(This) CALL_IFACE_METHOD(PipelineState, GetGraphicsPipelineDesc, This) # define IPipelineState_BindStaticResources(This, ...) CALL_IFACE_METHOD(PipelineState, BindStaticResources, This, __VA_ARGS__) # define IPipelineState_GetStaticVariableCount(This, ...) CALL_IFACE_METHOD(PipelineState, GetStaticVariableCount, This, __VA_ARGS__) # define IPipelineState_GetStaticVariableByName(This, ...) CALL_IFACE_METHOD(PipelineState, GetStaticVariableByName, This, __VA_ARGS__) diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h index 0cea79eb..ea4e05af 100644 --- a/Graphics/GraphicsEngine/interface/RenderDevice.h +++ b/Graphics/GraphicsEngine/interface/RenderDevice.h @@ -153,17 +153,27 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) const ResourceMappingDesc REF MappingDesc, IResourceMapping** ppMapping) PURE; - /// Creates a new pipeline state object + /// Creates a new graphics pipeline state object - /// \param [in] PSOCreateInfo - Pipeline state create info, see Diligent::PipelineStateCreateInfo for details. + /// \param [in] PSOCreateInfo - Pipeline state create info, see Diligent::GraphicsPipelineStateCreateInfo for details. /// \param [out] ppPipelineState - Address of the memory location where the pointer to the /// pipeline state interface will be stored. /// The function calls AddRef(), so that the new object will contain /// one reference. - VIRTUAL void METHOD(CreatePipelineState)(THIS_ - const PipelineStateCreateInfo REF PSOCreateInfo, - IPipelineState** ppPipelineState) PURE; + VIRTUAL void METHOD(CreateGraphicsPipelineState)(THIS_ + const GraphicsPipelineStateCreateInfo REF PSOCreateInfo, + IPipelineState** ppPipelineState) PURE; + + /// Creates a new compute pipeline state object + /// \param [in] PSOCreateInfo - Pipeline state create info, see Diligent::ComputePipelineStateCreateInfo for details. + /// \param [out] ppPipelineState - Address of the memory location where the pointer to the + /// pipeline state interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + VIRTUAL void METHOD(CreateComputePipelineState)(THIS_ + const ComputePipelineStateCreateInfo REF PSOCreateInfo, + IPipelineState** ppPipelineState) PURE; /// Creates a new fence object @@ -273,20 +283,21 @@ DILIGENT_END_INTERFACE // clang-format off -# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__) -# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__) -# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__) -# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__) -# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__) -# define IRenderDevice_CreatePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineState, This, __VA_ARGS__) -# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__) -# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__) -# define IRenderDevice_GetDeviceCaps(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceCaps, This) -# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__) -# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt,This, __VA_ARGS__) -# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__) -# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This) -# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This) +# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__) +# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__) +# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__) +# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__) +# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__) +# define IRenderDevice_CreateGraphicsPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateGraphicsPipelineState, This, __VA_ARGS__) +# define IRenderDevice_CreateComputePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateComputePipelineState, This, __VA_ARGS__) +# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__) +# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__) +# define IRenderDevice_GetDeviceCaps(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceCaps, This) +# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__) +# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt, This, __VA_ARGS__) +# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__) +# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This) +# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This) // clang-format on diff --git a/Graphics/GraphicsEngine/src/APIInfo.cpp b/Graphics/GraphicsEngine/src/APIInfo.cpp index f71b943e..05aef568 100644 --- a/Graphics/GraphicsEngine/src/APIInfo.cpp +++ b/Graphics/GraphicsEngine/src/APIInfo.cpp @@ -90,7 +90,6 @@ static APIInfo InitAPIInfo() INIT_STRUCTURE_SIZE(StaticSamplerDesc); INIT_STRUCTURE_SIZE(PipelineResourceLayoutDesc); INIT_STRUCTURE_SIZE(GraphicsPipelineDesc); - INIT_STRUCTURE_SIZE(ComputePipelineDesc); INIT_STRUCTURE_SIZE(PipelineStateDesc); INIT_STRUCTURE_SIZE(RasterizerStateDesc); INIT_STRUCTURE_SIZE(ResourceMappingEntry); diff --git a/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp index 1d836ab3..99062706 100644 --- a/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp @@ -49,9 +49,12 @@ class PipelineStateD3D11Impl final : public PipelineStateBase; - PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, - class RenderDeviceD3D11Impl* pDeviceD3D11, - const PipelineStateCreateInfo& CreateInfo); + PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D11Impl* pDeviceD3D11, + const GraphicsPipelineStateCreateInfo& CreateInfo); + PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D11Impl* pDeviceD3D11, + const ComputePipelineStateCreateInfo& CreateInfo); ~PipelineStateD3D11Impl(); virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; @@ -134,6 +137,10 @@ public: void SetStaticSamplers(ShaderResourceCacheD3D11& ResourceCache, Uint32 ShaderInd) const; private: + void InitResourceLayouts(RenderDeviceD3D11Impl* pRenderDeviceD3D11, + const PipelineStateCreateInfo& CreateInfo, + const std::vector>& ShaderStages); + CComPtr m_pd3d11BlendState; CComPtr m_pd3d11RasterizerState; CComPtr m_pd3d11DepthStencilState; @@ -147,8 +154,8 @@ private: RefCntAutoPtr m_pCS; // The caches are indexed by the shader order in the PSO, not shader index - ShaderResourceCacheD3D11* m_pStaticResourceCaches = nullptr; - ShaderResourceLayoutD3D11* m_pStaticResourceLayouts = nullptr; + ShaderResourceCacheD3D11* m_pStaticResourceCaches = nullptr; // [m_NumShaderStages] + ShaderResourceLayoutD3D11* m_pStaticResourceLayouts = nullptr; // [m_NumShaderStages] // SRB memory allocator must be defined before the default shader res binding SRBMemoryAllocator m_SRBMemAllocator; diff --git a/Graphics/GraphicsEngineD3D11/include/RenderDeviceD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/RenderDeviceD3D11Impl.hpp index 8003615e..1a1e01af 100644 --- a/Graphics/GraphicsEngineD3D11/include/RenderDeviceD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/RenderDeviceD3D11Impl.hpp @@ -69,9 +69,13 @@ public: virtual void DILIGENT_CALL_TYPE CreateSampler(const SamplerDesc& SamplerDesc, ISampler** ppSampler) override final; - /// Implementation of IRenderDevice::CreatePipelineState() in Direct3D11 backend. - virtual void DILIGENT_CALL_TYPE CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, - IPipelineState** ppPipelineState) override final; + /// Implementation of IRenderDevice::CreateGraphicsPipelineState() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, + IPipelineState** ppPipelineState) override final; + + /// Implementation of IRenderDevice::CreateComputePipelineState() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, + IPipelineState** ppPipelineState) override final; /// Implementation of IRenderDevice::CreateFence() in Direct3D11 backend. virtual void DILIGENT_CALL_TYPE CreateFence(const FenceDesc& Desc, diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index 75ce9094..39560453 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -75,7 +75,7 @@ void DeviceContextD3D11Impl::SetPipelineState(IPipelineState* pPipelineState) TDeviceContextBase::SetPipelineState(pPipelineStateD3D11, 0 /*Dummy*/); auto& Desc = pPipelineStateD3D11->GetDesc(); - if (Desc.IsComputePipeline()) + if (Desc.PipelineType == PIPELINE_TYPE_COMPUTE) { auto* pd3d11CS = pPipelineStateD3D11->GetD3D11ComputeShader(); if (pd3d11CS == nullptr) @@ -106,7 +106,9 @@ void DeviceContextD3D11Impl::SetPipelineState(IPipelineState* pPipelineState) COMMIT_SHADER(DS, DomainShader); #undef COMMIT_SHADER - m_pd3d11DeviceContext->OMSetBlendState(pPipelineStateD3D11->GetD3D11BlendState(), m_BlendFactors, Desc.GraphicsPipeline.SampleMask); + auto& GraphicsPipeline = pPipelineStateD3D11->GetGraphicsPipelineDesc(); + + m_pd3d11DeviceContext->OMSetBlendState(pPipelineStateD3D11->GetD3D11BlendState(), m_BlendFactors, GraphicsPipeline.SampleMask); m_pd3d11DeviceContext->RSSetState(pPipelineStateD3D11->GetD3D11RasterizerState()); m_pd3d11DeviceContext->OMSetDepthStencilState(pPipelineStateD3D11->GetD3D11DepthStencilState(), m_StencilRef); @@ -119,7 +121,7 @@ void DeviceContextD3D11Impl::SetPipelineState(IPipelineState* pPipelineState) m_CommittedD3D11InputLayout = pd3d11InputLayout; } - auto PrimTopology = Desc.GraphicsPipeline.PrimitiveTopology; + auto PrimTopology = GraphicsPipeline.PrimitiveTopology; if (m_CommittedPrimitiveTopology != PrimTopology) { m_CommittedPrimitiveTopology = PrimTopology; @@ -673,7 +675,7 @@ void DeviceContextD3D11Impl::SetBlendFactors(const float* pBlendFactors) ID3D11BlendState* pd3d11BS = nullptr; if (m_pPipelineState) { - SampleMask = m_pPipelineState->GetDesc().GraphicsPipeline.SampleMask; + SampleMask = m_pPipelineState->GetGraphicsPipelineDesc().SampleMask; pd3d11BS = m_pPipelineState->GetD3D11BlendState(); } m_pd3d11DeviceContext->OMSetBlendState(pd3d11BS, m_BlendFactors, SampleMask); diff --git a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp index 4893f97e..d20e0c32 100644 --- a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp @@ -35,9 +35,9 @@ namespace Diligent { -PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, - RenderDeviceD3D11Impl* pRenderDeviceD3D11, - const PipelineStateCreateInfo& CreateInfo) : +PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D11Impl* pRenderDeviceD3D11, + const GraphicsPipelineStateCreateInfo& CreateInfo) : // clang-format off TPipelineStateBase { @@ -51,28 +51,33 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR { m_ResourceLayoutIndex.fill(-1); - if (m_Desc.IsComputePipeline()) - { - auto* pCS = ValidatedCast(m_Desc.ComputePipeline.pCS); - m_pCS = pCS; - if (m_pCS == nullptr) - { - LOG_ERROR_AND_THROW("Compute shader is null"); - } + // We do not really need ShaderStages, but ExtractShaders() also initializes + // shader stage types and shader stage counter. + std::vector> ShaderStages; + ExtractShaders(CreateInfo, ShaderStages); - if (m_pCS && m_pCS->GetDesc().ShaderType != SHADER_TYPE_COMPUTE) - { - LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(SHADER_TYPE_COMPUTE), " shader is expeceted while ", GetShaderTypeLiteralName(m_pCS->GetDesc().ShaderType), " provided"); - } - m_ShaderResourceLayoutHash = pCS->GetD3D11Resources()->GetHash(); - } - else if (m_Desc.PipelineType == PIPELINE_TYPE_GRAPHICS) - { + // Memory must be released if an exception is thrown. + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(GetNumShaderStages()); + + ValidateAndReserveSpace(CreateInfo, MemPool); + + MemPool.Reserve(); + + m_pStaticResourceLayouts = MemPool.Allocate(GetNumShaderStages()); + m_pStaticResourceCaches = MemPool.Allocate(GetNumShaderStages()); + + InitGraphicsPipeline(CreateInfo, MemPool); + InitResourceLayouts(pRenderDeviceD3D11, CreateInfo, ShaderStages); + + auto& GraphicsPipeline = GetGraphicsPipelineDesc(); #define INIT_SHADER(ShortName, ExpectedType) \ do \ { \ - auto* pShader = ValidatedCast(m_Desc.GraphicsPipeline.p##ShortName); \ + auto* pShader = ValidatedCast(CreateInfo.p##ShortName); \ m_p##ShortName = pShader; \ if (m_p##ShortName && m_p##ShortName->GetDesc().ShaderType != ExpectedType) \ { \ @@ -82,81 +87,140 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR HashCombine(m_ShaderResourceLayoutHash, pShader->GetD3D11Resources()->GetHash()); \ } while (false) - INIT_SHADER(VS, SHADER_TYPE_VERTEX); - INIT_SHADER(PS, SHADER_TYPE_PIXEL); - INIT_SHADER(GS, SHADER_TYPE_GEOMETRY); - INIT_SHADER(DS, SHADER_TYPE_DOMAIN); - INIT_SHADER(HS, SHADER_TYPE_HULL); + INIT_SHADER(VS, SHADER_TYPE_VERTEX); + INIT_SHADER(PS, SHADER_TYPE_PIXEL); + INIT_SHADER(GS, SHADER_TYPE_GEOMETRY); + INIT_SHADER(DS, SHADER_TYPE_DOMAIN); + INIT_SHADER(HS, SHADER_TYPE_HULL); #undef INIT_SHADER - if (m_pVS == nullptr) - { - LOG_ERROR_AND_THROW("Vertex shader is null"); - } + if (m_pVS == nullptr) + { + LOG_ERROR_AND_THROW("Vertex shader is null"); + } - auto* pDeviceD3D11 = pRenderDeviceD3D11->GetD3D11Device(); + auto* pDeviceD3D11 = pRenderDeviceD3D11->GetD3D11Device(); - D3D11_BLEND_DESC D3D11BSDesc = {}; - BlendStateDesc_To_D3D11_BLEND_DESC(m_Desc.GraphicsPipeline.BlendDesc, D3D11BSDesc); - CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateBlendState(&D3D11BSDesc, &m_pd3d11BlendState), - "Failed to create D3D11 blend state object"); + D3D11_BLEND_DESC D3D11BSDesc = {}; + BlendStateDesc_To_D3D11_BLEND_DESC(GraphicsPipeline.BlendDesc, D3D11BSDesc); + CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateBlendState(&D3D11BSDesc, &m_pd3d11BlendState), + "Failed to create D3D11 blend state object"); - D3D11_RASTERIZER_DESC D3D11RSDesc = {}; - RasterizerStateDesc_To_D3D11_RASTERIZER_DESC(m_Desc.GraphicsPipeline.RasterizerDesc, D3D11RSDesc); - CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateRasterizerState(&D3D11RSDesc, &m_pd3d11RasterizerState), - "Failed to create D3D11 rasterizer state"); + D3D11_RASTERIZER_DESC D3D11RSDesc = {}; + RasterizerStateDesc_To_D3D11_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, D3D11RSDesc); + CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateRasterizerState(&D3D11RSDesc, &m_pd3d11RasterizerState), + "Failed to create D3D11 rasterizer state"); - D3D11_DEPTH_STENCIL_DESC D3D11DSSDesc = {}; - DepthStencilStateDesc_To_D3D11_DEPTH_STENCIL_DESC(m_Desc.GraphicsPipeline.DepthStencilDesc, D3D11DSSDesc); - CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateDepthStencilState(&D3D11DSSDesc, &m_pd3d11DepthStencilState), - "Failed to create D3D11 depth stencil state"); + D3D11_DEPTH_STENCIL_DESC D3D11DSSDesc = {}; + DepthStencilStateDesc_To_D3D11_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, D3D11DSSDesc); + CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateDepthStencilState(&D3D11DSSDesc, &m_pd3d11DepthStencilState), + "Failed to create D3D11 depth stencil state"); - // Create input layout - const auto& InputLayout = m_Desc.GraphicsPipeline.InputLayout; - if (InputLayout.NumElements > 0) - { - std::vector> d311InputElements(STD_ALLOCATOR_RAW_MEM(D3D11_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector")); - LayoutElements_To_D3D11_INPUT_ELEMENT_DESCs(InputLayout, d311InputElements); + // Create input layout + const auto& InputLayout = GraphicsPipeline.InputLayout; + if (InputLayout.NumElements > 0) + { + std::vector> d311InputElements(STD_ALLOCATOR_RAW_MEM(D3D11_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector")); + LayoutElements_To_D3D11_INPUT_ELEMENT_DESCs(InputLayout, d311InputElements); - ID3DBlob* pVSByteCode = m_pVS.RawPtr()->GetBytecode(); - if (!pVSByteCode) - LOG_ERROR_AND_THROW("Vertex Shader byte code does not exist"); + ID3DBlob* pVSByteCode = m_pVS.RawPtr()->GetBytecode(); + if (!pVSByteCode) + LOG_ERROR_AND_THROW("Vertex Shader byte code does not exist"); - CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateInputLayout(d311InputElements.data(), static_cast(d311InputElements.size()), pVSByteCode->GetBufferPointer(), pVSByteCode->GetBufferSize(), &m_pd3d11InputLayout), - "Failed to create the Direct3D11 input layout"); - } + CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateInputLayout(d311InputElements.data(), static_cast(d311InputElements.size()), pVSByteCode->GetBufferPointer(), pVSByteCode->GetBufferSize(), &m_pd3d11InputLayout), + "Failed to create the Direct3D11 input layout"); } - else + + void* Ptr = MemPool.Release(); + VERIFY_EXPR(Ptr == m_pStaticResourceLayouts); +} + +PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D11Impl* pRenderDeviceD3D11, + const ComputePipelineStateCreateInfo& CreateInfo) : + // clang-format off + TPipelineStateBase { - UNEXPECTED(GetPipelineTypeString(m_Desc.PipelineType), " pipelines are not supported by Direct3D11 backend"); - } + pRefCounters, + pRenderDeviceD3D11, + CreateInfo.PSODesc + }, + m_SRBMemAllocator{GetRawAllocator()}, + m_StaticSamplers (STD_ALLOCATOR_RAW_MEM(StaticSamplerInfo, GetRawAllocator(), "Allocator for vector")) +// clang-format on +{ + m_ResourceLayoutIndex.fill(-1); // We do not really need ShaderStages, but ExtractShaders() also initializes // shader stage types and shader stage counter. std::vector> ShaderStages; - ExtractShaders(ShaderStages); - VERIFY_EXPR(GetNumShaderStages() == ShaderStages.size()); + ExtractShaders(CreateInfo, ShaderStages); - // clang-format off - 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 + // Memory must be released if an exception is thrown. + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(GetNumShaderStages()); + + ValidateAndReserveSpace(CreateInfo, MemPool); + + MemPool.Reserve(); - const auto MemSize = (sizeof(ShaderResourceLayoutD3D11) + sizeof(ShaderResourceCacheD3D11)) * GetNumShaderStages(); - auto* const pRawMem = - ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutD3D11 and ShaderResourceCacheD3D11 arrays", MemSize); + m_pStaticResourceLayouts = MemPool.Allocate(GetNumShaderStages()); + m_pStaticResourceCaches = MemPool.Allocate(GetNumShaderStages()); - m_pStaticResourceLayouts = reinterpret_cast(pRawMem); - m_pStaticResourceCaches = reinterpret_cast(m_pStaticResourceLayouts + GetNumShaderStages()); + InitComputePipeline(CreateInfo, MemPool); + InitResourceLayouts(pRenderDeviceD3D11, CreateInfo, ShaderStages); + auto* pCS = ValidatedCast(CreateInfo.pCS); + m_pCS = pCS; + if (m_pCS == nullptr) + { + LOG_ERROR_AND_THROW("Compute shader is null"); + } + + if (m_pCS && m_pCS->GetDesc().ShaderType != SHADER_TYPE_COMPUTE) + { + LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(SHADER_TYPE_COMPUTE), " shader is expeceted while ", GetShaderTypeLiteralName(m_pCS->GetDesc().ShaderType), " provided"); + } + m_ShaderResourceLayoutHash = pCS->GetD3D11Resources()->GetHash(); + + void* Ptr = MemPool.Release(); + VERIFY_EXPR(Ptr == m_pStaticResourceLayouts); +} + +PipelineStateD3D11Impl::~PipelineStateD3D11Impl() +{ + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) + { + m_pStaticResourceCaches[s].Destroy(GetRawAllocator()); + m_pStaticResourceCaches[s].~ShaderResourceCacheD3D11(); + } + + for (Uint32 l = 0; l < GetNumShaderStages(); ++l) + { + m_pStaticResourceLayouts[l].~ShaderResourceLayoutD3D11(); + } + // m_pStaticResourceLayouts and m_pStaticResourceCaches are allocated in contiguous chunks of memory. + if (auto* pRawMem = m_pStaticResourceLayouts) + GetRawAllocator().Free(pRawMem); +} + +IMPLEMENT_QUERY_INTERFACE(PipelineStateD3D11Impl, IID_PipelineStateD3D11, TPipelineStateBase) + + +void PipelineStateD3D11Impl::InitResourceLayouts(RenderDeviceD3D11Impl* pRenderDeviceD3D11, + const PipelineStateCreateInfo& CreateInfo, + const std::vector>& ShaderStages) +{ const auto& ResourceLayout = m_Desc.ResourceLayout; #ifdef DILIGENT_DEVELOPMENT { const ShaderResources* pResources[MAX_SHADERS_IN_PIPELINE] = {}; - for (Uint32 s = 0; s < GetNumShaderStages(); ++s) + for (Uint32 s = 0; s < ShaderStages.size(); ++s) { - auto* pShader = GetShader(s); + auto* pShader = ShaderStages[s].second; pResources[s] = &(*pShader->GetD3D11Resources()); } ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, GetNumShaderStages(), @@ -168,9 +232,9 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR decltype(m_StaticSamplers) StaticSamplers(STD_ALLOCATOR_RAW_MEM(StaticSamplerInfo, GetRawAllocator(), "Allocator for vector")); std::array ShaderResLayoutDataSizes = {}; std::array ShaderResCacheDataSizes = {}; - for (Uint32 s = 0; s < GetNumShaderStages(); ++s) + for (Uint32 s = 0; s < ShaderStages.size(); ++s) { - const auto* pShader = GetShader(s); + const auto* pShader = ShaderStages[s].second; const auto& ShaderDesc = pShader->GetDesc(); const auto& ShaderResources = *pShader->GetD3D11Resources(); VERIFY_EXPR(ShaderDesc.ShaderType == ShaderResources.GetShaderType()); @@ -242,27 +306,6 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR } } - -PipelineStateD3D11Impl::~PipelineStateD3D11Impl() -{ - for (Uint32 s = 0; s < GetNumShaderStages(); ++s) - { - m_pStaticResourceCaches[s].Destroy(GetRawAllocator()); - m_pStaticResourceCaches[s].~ShaderResourceCacheD3D11(); - } - - for (Uint32 l = 0; l < GetNumShaderStages(); ++l) - { - m_pStaticResourceLayouts[l].~ShaderResourceLayoutD3D11(); - } - // m_pStaticResourceLayouts and m_pStaticResourceCaches are allocated in contiguous chunks of memory. - if (auto* pRawMem = m_pStaticResourceLayouts) - GetRawAllocator().Free(pRawMem); -} - -IMPLEMENT_QUERY_INTERFACE(PipelineStateD3D11Impl, IID_PipelineStateD3D11, TPipelineStateBase) - - ID3D11BlendState* PipelineStateD3D11Impl::GetD3D11BlendState() { return m_pd3d11BlendState; diff --git a/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp index 76020ed8..537d9db2 100644 --- a/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp @@ -385,7 +385,18 @@ void RenderDeviceD3D11Impl::CreateSampler(const SamplerDesc& SamplerDesc, ISampl }); } -void RenderDeviceD3D11Impl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +void RenderDeviceD3D11Impl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreateDeviceObject("Pipeline state", PSOCreateInfo.PSODesc, ppPipelineState, + [&]() // + { + PipelineStateD3D11Impl* pPipelineStateD3D11(NEW_RC_OBJ(m_PSOAllocator, "PipelineStateD3D11Impl instance", PipelineStateD3D11Impl)(this, PSOCreateInfo)); + pPipelineStateD3D11->QueryInterface(IID_PipelineState, reinterpret_cast(ppPipelineState)); + OnCreateDeviceObject(pPipelineStateD3D11); + }); +} + +void RenderDeviceD3D11Impl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) { CreateDeviceObject("Pipeline state", PSOCreateInfo.PSODesc, ppPipelineState, [&]() // diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp index 00b2affd..821ff951 100644 --- a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp @@ -38,6 +38,7 @@ #include "SRBMemoryAllocator.hpp" #include "RenderDeviceD3D12Impl.hpp" #include "ShaderVariableD3D12.hpp" +#include "ShaderD3D12Impl.hpp" namespace Diligent { @@ -50,7 +51,8 @@ class PipelineStateD3D12Impl final : public PipelineStateBase; - PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const PipelineStateCreateInfo& CreateInfo); + PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const GraphicsPipelineStateCreateInfo& CreateInfo); + PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const ComputePipelineStateCreateInfo& CreateInfo); ~PipelineStateD3D12Impl(); virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; @@ -119,15 +121,29 @@ public: } private: + struct D3D12PipelineShaderStageInfo + { + const SHADER_TYPE Type; + ShaderD3D12Impl* const pShader; + D3D12PipelineShaderStageInfo(SHADER_TYPE _Type, + ShaderD3D12Impl* _pShader) : + Type{_Type}, + pShader{_pShader} + {} + }; + void InitResourceLayouts(RenderDeviceD3D12Impl* pDeviceD3D12, + const PipelineStateCreateInfo& CreateInfo, + std::vector& ShaderStages); + CComPtr m_pd3d12PSO; RootSignature m_RootSig; // Must be defined before default SRB SRBMemoryAllocator m_SRBMemAllocator; - ShaderResourceLayoutD3D12* m_pShaderResourceLayouts = nullptr; - ShaderResourceCacheD3D12* m_pStaticResourceCaches = nullptr; - ShaderVariableManagerD3D12* m_pStaticVarManagers = nullptr; + ShaderResourceLayoutD3D12* m_pShaderResourceLayouts = nullptr; // [m_NumShaderStages * 2] + ShaderResourceCacheD3D12* m_pStaticResourceCaches = nullptr; // [m_NumShaderStages] + ShaderVariableManagerD3D12* m_pStaticVarManagers = nullptr; // [m_NumShaderStages] // Resource layout index in m_pShaderResourceLayouts array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp index 0dc4201e..7083e30d 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp @@ -62,8 +62,11 @@ public: virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; - /// Implementation of IRenderDevice::CreatePipelineState() in Direct3D12 backend. - virtual void DILIGENT_CALL_TYPE CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; + /// Implementation of IRenderDevice::CreateGraphicsPipelineState() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; + + /// Implementation of IRenderDevice::CreateComputePipelineState() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; /// Implementation of IRenderDevice::CreateBuffer() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE CreateBuffer(const BufferDesc& BuffDesc, diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 546c9de8..f1bc35eb 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -211,49 +211,58 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) // This is necessary because if the command list had been flushed // and the first PSO set on the command list was a compute pipeline, // the states would otherwise never be committed (since m_pPipelineState != nullptr) - CommitStates = OldPSODesc.IsComputePipeline(); + CommitStates = !OldPSODesc.IsAnyGraphicsPipeline(); // We also need to update scissor rect if ScissorEnable state has changed - CommitScissor = OldPSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable != PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable; + if (OldPSODesc.IsAnyGraphicsPipeline() && PSODesc.IsAnyGraphicsPipeline()) + CommitScissor = m_pPipelineState->GetGraphicsPipelineDesc().RasterizerDesc.ScissorEnable != pPipelineStateD3D12->GetGraphicsPipelineDesc().RasterizerDesc.ScissorEnable; } TDeviceContextBase::SetPipelineState(pPipelineStateD3D12, 0 /*Dummy*/); - auto& CmdCtx = GetCmdContext(); - + auto& CmdCtx = GetCmdContext(); auto* pd3d12PSO = pPipelineStateD3D12->GetD3D12PipelineState(); - if (PSODesc.IsComputePipeline()) - { - CmdCtx.AsComputeContext().SetPipelineState(pd3d12PSO); - } - else + + switch (PSODesc.PipelineType) { - VERIFY_EXPR(PSODesc.IsAnyGraphicsPipeline()); + case PIPELINE_TYPE_GRAPHICS: + case PIPELINE_TYPE_MESH: + { + auto& GraphicsPipeline = pPipelineStateD3D12->GetGraphicsPipelineDesc(); + auto& GraphicsCtx = CmdCtx.AsGraphicsContext(); + GraphicsCtx.SetPipelineState(pd3d12PSO); - auto& GraphicsCtx = CmdCtx.AsGraphicsContext(); - GraphicsCtx.SetPipelineState(pd3d12PSO); + if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) + { + auto D3D12Topology = TopologyToD3D12Topology(GraphicsPipeline.PrimitiveTopology); + GraphicsCtx.SetPrimitiveTopology(D3D12Topology); + } - if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) - { - auto D3D12Topology = TopologyToD3D12Topology(PSODesc.GraphicsPipeline.PrimitiveTopology); - GraphicsCtx.SetPrimitiveTopology(D3D12Topology); - } + if (CommitStates) + { + GraphicsCtx.SetStencilRef(m_StencilRef); + GraphicsCtx.SetBlendFactor(m_BlendFactors); + if (GraphicsPipeline.pRenderPass == nullptr) + { + CommitRenderTargets(RESOURCE_STATE_TRANSITION_MODE_VERIFY); + } + CommitViewports(); + } - if (CommitStates) - { - GraphicsCtx.SetStencilRef(m_StencilRef); - GraphicsCtx.SetBlendFactor(m_BlendFactors); - if (PSODesc.GraphicsPipeline.pRenderPass == nullptr) + if (CommitStates || CommitScissor) { - CommitRenderTargets(RESOURCE_STATE_TRANSITION_MODE_VERIFY); + CommitScissorRects(GraphicsCtx, GraphicsPipeline.RasterizerDesc.ScissorEnable); } - CommitViewports(); + break; } - - if (CommitStates || CommitScissor) + case PIPELINE_TYPE_COMPUTE: { - CommitScissorRects(GraphicsCtx, PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable); + CmdCtx.AsComputeContext().SetPipelineState(pd3d12PSO); + break; } + default: + UNEXPECTED("unknown pipeline type"); } + m_State.pCommittedResourceCache = nullptr; m_State.bRootViewsCommitted = false; } @@ -964,7 +973,7 @@ void DeviceContextD3D12Impl::SetScissorRects(Uint32 NumRects, const Rect* pRects if (m_pPipelineState) { const auto& PSODesc = m_pPipelineState->GetDesc(); - if (PSODesc.IsAnyGraphicsPipeline() && PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable) + if (PSODesc.IsAnyGraphicsPipeline() && m_pPipelineState->GetGraphicsPipelineDesc().RasterizerDesc.ScissorEnable) { VERIFY(NumRects == m_NumScissorRects, "Unexpected number of scissor rects"); auto& Ctx = GetCmdContext().AsGraphicsContext(); diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index f5d60b60..0d26db2a 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -98,44 +98,324 @@ private: std::array m_Map; }; -PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, - RenderDeviceD3D12Impl* pDeviceD3D12, - const PipelineStateCreateInfo& CreateInfo) : +PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDeviceD3D12, + const GraphicsPipelineStateCreateInfo& CreateInfo) : TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo.PSODesc}, m_SRBMemAllocator{GetRawAllocator()} { m_ResourceLayoutIndex.fill(-1); - struct D3D12PipelineShaderStageInfo + std::vector ShaderStages; + ExtractShaders(CreateInfo, ShaderStages); + + // Memory must be released if an exception is thrown. + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddRequiredSize(GetNumShaderStages() * 2); + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(GetNumShaderStages()); + + ValidateAndReserveSpace(CreateInfo, MemPool); + + MemPool.Reserve(); + + auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); + m_RootSig.AllocateStaticSamplers(m_Desc.ResourceLayout); + + m_pShaderResourceLayouts = MemPool.Allocate(GetNumShaderStages() * 2); + m_pStaticResourceCaches = MemPool.Allocate(GetNumShaderStages()); + m_pStaticVarManagers = MemPool.Allocate(GetNumShaderStages()); + + InitGraphicsPipeline(CreateInfo, MemPool); + InitResourceLayouts(pDeviceD3D12, CreateInfo, ShaderStages); + + if (m_Desc.PipelineType == PIPELINE_TYPE_GRAPHICS) + { + const auto& GraphicsPipeline = GetGraphicsPipelineDesc(); + + D3D12_GRAPHICS_PIPELINE_STATE_DESC d3d12PSODesc = {}; + + for (const auto& Stage : ShaderStages) + { + auto* pShaderD3D12 = Stage.pShader; + auto ShaderType = pShaderD3D12->GetDesc().ShaderType; + VERIFY_EXPR(ShaderType == Stage.Type); + + D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; + switch (ShaderType) + { + // clang-format off + case SHADER_TYPE_VERTEX: pd3d12ShaderBytecode = &d3d12PSODesc.VS; break; + case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break; + case SHADER_TYPE_GEOMETRY: pd3d12ShaderBytecode = &d3d12PSODesc.GS; break; + case SHADER_TYPE_HULL: pd3d12ShaderBytecode = &d3d12PSODesc.HS; break; + case SHADER_TYPE_DOMAIN: pd3d12ShaderBytecode = &d3d12PSODesc.DS; break; + // clang-format on + default: UNEXPECTED("Unexpected shader type"); + } + auto* pByteCode = pShaderD3D12->GetShaderByteCode(); + + pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); + pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); + } + + d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + + memset(&d3d12PSODesc.StreamOutput, 0, sizeof(d3d12PSODesc.StreamOutput)); + + BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, d3d12PSODesc.BlendState); + // The sample mask for the blend state. + d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask; + + RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, d3d12PSODesc.RasterizerState); + DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, d3d12PSODesc.DepthStencilState); + + std::vector> d312InputElements(STD_ALLOCATOR_RAW_MEM(D3D12_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector")); + + const auto& InputLayout = GetGraphicsPipelineDesc().InputLayout; + if (InputLayout.NumElements > 0) + { + LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(InputLayout, d312InputElements); + d3d12PSODesc.InputLayout.NumElements = static_cast(d312InputElements.size()); + d3d12PSODesc.InputLayout.pInputElementDescs = d312InputElements.data(); + } + else + { + d3d12PSODesc.InputLayout.NumElements = 0; + d3d12PSODesc.InputLayout.pInputElementDescs = nullptr; + } + + d3d12PSODesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + static const PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimTopologyToD3D12TopologyType; + d3d12PSODesc.PrimitiveTopologyType = PrimTopologyToD3D12TopologyType[GraphicsPipeline.PrimitiveTopology]; + + d3d12PSODesc.NumRenderTargets = GraphicsPipeline.NumRenderTargets; + for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt) + d3d12PSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); + for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(d3d12PSODesc.RTVFormats); ++rt) + d3d12PSODesc.RTVFormats[rt] = DXGI_FORMAT_UNKNOWN; + d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat); + + d3d12PSODesc.SampleDesc.Count = GraphicsPipeline.SmplDesc.Count; + d3d12PSODesc.SampleDesc.Quality = GraphicsPipeline.SmplDesc.Quality; + + // For single GPU operation, set this to zero. If there are multiple GPU nodes, + // set bits to identify the nodes (the device's physical adapters) for which the + // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. + d3d12PSODesc.NodeMask = 0; + + d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; + d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; + + // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. + d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + + HRESULT hr = pd3d12Device->CreateGraphicsPipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast(static_cast(&m_pd3d12PSO))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create pipeline state"); + } + +#ifdef D3D12_H_HAS_MESH_SHADER + else if (m_Desc.PipelineType == PIPELINE_TYPE_MESH) { - const SHADER_TYPE Type; - ShaderD3D12Impl* const pShader; - D3D12PipelineShaderStageInfo(SHADER_TYPE _Type, - ShaderD3D12Impl* _pShader) : - Type{_Type}, - pShader{_pShader} - {} - }; + const auto& GraphicsPipeline = GetGraphicsPipelineDesc(); + + struct MESH_SHADER_PIPELINE_STATE_DESC + { + PSS_SubObject Flags; + PSS_SubObject NodeMask; + PSS_SubObject pRootSignature; + PSS_SubObject PS; + PSS_SubObject AS; + PSS_SubObject MS; + PSS_SubObject BlendState; + PSS_SubObject DepthStencilState; + PSS_SubObject RasterizerState; + PSS_SubObject SampleDesc; + PSS_SubObject SampleMask; + PSS_SubObject DSVFormat; + PSS_SubObject RTVFormatArray; + PSS_SubObject CachedPSO; + }; + MESH_SHADER_PIPELINE_STATE_DESC d3d12PSODesc = {}; + + for (const auto& Stage : ShaderStages) + { + auto* pShaderD3D12 = Stage.pShader; + auto ShaderType = pShaderD3D12->GetDesc().ShaderType; + VERIFY_EXPR(ShaderType == Stage.Type); + + D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; + switch (ShaderType) + { + // clang-format off + case SHADER_TYPE_AMPLIFICATION: pd3d12ShaderBytecode = &d3d12PSODesc.AS; break; + case SHADER_TYPE_MESH: pd3d12ShaderBytecode = &d3d12PSODesc.MS; break; + case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break; + // clang-format on + default: UNEXPECTED("Unexpected shader type"); + } + auto* pByteCode = pShaderD3D12->GetShaderByteCode(); + + pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); + pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); + } + + d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + + BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, *d3d12PSODesc.BlendState); + d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask; + + RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, *d3d12PSODesc.RasterizerState); + DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, *d3d12PSODesc.DepthStencilState); + + d3d12PSODesc.RTVFormatArray->NumRenderTargets = GraphicsPipeline.NumRenderTargets; + for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt) + d3d12PSODesc.RTVFormatArray->RTFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); + for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(d3d12PSODesc.RTVFormatArray->RTFormats); ++rt) + d3d12PSODesc.RTVFormatArray->RTFormats[rt] = DXGI_FORMAT_UNKNOWN; + d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat); + + d3d12PSODesc.SampleDesc->Count = GraphicsPipeline.SmplDesc.Count; + d3d12PSODesc.SampleDesc->Quality = GraphicsPipeline.SmplDesc.Quality; + + // For single GPU operation, set this to zero. If there are multiple GPU nodes, + // set bits to identify the nodes (the device's physical adapters) for which the + // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. + d3d12PSODesc.NodeMask = 0; + + d3d12PSODesc.CachedPSO->pCachedBlob = nullptr; + d3d12PSODesc.CachedPSO->CachedBlobSizeInBytes = 0; + + // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. + d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + + D3D12_PIPELINE_STATE_STREAM_DESC streamDesc; + streamDesc.SizeInBytes = sizeof(d3d12PSODesc); + streamDesc.pPipelineStateSubobjectStream = &d3d12PSODesc; + + auto* device2 = pDeviceD3D12->GetD3D12Device2(); + + CHECK_D3D_RESULT_THROW(device2->CreatePipelineState(&streamDesc, IID_PPV_ARGS(&m_pd3d12PSO)), "Failed to create pipeline state"); + } +#endif // D3D12_H_HAS_MESH_SHADER + else + { + LOG_ERROR_AND_THROW("Unsupported pipeline type"); + } + + if (*m_Desc.Name != 0) + { + m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str()); + String RootSignatureDesc("Root signature for PSO '"); + RootSignatureDesc.append(m_Desc.Name); + RootSignatureDesc.push_back('\''); + m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str()); + } + + void* Ptr = MemPool.Release(); + VERIFY_EXPR(Ptr == m_pShaderResourceLayouts); +} + +PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDeviceD3D12, + const ComputePipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + m_ResourceLayoutIndex.fill(-1); + std::vector ShaderStages; - ExtractShaders(ShaderStages); - VERIFY_EXPR(GetNumShaderStages() == ShaderStages.size()); + ExtractShaders(CreateInfo, ShaderStages); - auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); - const auto& ResourceLayout = m_Desc.ResourceLayout; - m_RootSig.AllocateStaticSamplers(ResourceLayout); + // Memory must be released if an exception is thrown. + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddRequiredSize(GetNumShaderStages() * 2); + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(GetNumShaderStages()); + + ValidateAndReserveSpace(CreateInfo, MemPool); + + MemPool.Reserve(); + + auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); + m_RootSig.AllocateStaticSamplers(m_Desc.ResourceLayout); + + m_pShaderResourceLayouts = MemPool.Allocate(GetNumShaderStages() * 2); + m_pStaticResourceCaches = MemPool.Allocate(GetNumShaderStages()); + m_pStaticVarManagers = MemPool.Allocate(GetNumShaderStages()); + + InitComputePipeline(CreateInfo, MemPool); + InitResourceLayouts(pDeviceD3D12, CreateInfo, ShaderStages); + + D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {}; + + VERIFY_EXPR(ShaderStages[0].Type == SHADER_TYPE_COMPUTE); + auto* pByteCode = ShaderStages[0].pShader->GetShaderByteCode(); + d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); + d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); + + // For single GPU operation, set this to zero. If there are multiple GPU nodes, + // set bits to identify the nodes (the device's physical adapters) for which the + // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. + d3d12PSODesc.NodeMask = 0; + + d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; + d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; + + // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. + d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + + d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + + HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast(static_cast(&m_pd3d12PSO))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create pipeline state"); + + if (*m_Desc.Name != 0) + { + m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str()); + String RootSignatureDesc("Root signature for PSO '"); + RootSignatureDesc.append(m_Desc.Name); + RootSignatureDesc.push_back('\''); + m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str()); + } + + void* Ptr = MemPool.Release(); + VERIFY_EXPR(Ptr == m_pShaderResourceLayouts); +} + +PipelineStateD3D12Impl::~PipelineStateD3D12Impl() +{ + auto& ShaderResLayoutAllocator = GetRawAllocator(); + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) + { + m_pStaticVarManagers[s].Destroy(GetRawAllocator()); + m_pStaticVarManagers[s].~ShaderVariableManagerD3D12(); + m_pStaticResourceCaches[s].~ShaderResourceCacheD3D12(); + m_pShaderResourceLayouts[s].~ShaderResourceLayoutD3D12(); + m_pShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutD3D12(); + } + // m_pShaderResourceLayouts, m_pStaticResourceCaches, and m_pShaderResourceLayouts are allocated in + // contiguous chunks of memory. + auto* pRawMem = m_pShaderResourceLayouts; + ShaderResLayoutAllocator.Free(pRawMem); - // clang-format off - static_assert((sizeof(ShaderResourceLayoutD3D12) % sizeof(void*)) == 0, "sizeof(ShaderResourceLayoutD3D12) is expected to be a multiple of sizeof(void*)"); - 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)) * GetNumShaderStages(); - auto* const pRawMem = - ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutD3D12, ShaderResourceCacheD3D12, and ShaderVariableManagerD3D12 arrays", MemSize); + // D3D12 object can only be destroyed when it is no longer used by the GPU + m_pDevice->SafeReleaseDeviceObject(std::move(m_pd3d12PSO), m_Desc.CommandQueueMask); +} + +IMPLEMENT_QUERY_INTERFACE(PipelineStateD3D12Impl, IID_PipelineStateD3D12, TPipelineStateBase) - m_pShaderResourceLayouts = reinterpret_cast(pRawMem); - m_pStaticResourceCaches = reinterpret_cast(m_pShaderResourceLayouts + GetNumShaderStages() * 2); - m_pStaticVarManagers = reinterpret_cast(m_pStaticResourceCaches + GetNumShaderStages()); + +void PipelineStateD3D12Impl::InitResourceLayouts(RenderDeviceD3D12Impl* pDeviceD3D12, + const PipelineStateCreateInfo& CreateInfo, + std::vector& ShaderStages) +{ + auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); + const auto& ResourceLayout = m_Desc.ResourceLayout; #ifdef DILIGENT_DEVELOPMENT { @@ -205,222 +485,6 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR } m_RootSig.Finalize(pd3d12Device); - switch (m_Desc.PipelineType) - { - case PIPELINE_TYPE_COMPUTE: - { - D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {}; - - VERIFY_EXPR(ShaderStages[0].Type == SHADER_TYPE_COMPUTE); - auto* pByteCode = ShaderStages[0].pShader->GetShaderByteCode(); - d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); - d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); - - // For single GPU operation, set this to zero. If there are multiple GPU nodes, - // set bits to identify the nodes (the device's physical adapters) for which the - // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. - d3d12PSODesc.NodeMask = 0; - - d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; - d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; - - // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. - d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - - d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); - - HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast(static_cast(&m_pd3d12PSO))); - if (FAILED(hr)) - LOG_ERROR_AND_THROW("Failed to create pipeline state"); - break; - } - - case PIPELINE_TYPE_GRAPHICS: - { - const auto& GraphicsPipeline = m_Desc.GraphicsPipeline; - - D3D12_GRAPHICS_PIPELINE_STATE_DESC d3d12PSODesc = {}; - - for (const auto& Stage : ShaderStages) - { - auto* pShaderD3D12 = Stage.pShader; - auto ShaderType = pShaderD3D12->GetDesc().ShaderType; - VERIFY_EXPR(ShaderType == Stage.Type); - - D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: pd3d12ShaderBytecode = &d3d12PSODesc.VS; break; - case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break; - case SHADER_TYPE_GEOMETRY: pd3d12ShaderBytecode = &d3d12PSODesc.GS; break; - case SHADER_TYPE_HULL: pd3d12ShaderBytecode = &d3d12PSODesc.HS; break; - case SHADER_TYPE_DOMAIN: pd3d12ShaderBytecode = &d3d12PSODesc.DS; break; - // clang-format on - default: UNEXPECTED("Unexpected shader type"); - } - auto* pByteCode = pShaderD3D12->GetShaderByteCode(); - - pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); - pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); - } - - d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); - - memset(&d3d12PSODesc.StreamOutput, 0, sizeof(d3d12PSODesc.StreamOutput)); - - BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, d3d12PSODesc.BlendState); - // The sample mask for the blend state. - d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask; - - RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, d3d12PSODesc.RasterizerState); - DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, d3d12PSODesc.DepthStencilState); - - std::vector> d312InputElements(STD_ALLOCATOR_RAW_MEM(D3D12_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector")); - - const auto& InputLayout = m_Desc.GraphicsPipeline.InputLayout; - if (InputLayout.NumElements > 0) - { - LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(InputLayout, d312InputElements); - d3d12PSODesc.InputLayout.NumElements = static_cast(d312InputElements.size()); - d3d12PSODesc.InputLayout.pInputElementDescs = d312InputElements.data(); - } - else - { - d3d12PSODesc.InputLayout.NumElements = 0; - d3d12PSODesc.InputLayout.pInputElementDescs = nullptr; - } - - d3d12PSODesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; - static const PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimTopologyToD3D12TopologyType; - d3d12PSODesc.PrimitiveTopologyType = PrimTopologyToD3D12TopologyType[GraphicsPipeline.PrimitiveTopology]; - - d3d12PSODesc.NumRenderTargets = GraphicsPipeline.NumRenderTargets; - for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt) - d3d12PSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); - for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(d3d12PSODesc.RTVFormats); ++rt) - d3d12PSODesc.RTVFormats[rt] = DXGI_FORMAT_UNKNOWN; - d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat); - - d3d12PSODesc.SampleDesc.Count = GraphicsPipeline.SmplDesc.Count; - d3d12PSODesc.SampleDesc.Quality = GraphicsPipeline.SmplDesc.Quality; - - // For single GPU operation, set this to zero. If there are multiple GPU nodes, - // set bits to identify the nodes (the device's physical adapters) for which the - // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. - d3d12PSODesc.NodeMask = 0; - - d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; - d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; - - // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. - d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - - HRESULT hr = pd3d12Device->CreateGraphicsPipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast(static_cast(&m_pd3d12PSO))); - if (FAILED(hr)) - LOG_ERROR_AND_THROW("Failed to create pipeline state"); - break; - } - -#ifdef D3D12_H_HAS_MESH_SHADER - case PIPELINE_TYPE_MESH: - { - const auto& GraphicsPipeline = m_Desc.GraphicsPipeline; - - struct MESH_SHADER_PIPELINE_STATE_DESC - { - PSS_SubObject Flags; - PSS_SubObject NodeMask; - PSS_SubObject pRootSignature; - PSS_SubObject PS; - PSS_SubObject AS; - PSS_SubObject MS; - PSS_SubObject BlendState; - PSS_SubObject DepthStencilState; - PSS_SubObject RasterizerState; - PSS_SubObject SampleDesc; - PSS_SubObject SampleMask; - PSS_SubObject DSVFormat; - PSS_SubObject RTVFormatArray; - PSS_SubObject CachedPSO; - }; - MESH_SHADER_PIPELINE_STATE_DESC d3d12PSODesc = {}; - - for (const auto& Stage : ShaderStages) - { - auto* pShaderD3D12 = Stage.pShader; - auto ShaderType = pShaderD3D12->GetDesc().ShaderType; - VERIFY_EXPR(ShaderType == Stage.Type); - - D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_AMPLIFICATION: pd3d12ShaderBytecode = &d3d12PSODesc.AS; break; - case SHADER_TYPE_MESH: pd3d12ShaderBytecode = &d3d12PSODesc.MS; break; - case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break; - // clang-format on - default: UNEXPECTED("Unexpected shader type"); - } - auto* pByteCode = pShaderD3D12->GetShaderByteCode(); - - pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); - pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); - } - - d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); - - BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, *d3d12PSODesc.BlendState); - d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask; - - RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, *d3d12PSODesc.RasterizerState); - DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, *d3d12PSODesc.DepthStencilState); - - d3d12PSODesc.RTVFormatArray->NumRenderTargets = GraphicsPipeline.NumRenderTargets; - for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt) - d3d12PSODesc.RTVFormatArray->RTFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); - for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(d3d12PSODesc.RTVFormatArray->RTFormats); ++rt) - d3d12PSODesc.RTVFormatArray->RTFormats[rt] = DXGI_FORMAT_UNKNOWN; - d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat); - - d3d12PSODesc.SampleDesc->Count = GraphicsPipeline.SmplDesc.Count; - d3d12PSODesc.SampleDesc->Quality = GraphicsPipeline.SmplDesc.Quality; - - // For single GPU operation, set this to zero. If there are multiple GPU nodes, - // set bits to identify the nodes (the device's physical adapters) for which the - // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. - d3d12PSODesc.NodeMask = 0; - - d3d12PSODesc.CachedPSO->pCachedBlob = nullptr; - d3d12PSODesc.CachedPSO->CachedBlobSizeInBytes = 0; - - // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. - d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - - D3D12_PIPELINE_STATE_STREAM_DESC streamDesc; - streamDesc.SizeInBytes = sizeof(d3d12PSODesc); - streamDesc.pPipelineStateSubobjectStream = &d3d12PSODesc; - - auto* device2 = pDeviceD3D12->GetD3D12Device2(); - - CHECK_D3D_RESULT_THROW(device2->CreatePipelineState(&streamDesc, IID_PPV_ARGS(&m_pd3d12PSO)), "Failed to create pipeline state"); - break; - } -#endif // D3D12_H_HAS_MESH_SHADER - - default: - LOG_ERROR_AND_THROW("Unsupported pipeline type"); - } - - if (*m_Desc.Name != 0) - { - m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str()); - String RootSignatureDesc("Root signature for PSO '"); - RootSignatureDesc.append(m_Desc.Name); - RootSignatureDesc.push_back('\''); - m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str()); - } - if (m_Desc.SRBAllocationGranularity > 1) { std::array ShaderVarMgrDataSizes = {}; @@ -443,29 +507,6 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR m_ShaderResourceLayoutHash = m_RootSig.GetHash(); } -PipelineStateD3D12Impl::~PipelineStateD3D12Impl() -{ - auto& ShaderResLayoutAllocator = GetRawAllocator(); - for (Uint32 s = 0; s < GetNumShaderStages(); ++s) - { - m_pStaticVarManagers[s].Destroy(GetRawAllocator()); - m_pStaticVarManagers[s].~ShaderVariableManagerD3D12(); - m_pStaticResourceCaches[s].~ShaderResourceCacheD3D12(); - m_pShaderResourceLayouts[s].~ShaderResourceLayoutD3D12(); - m_pShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutD3D12(); - } - // m_pShaderResourceLayouts, m_pStaticResourceCaches, and m_pShaderResourceLayouts are allocated in - // contiguous chunks of memory. - auto* pRawMem = m_pShaderResourceLayouts; - ShaderResLayoutAllocator.Free(pRawMem); - - // D3D12 object can only be destroyed when it is no longer used by the GPU - m_pDevice->SafeReleaseDeviceObject(std::move(m_pd3d12PSO), m_Desc.CommandQueueMask); -} - -IMPLEMENT_QUERY_INTERFACE(PipelineStateD3D12Impl, IID_PipelineStateD3D12, TPipelineStateBase) - - void PipelineStateD3D12Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) { auto& SRBAllocator = m_pDevice->GetSRBAllocator(); diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index db86d662..97069bd2 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -534,7 +534,18 @@ void RenderDeviceD3D12Impl::TestTextureFormat(TEXTURE_FORMAT TexFormat) IMPLEMENT_QUERY_INTERFACE(RenderDeviceD3D12Impl, IID_RenderDeviceD3D12, TRenderDeviceBase) -void RenderDeviceD3D12Impl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +void RenderDeviceD3D12Impl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreateDeviceObject("Pipeline State", PSOCreateInfo.PSODesc, ppPipelineState, + [&]() // + { + PipelineStateD3D12Impl* pPipelineStateD3D12(NEW_RC_OBJ(m_PSOAllocator, "PipelineStateD3D12Impl instance", PipelineStateD3D12Impl)(this, PSOCreateInfo)); + pPipelineStateD3D12->QueryInterface(IID_PipelineState, reinterpret_cast(ppPipelineState)); + OnCreateDeviceObject(pPipelineStateD3D12); + }); +} + +void RenderDeviceD3D12Impl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) { CreateDeviceObject("Pipeline State", PSOCreateInfo.PSODesc, ppPipelineState, [&]() // diff --git a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp index dea1d6c8..55c53c25 100644 --- a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp @@ -37,6 +37,7 @@ #include "GLProgramResources.hpp" #include "GLPipelineResourceLayout.hpp" #include "GLProgramResourceCache.hpp" +#include "ShaderGLImpl.hpp" namespace Diligent { @@ -49,10 +50,14 @@ class PipelineStateGLImpl final : public PipelineStateBase; - PipelineStateGLImpl(IReferenceCounters* pRefCounters, - RenderDeviceGLImpl* pDeviceGL, - const PipelineStateCreateInfo& CreateInfo, - bool IsDeviceInternal = false); + PipelineStateGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDeviceGL, + const GraphicsPipelineStateCreateInfo& CreateInfo, + bool IsDeviceInternal = false); + PipelineStateGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDeviceGL, + const ComputePipelineStateCreateInfo& CreateInfo, + bool IsDeviceInternal = false); ~PipelineStateGLImpl(); /// Queries the specific interface, see IObject::QueryInterface() for details @@ -92,10 +97,25 @@ private: void InitStaticSamplersInResourceCache(const GLPipelineResourceLayout& ResourceLayout, GLProgramResourceCache& Cache) const; + struct GLPipelineShaderStageInfo + { + const SHADER_TYPE Type; + ShaderGLImpl* const pShader; + GLPipelineShaderStageInfo(SHADER_TYPE _Type, + ShaderGLImpl* _pShader) : + Type{_Type}, + pShader{_pShader} + {} + }; + void InitResourceLayouts(RenderDeviceGLImpl* pDeviceVk, + const std::vector& ShaderStages, + LinearAllocator& MemPool); + // Linked GL programs for every shader stage. Every pipeline needs to have its own programs // because resource bindings assigned by GLProgramResources::LoadUniforms depend on other // shader stages. - std::vector m_GLPrograms; + using GLProgramObj = GLObjectWrappers::GLProgramObj; + GLProgramObj* m_GLPrograms = nullptr; // [m_NumShaderStages] ThreadingTools::LockFlag m_ProgPipelineLockFlag; @@ -113,14 +133,15 @@ private: GLProgramResourceCache m_StaticResourceCache; // Program resources for all shader stages in the pipeline - std::vector m_ProgramResources; + GLProgramResources* m_ProgramResources = nullptr; // [m_NumShaderStages] Uint32 m_TotalUniformBufferBindings = 0; Uint32 m_TotalSamplerBindings = 0; Uint32 m_TotalImageBindings = 0; Uint32 m_TotalStorageBufferBindings = 0; - std::vector> m_StaticSamplers; + using SamplerPtr = RefCntAutoPtr; + SamplerPtr* m_StaticSamplers = nullptr; // [m_Desc.ResourceLayout.NumStaticSamplers] }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp index afb46edb..d23142e0 100644 --- a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp @@ -86,12 +86,20 @@ public: virtual void DILIGENT_CALL_TYPE CreateSampler(const SamplerDesc& SamplerDesc, ISampler** ppSampler) override final; - /// Implementation of IRenderDevice::CreatePipelineState() in OpenGL backend. - void CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, - IPipelineState** ppPipelineState, - bool bIsDeviceInternal); - virtual void DILIGENT_CALL_TYPE CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, - IPipelineState** ppPipelineState) override final; + /// Implementation of IRenderDevice::CreateGraphicsPipelineState() in OpenGL backend. + virtual void CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, + IPipelineState** ppPipelineState) override final; + + /// Implementation of IRenderDevice::CreateComputePipelineState() in OpenGL backend. + virtual void CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, + IPipelineState** ppPipelineState) override final; + + void CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, + IPipelineState** ppPipelineState, + bool bIsDeviceInternal); + void CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, + IPipelineState** ppPipelineState, + bool bIsDeviceInternal); /// Implementation of IRenderDevice::CreateFence() in OpenGL backend. virtual void DILIGENT_CALL_TYPE CreateFence(const FenceDesc& Desc, IFence** ppFence) override final; diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index f4ef1136..d8af2feb 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -85,12 +85,12 @@ void DeviceContextGLImpl::SetPipelineState(IPipelineState* pPipelineState) TDeviceContextBase::SetPipelineState(pPipelineStateGLImpl, 0 /*Dummy*/); const auto& Desc = pPipelineStateGLImpl->GetDesc(); - if (Desc.IsComputePipeline()) + if (Desc.PipelineType == PIPELINE_TYPE_COMPUTE) { } else if (Desc.PipelineType == PIPELINE_TYPE_GRAPHICS) { - const auto& GraphicsPipeline = Desc.GraphicsPipeline; + const auto& GraphicsPipeline = pPipelineStateGLImpl->GetGraphicsPipelineDesc(); // Set rasterizer state { const auto& RasterizerDesc = GraphicsPipeline.RasterizerDesc; @@ -896,7 +896,7 @@ void DeviceContextGLImpl::PrepareForDraw(DRAW_FLAGS Flags, bool IsIndexed, GLenu m_pPipelineState->CommitProgram(m_ContextState); auto CurrNativeGLContext = m_pDevice->m_GLContext.GetCurrentNativeGLContext(); - const auto& PipelineDesc = m_pPipelineState->GetDesc().GraphicsPipeline; + const auto& PipelineDesc = m_pPipelineState->GetGraphicsPipelineDesc(); if (!m_ContextState.IsValidVAOBound()) { auto& VAOCache = m_pDevice->GetVAOCache(CurrNativeGLContext); diff --git a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp index 8590e203..4ac36396 100644 --- a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp @@ -36,10 +36,10 @@ namespace Diligent { -PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters, - RenderDeviceGLImpl* pDeviceGL, - const PipelineStateCreateInfo& CreateInfo, - bool bIsDeviceInternal) : +PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDeviceGL, + const GraphicsPipelineStateCreateInfo& CreateInfo, + bool bIsDeviceInternal) : // clang-format off TPipelineStateBase { @@ -52,8 +52,11 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun m_StaticResourceLayout{*this} // clang-format on { + std::vector ShaderStages; + ExtractShaders(CreateInfo, ShaderStages); + RefCntAutoPtr pTempPS; - if (m_Desc.IsAnyGraphicsPipeline() && m_Desc.GraphicsPipeline.pPS == nullptr) + if (CreateInfo.pPS == nullptr) { // Some OpenGL implementations fail if fragment shader is not present, so // create a dummy one. @@ -64,22 +67,92 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun ShaderCI.Desc.Name = "Dummy fragment shader"; pDeviceGL->CreateShader(ShaderCI, reinterpret_cast(static_cast(&pTempPS))); - m_Desc.GraphicsPipeline.pPS = pTempPS; + ShaderStages.emplace_back(SHADER_TYPE_PIXEL, pTempPS); + m_ShaderStageTypes[m_NumShaderStages++] = SHADER_TYPE_PIXEL; } - struct GLPipelineShaderStageInfo + // Memory must be released if an exception is thrown. + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(m_Desc.ResourceLayout.NumStaticSamplers); + + ValidateAndReserveSpace(CreateInfo, MemPool); + + MemPool.Reserve(); + + InitResourceLayouts(pDeviceGL, ShaderStages, MemPool); + InitGraphicsPipeline(CreateInfo, MemPool); + + void* Ptr = MemPool.Release(); + VERIFY_EXPR(Ptr == m_GLPrograms); +} + +PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDeviceGL, + const ComputePipelineStateCreateInfo& CreateInfo, + bool bIsDeviceInternal) : + // clang-format off + TPipelineStateBase { - const SHADER_TYPE Type; - ShaderGLImpl* const pShader; - GLPipelineShaderStageInfo(SHADER_TYPE _Type, - ShaderGLImpl* _pShader) : - Type{_Type}, - pShader{_pShader} - {} - }; + pRefCounters, + pDeviceGL, + CreateInfo.PSODesc, + bIsDeviceInternal + }, + m_ResourceLayout {*this}, + m_StaticResourceLayout{*this} +// clang-format on +{ std::vector ShaderStages; - ExtractShaders(ShaderStages); + ExtractShaders(CreateInfo, ShaderStages); + + // Memory must be released if an exception is thrown. + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(m_Desc.ResourceLayout.NumStaticSamplers); + + ValidateAndReserveSpace(CreateInfo, MemPool); + + MemPool.Reserve(); + + InitResourceLayouts(pDeviceGL, ShaderStages, MemPool); + InitComputePipeline(CreateInfo, MemPool); + + void* Ptr = MemPool.Release(); + VERIFY_EXPR(Ptr == m_GLPrograms); +} +PipelineStateGLImpl::~PipelineStateGLImpl() +{ + auto& RawAllocator = GetRawAllocator(); + m_StaticResourceCache.Destroy(RawAllocator); + GetDevice()->OnDestroyPSO(this); + + for (Uint32 i = 0; i < GetNumShaderStages(); ++i) + { + m_GLPrograms[i].~GLProgramObj(); + m_ProgramResources[i].~GLProgramResources(); + } + for (Uint32 i = 0; i < m_Desc.ResourceLayout.NumStaticSamplers; ++i) + { + m_StaticSamplers[i].~SamplerPtr(); + } + + void* pRawMem = m_GLPrograms; + RawAllocator.Free(pRawMem); +} + +IMPLEMENT_QUERY_INTERFACE(PipelineStateGLImpl, IID_PipelineStateGL, TPipelineStateBase) + + +void PipelineStateGLImpl::InitResourceLayouts(RenderDeviceGLImpl* pDeviceGL, + const std::vector& ShaderStages, + LinearAllocator& MemPool) +{ auto& DeviceCaps = pDeviceGL->GetDeviceCaps(); VERIFY(DeviceCaps.DevType != RENDER_DEVICE_TYPE_UNDEFINED, "Device caps are not initialized"); @@ -97,13 +170,13 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun // Program pipelines are not shared between GL contexts, so we cannot create // it now m_ShaderResourceLayoutHash = 0; - m_ProgramResources.resize(ShaderStages.size()); - m_GLPrograms.reserve(ShaderStages.size()); + m_GLPrograms = MemPool.Allocate(ShaderStages.size()); + m_ProgramResources = MemPool.ConstructArray(ShaderStages.size()); for (size_t i = 0; i < ShaderStages.size(); ++i) { auto* pShaderGL = ShaderStages[i].pShader; const auto& ShaderDesc = pShaderGL->GetDesc(); - m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(&pShaderGL, 1, true)); + new (m_GLPrograms + i) GLProgramObj{ShaderGLImpl::LinkProgram(&pShaderGL, 1, true)}; // Load uniforms and assign bindings m_ProgramResources[i].LoadUniforms(ShaderDesc.ShaderType, m_GLPrograms[i], GLState, m_TotalUniformBufferBindings, @@ -126,8 +199,9 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun ActiveStages |= Stage.Type; } - m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(Shaders.data(), static_cast(ShaderStages.size()), false)); - m_ProgramResources.resize(1); + m_GLPrograms = MemPool.Construct(ShaderGLImpl::LinkProgram(Shaders.data(), static_cast(ShaderStages.size()), false)); + m_ProgramResources = MemPool.Construct(); + m_ProgramResources[0].LoadUniforms(ActiveStages, m_GLPrograms[0], GLState, m_TotalUniformBufferBindings, m_TotalSamplerBindings, @@ -138,10 +212,10 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun } // Initialize master resource layout that keeps all variable types and does not reference a resource cache - m_ResourceLayout.Initialize(m_ProgramResources.data(), static_cast(m_GLPrograms.size()), m_Desc.PipelineType, m_Desc.ResourceLayout, nullptr, 0, nullptr); + m_ResourceLayout.Initialize(m_ProgramResources, static_cast(ShaderStages.size()), m_Desc.PipelineType, m_Desc.ResourceLayout, nullptr, 0, nullptr); } - m_StaticSamplers.resize(m_Desc.ResourceLayout.NumStaticSamplers); + m_StaticSamplers = MemPool.ConstructArray(m_Desc.ResourceLayout.NumStaticSamplers); for (Uint32 s = 0; s < m_Desc.ResourceLayout.NumStaticSamplers; ++s) { pDeviceGL->CreateSampler(m_Desc.ResourceLayout.StaticSamplers[s].Desc, &m_StaticSamplers[s]); @@ -150,26 +224,16 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun { // Clone only static variables into static resource layout, assign and initialize static resource cache const SHADER_RESOURCE_VARIABLE_TYPE StaticVars[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; - m_StaticResourceLayout.Initialize(m_ProgramResources.data(), static_cast(m_GLPrograms.size()), m_Desc.PipelineType, m_Desc.ResourceLayout, StaticVars, _countof(StaticVars), &m_StaticResourceCache); + m_StaticResourceLayout.Initialize(m_ProgramResources, static_cast(ShaderStages.size()), m_Desc.PipelineType, m_Desc.ResourceLayout, StaticVars, _countof(StaticVars), &m_StaticResourceCache); InitStaticSamplersInResourceCache(m_StaticResourceLayout, m_StaticResourceCache); } } - -PipelineStateGLImpl::~PipelineStateGLImpl() -{ - m_StaticResourceCache.Destroy(GetRawAllocator()); - GetDevice()->OnDestroyPSO(this); -} - -IMPLEMENT_QUERY_INTERFACE(PipelineStateGLImpl, IID_PipelineStateGL, TPipelineStateBase) - - void PipelineStateGLImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) { auto* pRenderDeviceGL = GetDevice(); auto& SRBAllocator = pRenderDeviceGL->GetSRBAllocator(); - auto pResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingGLImpl instance", ShaderResourceBindingGLImpl)(this, m_ProgramResources.data(), static_cast(m_ProgramResources.size())); + auto pResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingGLImpl instance", ShaderResourceBindingGLImpl)(this, m_ProgramResources, GetNumShaderStages()); if (InitStaticResources) pResBinding->InitializeStaticResources(this); pResBinding->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast(ppShaderResourceBinding)); @@ -186,10 +250,10 @@ bool PipelineStateGLImpl::IsCompatibleWith(const IPipelineState* pPSO) const if (m_ShaderResourceLayoutHash != pPSOGL->m_ShaderResourceLayoutHash) return false; - if (m_ProgramResources.size() != pPSOGL->m_ProgramResources.size()) + if (GetNumShaderStages() != pPSOGL->GetNumShaderStages()) return false; - for (size_t i = 0; i < m_ProgramResources.size(); ++i) + for (size_t i = 0; i < GetNumShaderStages(); ++i) { if (!m_ProgramResources[i].IsCompatibleWith(pPSOGL->m_ProgramResources[i])) return false; @@ -214,7 +278,7 @@ void PipelineStateGLImpl::CommitProgram(GLContextState& State) } else { - VERIFY_EXPR(m_GLPrograms.size() == 1); + VERIFY_EXPR(m_GLPrograms != nullptr); State.SetProgram(m_GLPrograms[0]); } } diff --git a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp index 466f1387..59b4bdfd 100644 --- a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp @@ -696,13 +696,20 @@ void RenderDeviceGLImpl::CreateSampler(const SamplerDesc& SamplerDesc, ISampler* CreateSampler(SamplerDesc, ppSampler, false); } - -void RenderDeviceGLImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +void RenderDeviceGLImpl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState, bool bIsDeviceInternal) { - CreatePipelineState(PSOCreateInfo, ppPipelineState, false); + CreateDeviceObject( + "Pipeline state", PSOCreateInfo.PSODesc, ppPipelineState, + [&]() // + { + PipelineStateGLImpl* pPipelineStateOGL(NEW_RC_OBJ(m_PSOAllocator, "PipelineStateGLImpl instance", PipelineStateGLImpl)(this, PSOCreateInfo, bIsDeviceInternal)); + pPipelineStateOGL->QueryInterface(IID_PipelineState, reinterpret_cast(ppPipelineState)); + OnCreateDeviceObject(pPipelineStateOGL); + } // + ); } -void RenderDeviceGLImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState, bool bIsDeviceInternal) +void RenderDeviceGLImpl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState, bool bIsDeviceInternal) { CreateDeviceObject( "Pipeline state", PSOCreateInfo.PSODesc, ppPipelineState, @@ -715,6 +722,16 @@ void RenderDeviceGLImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOC ); } +void RenderDeviceGLImpl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + return CreateGraphicsPipelineState(PSOCreateInfo, ppPipelineState, false); +} + +void RenderDeviceGLImpl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + return CreateComputePipelineState(PSOCreateInfo, ppPipelineState, false); +} + void RenderDeviceGLImpl::CreateFence(const FenceDesc& Desc, IFence** ppFence) { CreateDeviceObject( diff --git a/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp b/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp index bd47e4ac..1a9c99c0 100644 --- a/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp @@ -105,16 +105,15 @@ TexRegionRender::TexRegionRender(class RenderDeviceGLImpl* pDeviceGL) CBDesc.CPUAccessFlags = CPU_ACCESS_WRITE; pDeviceGL->CreateBuffer(CBDesc, nullptr, &m_pConstantBuffer, IsInternalDeviceObject); - PipelineStateCreateInfo PSOCreateInfo; - PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc; + GraphicsPipelineStateCreateInfo PSOCreateInfo; - auto& GraphicsPipeline = PSODesc.GraphicsPipeline; + auto& GraphicsPipeline = PSOCreateInfo.GraphicsPipeline; GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_NONE; GraphicsPipeline.RasterizerDesc.FillMode = FILL_MODE_SOLID; GraphicsPipeline.DepthStencilDesc.DepthEnable = False; GraphicsPipeline.DepthStencilDesc.DepthWriteEnable = False; - GraphicsPipeline.pVS = m_pVertexShader; + PSOCreateInfo.pVS = m_pVertexShader; GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; static const char* CmpTypePrefix[3] = {"", "i", "u"}; @@ -150,17 +149,17 @@ TexRegionRender::TexRegionRender(class RenderDeviceGLImpl* pDeviceGL) ShaderAttrs.Source = Source.c_str(); auto& FragmetShader = m_pFragmentShaders[Dim * 3 + Fmt]; pDeviceGL->CreateShader(ShaderAttrs, &FragmetShader, IsInternalDeviceObject); - GraphicsPipeline.pPS = FragmetShader; + PSOCreateInfo.pPS = FragmetShader; - PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; + PSOCreateInfo.PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; ShaderResourceVariableDesc Vars[] = { {SHADER_TYPE_PIXEL, "cbConstants", SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE} // }; - PSODesc.ResourceLayout.NumVariables = _countof(Vars); - PSODesc.ResourceLayout.Variables = Vars; + PSOCreateInfo.PSODesc.ResourceLayout.NumVariables = _countof(Vars); + PSOCreateInfo.PSODesc.ResourceLayout.Variables = Vars; - pDeviceGL->CreatePipelineState(PSOCreateInfo, &m_pPSO[Dim * 3 + Fmt], IsInternalDeviceObject); + pDeviceGL->CreateGraphicsPipelineState(PSOCreateInfo, &m_pPSO[Dim * 3 + Fmt], IsInternalDeviceObject); } } m_pPSO[RESOURCE_DIM_TEX_2D * 3]->CreateShaderResourceBinding(&m_pSRB); diff --git a/Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp b/Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp index 8838b968..acb22e2a 100644 --- a/Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp @@ -93,7 +93,7 @@ const GLObjectWrappers::GLVertexArrayObj& VAOCache::GetVAO(IPipelineState* // Get layout auto* pPSOGL = ValidatedCast(pPSO); auto* pIndexBufferGL = ValidatedCast(pIndexBuffer); - const auto& InputLayout = pPSOGL->GetDesc().GraphicsPipeline.InputLayout; + const auto& InputLayout = pPSOGL->GetGraphicsPipelineDesc().InputLayout; const LayoutElement* LayoutElems = InputLayout.LayoutElements; Uint32 NumElems = InputLayout.NumElements; // Construct the key diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp index 2185dabd..1773e743 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp @@ -57,7 +57,8 @@ class PipelineStateVkImpl final : public PipelineStateBase; - PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const PipelineStateCreateInfo& CreateInfo); + PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const GraphicsPipelineStateCreateInfo& CreateInfo); + PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const ComputePipelineStateCreateInfo& CreateInfo); ~PipelineStateVkImpl(); virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; @@ -125,6 +126,11 @@ public: void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const; private: + using TShaderStages = ShaderResourceLayoutVk::TShaderStages; + void InitResourceLayouts(RenderDeviceVkImpl* pDeviceVk, + const PipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages); + const ShaderResourceLayoutVk& GetStaticShaderResLayout(Uint32 ShaderInd) const { VERIFY_EXPR(ShaderInd < GetNumShaderStages()); @@ -143,9 +149,9 @@ private: return m_StaticVarsMgrs[ShaderInd]; } - ShaderResourceLayoutVk* m_ShaderResourceLayouts = nullptr; - ShaderResourceCacheVk* m_StaticResCaches = nullptr; - ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; + ShaderResourceLayoutVk* m_ShaderResourceLayouts = nullptr; // [m_NumShaderStages * 2] + ShaderResourceCacheVk* m_StaticResCaches = nullptr; // [m_NumShaderStages] + ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; // [m_NumShaderStages] // SRB memory allocator must be declared before m_pDefaultShaderResBinding SRBMemoryAllocator m_SRBMemAllocator; diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index 25a9f44b..24f3345c 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -72,8 +72,11 @@ public: virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; - /// Implementation of IRenderDevice::CreatePipelineState() in Vulkan backend. - virtual void DILIGENT_CALL_TYPE CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; + /// Implementation of IRenderDevice::CreateGraphicsPipelineState() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; + + /// Implementation of IRenderDevice::CreateComputePipelineState() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; /// Implementation of IRenderDevice::CreateBuffer() in Vulkan backend. virtual void DILIGENT_CALL_TYPE CreateBuffer(const BufferDesc& BuffDesc, diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 2d7b9591..c8b231c2 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -257,39 +257,49 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) else { const auto& OldPSODesc = m_pPipelineState->GetDesc(); - // Commit all graphics states when switching from compute pipeline + // Commit all graphics states when switching from non-graphics pipeline // This is necessary because if the command list had been flushed // and the first PSO set on the command list was a compute pipeline, // the states would otherwise never be committed (since m_pPipelineState != nullptr) - CommitStates = OldPSODesc.IsComputePipeline(); + CommitStates = !OldPSODesc.IsAnyGraphicsPipeline(); // We also need to update scissor rect if ScissorEnable state was disabled in previous pipeline - CommitScissor = !OldPSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable; + if (OldPSODesc.IsAnyGraphicsPipeline()) + CommitScissor = !m_pPipelineState->GetGraphicsPipelineDesc().RasterizerDesc.ScissorEnable; } TDeviceContextBase::SetPipelineState(pPipelineStateVk, 0 /*Dummy*/); EnsureVkCmdBuffer(); - if (PSODesc.IsComputePipeline()) - { - auto vkPipeline = pPipelineStateVk->GetVkPipeline(); - m_CommandBuffer.BindComputePipeline(vkPipeline); - } - else - { - auto vkPipeline = pPipelineStateVk->GetVkPipeline(); - m_CommandBuffer.BindGraphicsPipeline(vkPipeline); + auto vkPipeline = pPipelineStateVk->GetVkPipeline(); - if (CommitStates) + switch (PSODesc.PipelineType) + { + case PIPELINE_TYPE_GRAPHICS: + case PIPELINE_TYPE_MESH: { - m_CommandBuffer.SetStencilReference(m_StencilRef); - m_CommandBuffer.SetBlendConstants(m_BlendFactors); - CommitViewports(); - } + auto& GraphicsPipeline = pPipelineStateVk->GetGraphicsPipelineDesc(); + m_CommandBuffer.BindGraphicsPipeline(vkPipeline); + + if (CommitStates) + { + m_CommandBuffer.SetStencilReference(m_StencilRef); + m_CommandBuffer.SetBlendConstants(m_BlendFactors); + CommitViewports(); + } - if (PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable && (CommitStates || CommitScissor)) + if (GraphicsPipeline.RasterizerDesc.ScissorEnable && (CommitStates || CommitScissor)) + { + CommitScissorRects(); + } + break; + } + case PIPELINE_TYPE_COMPUTE: { - CommitScissorRects(); + m_CommandBuffer.BindComputePipeline(vkPipeline); + break; } + default: + UNEXPECTED("unknown pipeline type"); } m_DescrSetBindInfo.Reset(); @@ -381,8 +391,11 @@ void DeviceContextVkImpl::CommitVkVertexBuffers() void DeviceContextVkImpl::DvpLogRenderPass_PSOMismatch() { + const auto& Desc = m_pPipelineState->GetDesc(); + const auto& GrPipeline = m_pPipelineState->GetGraphicsPipelineDesc(); + std::stringstream ss; - ss << "Active render pass is incomaptible with PSO '" << m_pPipelineState->GetDesc().Name + ss << "Active render pass is incomaptible with PSO '" << Desc.Name << "'. This indicates the mismatch between the number and/or format of bound render " "targets and/or depth stencil buffer and the PSO. Vulkand requires exact match.\n" " Bound render targets (" @@ -411,7 +424,6 @@ void DeviceContextVkImpl::DvpLogRenderPass_PSOMismatch() ss << ""; ss << "; Sample count: " << SampleCount; - const auto& GrPipeline = m_pPipelineState->GetDesc().GraphicsPipeline; ss << "\n PSO: render targets (" << Uint32{GrPipeline.NumRenderTargets} << "): "; for (Uint32 rt = 0; rt < GrPipeline.NumRenderTargets; ++rt) ss << ' ' << GetTextureFormatAttribs(GrPipeline.RTVFormats[rt]).Name; @@ -472,7 +484,7 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) # endif #endif - if (m_pPipelineState->GetDesc().GraphicsPipeline.pRenderPass == nullptr) + if (m_pPipelineState->GetGraphicsPipelineDesc().pRenderPass == nullptr) { #ifdef DILIGENT_DEVELOPMENT if (m_pPipelineState->GetRenderPass()->GetVkRenderPass() != m_vkRenderPass) @@ -1110,7 +1122,7 @@ void DeviceContextVkImpl::SetViewports(Uint32 NumViewports, const Viewport* pVie void DeviceContextVkImpl::CommitScissorRects() { - VERIFY(m_pPipelineState && m_pPipelineState->GetDesc().GraphicsPipeline.RasterizerDesc.ScissorEnable, "Scissor test must be enabled in the graphics pipeline"); + VERIFY(m_pPipelineState && m_pPipelineState->GetGraphicsPipelineDesc().RasterizerDesc.ScissorEnable, "Scissor test must be enabled in the graphics pipeline"); if (m_NumScissorRects == 0) return; // Scissors have not been set in the context yet @@ -1136,14 +1148,10 @@ void DeviceContextVkImpl::SetScissorRects(Uint32 NumRects, const Rect* pRects, U // Only commit scissor rects if scissor test is enabled in the rasterizer state. // If scissor is currently disabled, or no PSO is bound, scissor rects will be committed by // the SetPipelineState() when a PSO with enabled scissor test is set. - if (m_pPipelineState) + if (m_pPipelineState && m_pPipelineState->GetDesc().IsAnyGraphicsPipeline() && m_pPipelineState->GetGraphicsPipelineDesc().RasterizerDesc.ScissorEnable) { - const auto& PSODesc = m_pPipelineState->GetDesc(); - if (PSODesc.IsAnyGraphicsPipeline() && PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable) - { - VERIFY(NumRects == m_NumScissorRects, "Unexpected number of scissor rects"); - CommitScissorRects(); - } + VERIFY(NumRects == m_NumScissorRects, "Unexpected number of scissor rects"); + CommitScissorRects(); } } diff --git a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp index 5110c873..d6f4b0be 100644 --- a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp +++ b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp @@ -154,12 +154,12 @@ std::array, 4> GenerateMipsVkHelper::CreatePSOs(TE m_DeviceVkImpl.CreateShader(CSCreateInfo, &pCS); - PipelineStateCreateInfo PSOCreateInfo; - PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc; + ComputePipelineStateCreateInfo PSOCreateInfo; + PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc; - PSODesc.PipelineType = PIPELINE_TYPE_COMPUTE; - PSODesc.Name = name.c_str(); - PSODesc.ComputePipeline.pCS = pCS; + PSODesc.PipelineType = PIPELINE_TYPE_COMPUTE; + PSODesc.Name = name.c_str(); + PSOCreateInfo.pCS = pCS; PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; ShaderResourceVariableDesc VarDesc{SHADER_TYPE_COMPUTE, "CB", SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; @@ -170,7 +170,7 @@ std::array, 4> GenerateMipsVkHelper::CreatePSOs(TE PSODesc.ResourceLayout.StaticSamplers = &StaticSampler; PSODesc.ResourceLayout.NumStaticSamplers = 1; - m_DeviceVkImpl.CreatePipelineState(PSOCreateInfo, &PSOs[NonPowOfTwo]); + m_DeviceVkImpl.CreateComputePipelineState(PSOCreateInfo, &PSOs[NonPowOfTwo]); PSOs[NonPowOfTwo]->GetStaticVariableByName(SHADER_TYPE_COMPUTE, "CB")->Set(m_ConstantsCB); } #endif diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index fbc5fae3..3e4154be 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -196,7 +196,7 @@ static void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice& static void CreateComputePipeline(RenderDeviceVkImpl* pDeviceVk, std::vector& Stages, const PipelineLayout& Layout, - const PipelineStateDesc& Desc, + const PipelineStateDesc& PSODesc, VulkanUtilities::PipelineWrapper& Pipeline) { const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); @@ -214,21 +214,21 @@ static void CreateComputePipeline(RenderDeviceVkImpl* PipelineCI.stage = Stages[0]; PipelineCI.layout = Layout.GetVkPipelineLayout(); - Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, Desc.Name); + Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, PSODesc.Name); } static void CreateGraphicsPipeline(RenderDeviceVkImpl* pDeviceVk, std::vector& Stages, const PipelineLayout& Layout, - const PipelineStateDesc& Desc, + const PipelineStateDesc& PSODesc, + const GraphicsPipelineDesc& GraphicsPipeline, VulkanUtilities::PipelineWrapper& Pipeline, RefCntAutoPtr& pRenderPass) { - const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); - const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); - auto& GraphicsPipeline = Desc.GraphicsPipeline; - auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); + auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); if (pRenderPass == nullptr) { @@ -276,7 +276,7 @@ static void CreateGraphicsPipeline(RenderDeviceVkImpl* TessStateCI.flags = 0; // reserved for future use PipelineCI.pTessellationState = &TessStateCI; - if (Desc.PipelineType == PIPELINE_TYPE_MESH) + if (PSODesc.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. @@ -394,40 +394,19 @@ static void CreateGraphicsPipeline(RenderDeviceVkImpl* PipelineCI.renderPass = pRenderPass.RawPtr()->GetVkRenderPass(); - PipelineCI.subpass = Desc.GraphicsPipeline.SubpassIndex; + PipelineCI.subpass = 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); + Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, PSODesc.Name); } - -PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pDeviceVk, - const PipelineStateCreateInfo& CreateInfo) : - TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, - m_SRBMemAllocator{GetRawAllocator()} +void PipelineStateVkImpl::InitResourceLayouts(RenderDeviceVkImpl* pDeviceVk, + const PipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages) { - m_ResourceLayoutIndex.fill(-1); - const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); - ShaderResourceLayoutVk::TShaderStages ShaderStages; - ExtractShaders(ShaderStages); - - // 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)) * GetNumShaderStages(); - auto* const pRawMem = - ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutVk, ShaderResourceCacheVk, and ShaderVariableManagerVk arrays", MemSize); - - m_ShaderResourceLayouts = reinterpret_cast(pRawMem); - m_StaticResCaches = reinterpret_cast(m_ShaderResourceLayouts + GetNumShaderStages() * 2); - m_StaticVarsMgrs = reinterpret_cast(m_StaticResCaches + GetNumShaderStages()); - for (size_t s = 0; s < ShaderStages.size(); ++s) { auto& StageInfo = ShaderStages[s]; @@ -436,7 +415,6 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk{LogicalDevice}; - m_ResourceLayoutIndex[ShaderTypeInd] = static_cast(s); auto* pStaticResLayout = new (m_ShaderResourceLayouts + ShaderStages.size() + s) ShaderResourceLayoutVk{LogicalDevice}; @@ -469,22 +447,6 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderVariableDataSizes.data(), 1, &CacheMemorySize); } - // Create shader modules and initialize shader stages - std::vector VkShaderStages; - std::vector ShaderModules; - InitPipelineShaderStages(LogicalDevice, ShaderStages, ShaderModules, VkShaderStages); - - // 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 < GetNumShaderStages(); ++s) @@ -501,6 +463,89 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun m_ShaderResourceLayoutHash = m_PipelineLayout.GetHash(); } + +PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVk, + const GraphicsPipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + m_ResourceLayoutIndex.fill(-1); + + ShaderResourceLayoutVk::TShaderStages ShaderStages; + ExtractShaders(CreateInfo, ShaderStages); + + // Memory must be released if an exception is thrown. + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddRequiredSize(GetNumShaderStages() * 2); + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(GetNumShaderStages()); + + ValidateAndReserveSpace(CreateInfo, MemPool); + + MemPool.Reserve(); + + m_ShaderResourceLayouts = MemPool.Allocate(GetNumShaderStages() * 2); + m_StaticResCaches = MemPool.Allocate(GetNumShaderStages()); + m_StaticVarsMgrs = MemPool.Allocate(GetNumShaderStages()); + + InitGraphicsPipeline(CreateInfo, MemPool); + InitResourceLayouts(pDeviceVk, CreateInfo, ShaderStages); + + // Create shader modules and initialize shader stages + std::vector VkShaderStages; + std::vector ShaderModules; + InitPipelineShaderStages(pDeviceVk->GetLogicalDevice(), ShaderStages, ShaderModules, VkShaderStages); + + CreateGraphicsPipeline(pDeviceVk, VkShaderStages, m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass); + + void* Ptr = MemPool.Release(); + VERIFY_EXPR(Ptr == m_ShaderResourceLayouts); +} + + +PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVk, + const ComputePipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + m_ResourceLayoutIndex.fill(-1); + + ShaderResourceLayoutVk::TShaderStages ShaderStages; + ExtractShaders(CreateInfo, ShaderStages); + + // Memory must be released if an exception is thrown. + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddRequiredSize(GetNumShaderStages() * 2); + MemPool.AddRequiredSize(GetNumShaderStages()); + MemPool.AddRequiredSize(GetNumShaderStages()); + + ValidateAndReserveSpace(CreateInfo, MemPool); + + MemPool.Reserve(); + + m_ShaderResourceLayouts = MemPool.Allocate(GetNumShaderStages() * 2); + m_StaticResCaches = MemPool.Allocate(GetNumShaderStages()); + m_StaticVarsMgrs = MemPool.Allocate(GetNumShaderStages()); + + InitComputePipeline(CreateInfo, MemPool); + InitResourceLayouts(pDeviceVk, CreateInfo, ShaderStages); + + // Create shader modules and initialize shader stages + std::vector VkShaderStages; + std::vector ShaderModules; + InitPipelineShaderStages(pDeviceVk->GetLogicalDevice(), ShaderStages, ShaderModules, VkShaderStages); + + CreateComputePipeline(pDeviceVk, VkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline); + + void* Ptr = MemPool.Release(); + VERIFY_EXPR(Ptr == m_ShaderResourceLayouts); +} + + PipelineStateVkImpl::~PipelineStateVkImpl() { m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask); diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index f6e337c2..ca729479 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -541,7 +541,21 @@ void RenderDeviceVkImpl::TestTextureFormat(TEXTURE_FORMAT TexFormat) IMPLEMENT_QUERY_INTERFACE(RenderDeviceVkImpl, IID_RenderDeviceVk, TRenderDeviceBase) -void RenderDeviceVkImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +void RenderDeviceVkImpl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreateDeviceObject( + "Pipeline State", PSOCreateInfo.PSODesc, ppPipelineState, + [&]() // + { + PipelineStateVkImpl* pPipelineStateVk(NEW_RC_OBJ(m_PSOAllocator, "PipelineStateVkImpl instance", PipelineStateVkImpl)(this, PSOCreateInfo)); + pPipelineStateVk->QueryInterface(IID_PipelineState, reinterpret_cast(ppPipelineState)); + OnCreateDeviceObject(pPipelineStateVk); + } // + ); +} + + +void RenderDeviceVkImpl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) { CreateDeviceObject( "Pipeline State", PSOCreateInfo.PSODesc, ppPipelineState, -- cgit v1.2.3