diff options
| author | azhirnov <zh1dron@gmail.com> | 2020-10-21 22:15:55 +0000 |
|---|---|---|
| committer | azhirnov <zh1dron@gmail.com> | 2020-10-25 10:50:53 +0000 |
| commit | 42217cc1ec7f81c028dcc5c1f845a2fc3b3da497 (patch) | |
| tree | 2efcb7c0fdeae582ecb5c8d13c7bedd593ab9a3c /Graphics | |
| parent | Fixed Mac/iOS build (diff) | |
| parent | Updated Metal testing environment (diff) | |
| download | DiligentCore-42217cc1ec7f81c028dcc5c1f845a2fc3b3da497.tar.gz DiligentCore-42217cc1ec7f81c028dcc5c1f845a2fc3b3da497.zip | |
Merge branch 'master' into ray_tracing
# Conflicts:
# Graphics/GraphicsEngine/interface/PipelineState.h
# Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp
# Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
# Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
Diffstat (limited to 'Graphics')
91 files changed, 3270 insertions, 2119 deletions
diff --git a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp index 00cb22e4..499509fb 100644 --- a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp +++ b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp @@ -771,16 +771,16 @@ const Char* GetUsageString(USAGE Usage) { // clang-format off #define INIT_USGAGE_STR(Usage)UsageStrings[Usage] = #Usage - INIT_USGAGE_STR( USAGE_STATIC ); - INIT_USGAGE_STR( USAGE_DEFAULT ); - INIT_USGAGE_STR( USAGE_DYNAMIC ); - INIT_USGAGE_STR( USAGE_STAGING ); - INIT_USGAGE_STR( USAGE_UNIFIED ); + INIT_USGAGE_STR(USAGE_IMMUTABLE); + INIT_USGAGE_STR(USAGE_DEFAULT); + INIT_USGAGE_STR(USAGE_DYNAMIC); + INIT_USGAGE_STR(USAGE_STAGING); + INIT_USGAGE_STR(USAGE_UNIFIED); #undef INIT_USGAGE_STR // clang-format on bUsageStringsInit = true; } - if (Usage >= USAGE_STATIC && Usage < USAGE_NUM_USAGES) + if (Usage >= USAGE_IMMUTABLE && Usage < USAGE_NUM_USAGES) return UsageStrings[Usage]; else { @@ -797,13 +797,13 @@ const Char* GetResourceDimString(RESOURCE_DIMENSION TexType) { TexTypeStrings[RESOURCE_DIM_UNDEFINED] = "Undefined"; TexTypeStrings[RESOURCE_DIM_BUFFER] = "Buffer"; - TexTypeStrings[RESOURCE_DIM_TEX_1D] = "Tex 1D"; - TexTypeStrings[RESOURCE_DIM_TEX_1D_ARRAY] = "Tex 1D Array"; - TexTypeStrings[RESOURCE_DIM_TEX_2D] = "Tex 2D"; - TexTypeStrings[RESOURCE_DIM_TEX_2D_ARRAY] = "Tex 2D Array"; - TexTypeStrings[RESOURCE_DIM_TEX_3D] = "Tex 3D"; - TexTypeStrings[RESOURCE_DIM_TEX_CUBE] = "Tex Cube"; - TexTypeStrings[RESOURCE_DIM_TEX_CUBE_ARRAY] = "Tex Cube Array"; + TexTypeStrings[RESOURCE_DIM_TEX_1D] = "Texture 1D"; + TexTypeStrings[RESOURCE_DIM_TEX_1D_ARRAY] = "Texture 1D Array"; + TexTypeStrings[RESOURCE_DIM_TEX_2D] = "Texture 2D"; + TexTypeStrings[RESOURCE_DIM_TEX_2D_ARRAY] = "Texture 2D Array"; + TexTypeStrings[RESOURCE_DIM_TEX_3D] = "Texture 3D"; + TexTypeStrings[RESOURCE_DIM_TEX_CUBE] = "Texture Cube"; + TexTypeStrings[RESOURCE_DIM_TEX_CUBE_ARRAY] = "Texture Cube Array"; static_assert(RESOURCE_DIM_NUM_DIMENSIONS == RESOURCE_DIM_TEX_CUBE_ARRAY + 1, "Not all texture type strings initialized."); bTexTypeStrsInit = true; @@ -1337,7 +1337,7 @@ Int32 GetShaderTypePipelineIndex(SHADER_TYPE ShaderType, PIPELINE_TYPE PipelineT { VERIFY(IsConsistentShaderType(ShaderType, PipelineType), "Shader type ", GetShaderTypeLiteralName(ShaderType), " is inconsistent with pipeline type ", GetPipelineTypeString(PipelineType)); - VERIFY(IsPowerOfTwo(Uint32{ShaderType}), "Only single shader stage should be provided"); + VERIFY(IsPowerOfTwo(Uint32{ShaderType}), "More than one shader type is specified"); static_assert(SHADER_TYPE_LAST == SHADER_TYPE_CALLABLE, "Please update the switch below to handle the new shader type"); switch (ShaderType) @@ -1488,7 +1488,8 @@ Uint32 GetStagingTextureLocationOffset(const TextureDesc& TexDesc, // For non-compressed formats, BlockWidth is 1. Offset += (LocationX / FmtAttribs.BlockWidth) * FmtAttribs.GetElementSize(); - // Note: this addressing complies with how Vulkan addresses textures when copying data to/from buffer: + // Note: this addressing complies with how Vulkan (as well as OpenGL/GLES and Metal) address + // textures when copying data to/from buffers: // address of (x,y,z) = bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) } diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt index 3162b6a0..47692deb 100644 --- a/Graphics/GraphicsEngine/CMakeLists.txt +++ b/Graphics/GraphicsEngine/CMakeLists.txt @@ -72,6 +72,7 @@ set(SOURCE src/DefaultShaderSourceStreamFactory.cpp src/EngineMemory.cpp src/FramebufferBase.cpp + src/PipelineStateBase.cpp src/ResourceMappingBase.cpp src/RenderPassBase.cpp src/TextureBase.cpp diff --git a/Graphics/GraphicsEngine/include/BufferBase.hpp b/Graphics/GraphicsEngine/include/BufferBase.hpp index 9ae6db92..605bc2ed 100644 --- a/Graphics/GraphicsEngine/include/BufferBase.hpp +++ b/Graphics/GraphicsEngine/include/BufferBase.hpp @@ -30,12 +30,14 @@ /// \file /// Implementation of the Diligent::BufferBase template class +#include <memory> + #include "Buffer.h" #include "GraphicsTypes.h" #include "DeviceObjectBase.hpp" #include "GraphicsAccessories.hpp" #include "STDAllocator.hpp" -#include <memory> +#include "FormatString.hpp" namespace Diligent { @@ -232,6 +234,9 @@ void BufferBase<BaseInterface, RenderDeviceImplType, BufferViewImplType, TBuffVi { BufferViewDesc ViewDesc; ViewDesc.ViewType = BUFFER_VIEW_UNORDERED_ACCESS; + auto UAVName = FormatString("Default UAV of buffer '", this->m_Desc.Name, '\''); + ViewDesc.Name = UAVName.c_str(); + IBufferView* pUAV = nullptr; CreateViewInternal(ViewDesc, &pUAV, true); m_pDefaultUAV.reset(static_cast<BufferViewImplType*>(pUAV)); @@ -242,6 +247,9 @@ void BufferBase<BaseInterface, RenderDeviceImplType, BufferViewImplType, TBuffVi { BufferViewDesc ViewDesc; ViewDesc.ViewType = BUFFER_VIEW_SHADER_RESOURCE; + auto SRVName = FormatString("Default SRV of buffer '", this->m_Desc.Name, '\''); + ViewDesc.Name = SRVName.c_str(); + IBufferView* pSRV = nullptr; CreateViewInternal(ViewDesc, &pSRV, true); m_pDefaultSRV.reset(static_cast<BufferViewImplType*>(pSRV)); diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index dd8851c7..c16219da 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -1672,6 +1672,13 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: return; } + const auto& PSODesc = m_pPipelineState->GetDesc(); + if (!PSODesc.IsAnyGraphicsPipeline()) + { + LOG_ERROR_MESSAGE("Pipeline state '", PSODesc.Name, "' is not a graphics pipeline"); + return; + } + TEXTURE_FORMAT BoundRTVFormats[8] = {TEX_FORMAT_UNKNOWN}; TEXTURE_FORMAT BoundDSVFormat = TEX_FORMAT_UNKNOWN; @@ -1685,8 +1692,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>:: 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 b54a2f76..1effd32f 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -38,11 +38,16 @@ #include "STDAllocator.hpp" #include "EngineMemory.h" #include "GraphicsAccessories.hpp" -#include "StringPool.hpp" +#include "LinearAllocator.hpp" namespace Diligent { +void ValidateGraphicsPipelineCreateInfo(const GraphicsPipelineStateCreateInfo& CreateInfo) noexcept(false); +void ValidateComputePipelineCreateInfo(const ComputePipelineStateCreateInfo& CreateInfo) noexcept(false); + +void CorrectGraphicsPipelineDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept; + /// Template class implementing base functionality for a pipeline state object. /// \tparam BaseInterface - base interface that this class will inheret @@ -57,298 +62,17 @@ class PipelineStateBase : public DeviceObjectBase<BaseInterface, RenderDeviceImp public: using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, PipelineStateDesc>; - /// \param pRefCounters - reference counters object that controls the lifetime of this PSO - /// \param pDevice - pointer to the device. - /// \param PSODesc - pipeline state description. - /// \param bIsDeviceInternal - flag indicating if the blend state is an internal device object and + /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO + /// \param pDevice - Pointer to the device. + /// \param CreateInfo - Pipeline state create info. + /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and /// must not keep a strong reference to the device. PipelineStateBase(IReferenceCounters* pRefCounters, RenderDeviceImplType* pDevice, const PipelineStateDesc& PSODesc, bool bIsDeviceInternal = false) : - TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal}, - m_NumShaders{0} + TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal} { - ValidateDesc(); - - const auto& SrcLayout = PSODesc.ResourceLayout; - size_t StringPoolSize = 0; - if (SrcLayout.Variables != nullptr) - { - for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) - StringPoolSize += strlen(SrcLayout.Variables[i].Name) + 1; - } - - if (SrcLayout.StaticSamplers != nullptr) - { - for (Uint32 i = 0; i < SrcLayout.NumStaticSamplers; ++i) - StringPoolSize += strlen(SrcLayout.StaticSamplers[i].SamplerOrTextureName) + 1; - } - - if (PSODesc.IsAnyGraphicsPipeline()) - { - CheckAndCorrectBlendStateDesc(); - CheckRasterizerStateDesc(); - CheckAndCorrectDepthStencilDesc(); - - const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout; - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - StringPoolSize += strlen(InputLayout.LayoutElements[i].HLSLSemantic) + 1; - } - else - { - DEV_CHECK_ERR(PSODesc.GraphicsPipeline.InputLayout.NumElements == 0, "Compute pipelines must not have input layout elements"); - } - - 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) - { - VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null"); - Variables[i] = SrcLayout.Variables[i]; - Variables[i].Name = m_StringPool.CopyString(SrcLayout.Variables[i].Name); - } - } - - 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) - { - VERIFY(SrcLayout.StaticSamplers[i].SamplerOrTextureName != nullptr, "Static sampler or texture name can't be null"); -#ifdef DILIGENT_DEVELOPMENT - { - const auto& BorderColor = SrcLayout.StaticSamplers[i].Desc.BorderColor; - 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); - } - } - - - if (this->m_Desc.IsComputePipeline()) - { - const auto& ComputePipeline = PSODesc.ComputePipeline; - if (ComputePipeline.pCS == nullptr) - { - LOG_ERROR_AND_THROW("Compute shader is not provided"); - } - -#define VALIDATE_SHADER_TYPE(Shader, ExpectedType, ShaderName) \ - if (Shader && Shader->GetDesc().ShaderType != ExpectedType) \ - { \ - LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(Shader->GetDesc().ShaderType), " is not a valid type for ", ShaderName, " shader"); \ - } - - VALIDATE_SHADER_TYPE(ComputePipeline.pCS, SHADER_TYPE_COMPUTE, "compute") - - m_pCS = ComputePipeline.pCS; - m_ppShaders[0] = ComputePipeline.pCS; - m_NumShaders = 1; - } - else - { - const auto& GraphicsPipeline = PSODesc.GraphicsPipeline; - - VALIDATE_SHADER_TYPE(GraphicsPipeline.pVS, SHADER_TYPE_VERTEX, "vertex") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pPS, SHADER_TYPE_PIXEL, "pixel") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pGS, SHADER_TYPE_GEOMETRY, "geometry") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pHS, SHADER_TYPE_HULL, "hull") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pDS, SHADER_TYPE_DOMAIN, "domain") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pAS, SHADER_TYPE_AMPLIFICATION, "amplification") - VALIDATE_SHADER_TYPE(GraphicsPipeline.pMS, SHADER_TYPE_MESH, "mesh") -#undef VALIDATE_SHADER_TYPE - - if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) - { - DEV_CHECK_ERR(GraphicsPipeline.pVS, "Vertex shader must be defined"); - DEV_CHECK_ERR(!GraphicsPipeline.pAS && !GraphicsPipeline.pMS, "Mesh shaders are not supported in graphics pipeline"); - m_pVS = GraphicsPipeline.pVS; - m_pPS = GraphicsPipeline.pPS; - m_pGS = GraphicsPipeline.pGS; - m_pDS = GraphicsPipeline.pDS; - m_pHS = GraphicsPipeline.pHS; - } - else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH) - { - DEV_CHECK_ERR(GraphicsPipeline.pMS, "Mesh shader must be defined"); - DEV_CHECK_ERR(!GraphicsPipeline.pVS && !GraphicsPipeline.pGS && !GraphicsPipeline.pDS && !GraphicsPipeline.pHS, - "Vertex, geometry and tessellation shaders are not supported in a mesh pipeline"); - DEV_CHECK_ERR(GraphicsPipeline.InputLayout.NumElements == 0, "Input layout ignored in mesh shader"); - DEV_CHECK_ERR(GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_TRIANGLE_LIST || - GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_UNDEFINED, - "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)"); - m_pAS = GraphicsPipeline.pAS; - m_pMS = GraphicsPipeline.pMS; - m_pPS = GraphicsPipeline.pPS; - } - - if (GraphicsPipeline.pVS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pVS; - if (GraphicsPipeline.pPS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pPS; - if (GraphicsPipeline.pGS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pGS; - if (GraphicsPipeline.pHS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pHS; - if (GraphicsPipeline.pDS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pDS; - if (GraphicsPipeline.pAS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pAS; - if (GraphicsPipeline.pMS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pMS; - - DEV_CHECK_ERR(m_NumShaders > 0, "There must be at least one shader in the Pipeline State"); - - m_pRenderPass = PSODesc.GraphicsPipeline.pRenderPass; - - for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt) - { - auto RTVFmt = GraphicsPipeline.RTVFormats[rt]; - if (RTVFmt != TEX_FORMAT_UNKNOWN) - { - LOG_ERROR_MESSAGE("Render target format (", GetTextureFormatAttribs(RTVFmt).Name, ") of unused slot ", rt, - " must be set to TEX_FORMAT_UNKNOWN"); - } - } - - if (m_pRenderPass) - { - const auto& RPDesc = m_pRenderPass->GetDesc(); - VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount); - const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex]; - - this->m_Desc.GraphicsPipeline.NumRenderTargets = static_cast<Uint8>(Subpass.RenderTargetAttachmentCount); - for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt) - { - const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt]; - if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) - { - VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); - this->m_Desc.GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; - } - } - - if (Subpass.pDepthStencilAttachment != nullptr) - { - const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment; - if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) - { - VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); - this->m_Desc.GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; - } - } - } - - const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout; - LayoutElement* pLayoutElements = nullptr; - if (InputLayout.NumElements > 0) - { - pLayoutElements = ALLOCATE(GetRawAllocator(), "Raw memory for input layout elements", LayoutElement, InputLayout.NumElements); - } - this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements; - for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem) - { - pLayoutElements[Elem] = InputLayout.LayoutElements[Elem]; - pLayoutElements[Elem].HLSLSemantic = m_StringPool.CopyString(InputLayout.LayoutElements[Elem].HLSLSemantic); - } - - - // Correct description and compute offsets and tight strides - std::array<Uint32, MAX_BUFFER_SLOTS> Strides, TightStrides = {}; - // Set all strides to an invalid value because an application may want to use 0 stride - for (auto& Stride : Strides) - Stride = LAYOUT_ELEMENT_AUTO_STRIDE; - - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - { - auto& LayoutElem = pLayoutElements[i]; - - if (LayoutElem.ValueType == VT_FLOAT32 || LayoutElem.ValueType == VT_FLOAT16) - LayoutElem.IsNormalized = false; // Floating point values cannot be normalized - - auto BuffSlot = LayoutElem.BufferSlot; - if (BuffSlot >= Strides.size()) - { - UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds maximum allowed value (", Strides.size() - 1, ")"); - continue; - } - m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, BuffSlot + 1); - - auto& CurrAutoStride = TightStrides[BuffSlot]; - // If offset is not explicitly specified, use current auto stride value - if (LayoutElem.RelativeOffset == LAYOUT_ELEMENT_AUTO_OFFSET) - { - LayoutElem.RelativeOffset = CurrAutoStride; - } - - // If stride is explicitly specified, use it for the current buffer slot - if (LayoutElem.Stride != LAYOUT_ELEMENT_AUTO_STRIDE) - { - // Verify that the value is consistent with the previously specified stride, if any - if (Strides[BuffSlot] != LAYOUT_ELEMENT_AUTO_STRIDE && Strides[BuffSlot] != LayoutElem.Stride) - { - LOG_ERROR_MESSAGE("Inconsistent strides are specified for buffer slot ", BuffSlot, - ". Input element at index ", LayoutElem.InputIndex, " explicitly specifies stride ", - LayoutElem.Stride, ", while current value is ", Strides[BuffSlot], - ". Specify consistent strides or use LAYOUT_ELEMENT_AUTO_STRIDE to allow " - "the engine compute strides automatically."); - } - Strides[BuffSlot] = LayoutElem.Stride; - } - - CurrAutoStride = std::max(CurrAutoStride, LayoutElem.RelativeOffset + LayoutElem.NumComponents * GetValueSize(LayoutElem.ValueType)); - } - - for (Uint32 i = 0; i < InputLayout.NumElements; ++i) - { - auto& LayoutElem = pLayoutElements[i]; - - auto BuffSlot = LayoutElem.BufferSlot; - // If no input elements explicitly specified stride for this buffer slot, use automatic stride - if (Strides[BuffSlot] == LAYOUT_ELEMENT_AUTO_STRIDE) - { - Strides[BuffSlot] = TightStrides[BuffSlot]; - } - else - { - if (Strides[BuffSlot] < TightStrides[BuffSlot]) - { - LOG_ERROR_MESSAGE("Stride ", Strides[BuffSlot], " explicitly specified for slot ", BuffSlot, - " is smaller than the minimum stride ", TightStrides[BuffSlot], - " required to accomodate all input elements."); - } - } - if (LayoutElem.Stride == LAYOUT_ELEMENT_AUTO_STRIDE) - LayoutElem.Stride = Strides[BuffSlot]; - } - - if (m_BufferSlotsUsed > 0) - { - m_pStrides = ALLOCATE(GetRawAllocator(), "Raw memory for buffer strides", Uint32, m_BufferSlotsUsed); - - // Set strides for all unused slots to 0 - for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i) - { - auto Stride = Strides[i]; - m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0; - } - } - } - - 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, @@ -356,6 +80,35 @@ public: this->m_Desc.CommandQueueMask &= DeviceQueuesMask; } + /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO + /// \param pDevice - Pointer to the device. + /// \param GraphicsPipelineCI - Graphics pipeline create information. + /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and + /// must not keep a strong reference to the device. + PipelineStateBase(IReferenceCounters* pRefCounters, + RenderDeviceImplType* pDevice, + const GraphicsPipelineStateCreateInfo& GraphicsPipelineCI, + bool bIsDeviceInternal = false) : + PipelineStateBase{pRefCounters, pDevice, GraphicsPipelineCI.PSODesc, bIsDeviceInternal} + { + ValidateGraphicsPipelineCreateInfo(GraphicsPipelineCI); + } + + /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO + /// \param pDevice - Pointer to the device. + /// \param ComputePipelineCI - Compute pipeline create information. + /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and + /// must not keep a strong reference to the device. + PipelineStateBase(IReferenceCounters* pRefCounters, + RenderDeviceImplType* pDevice, + const ComputePipelineStateCreateInfo& ComputePipelineCI, + bool bIsDeviceInternal = false) : + PipelineStateBase{pRefCounters, pDevice, ComputePipelineCI.PSODesc, bIsDeviceInternal} + { + ValidateComputePipelineCreateInfo(ComputePipelineCI); + } + + ~PipelineStateBase() { /* @@ -375,16 +128,6 @@ public: RasterizerStateRegistry.ReportDeletedObject(); DSSRegistry.ReportDeletedObject(); */ - - auto& RawAllocator = GetRawAllocator(); - if (this->m_Desc.ResourceLayout.Variables != nullptr) - RawAllocator.Free(const_cast<ShaderResourceVariableDesc*>(this->m_Desc.ResourceLayout.Variables)); - if (this->m_Desc.ResourceLayout.StaticSamplers != nullptr) - RawAllocator.Free(const_cast<StaticSamplerDesc*>(this->m_Desc.ResourceLayout.StaticSamplers)); - if (this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements != nullptr) - RawAllocator.Free(const_cast<LayoutElement*>(this->m_Desc.GraphicsPipeline.InputLayout.LayoutElements)); - if (m_pStrides != nullptr) - RawAllocator.Free(m_pStrides); } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineState, TDeviceObjectBase) @@ -399,28 +142,8 @@ public: return m_BufferSlotsUsed; } - IShader* GetVS() { return m_pVS; } - IShader* GetPS() { return m_pPS; } - IShader* GetGS() { return m_pGS; } - IShader* GetDS() { return m_pDS; } - IShader* GetHS() { return m_pHS; } - IShader* GetCS() { return m_pCS; } - - IShader* const* GetShaders() const { return m_ppShaders.data(); } - Uint32 GetNumShaders() const { return m_NumShaders; } - - template <typename ShaderType> - ShaderType* GetShader(Uint32 ShaderInd) - { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return ValidatedCast<ShaderType>(m_ppShaders[ShaderInd]); - } - template <typename ShaderType> - ShaderType* GetShader(Uint32 ShaderInd) const - { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return ValidatedCast<ShaderType>(m_ppShaders[ShaderInd]); - } + SHADER_TYPE GetShaderStageType(Uint32 Stage) const { return m_ShaderStageTypes[Stage]; } + Uint32 GetNumShaderStages() const { return m_NumShaderStages; } // This function only compares shader resource layout hashes, so // it can potentially give false negatives @@ -429,27 +152,12 @@ public: return m_ShaderResourceLayoutHash != ValidatedCast<const PipelineStateBase>(pPSO)->m_ShaderResourceLayoutHash; } -protected: - Uint32 m_BufferSlotsUsed = 0; - Uint32 m_NumShaders = 0; ///< Number of shaders that this PSO uses - Uint32* m_pStrides = nullptr; - - StringPool m_StringPool; - - RefCntAutoPtr<IShader> m_pVS; ///< Strong reference to the vertex shader - RefCntAutoPtr<IShader> m_pPS; ///< Strong reference to the pixel shader - RefCntAutoPtr<IShader> m_pGS; ///< Strong reference to the geometry shader - RefCntAutoPtr<IShader> m_pDS; ///< Strong reference to the domain shader - RefCntAutoPtr<IShader> m_pHS; ///< Strong reference to the hull shader - RefCntAutoPtr<IShader> m_pCS; ///< Strong reference to the compute shader - RefCntAutoPtr<IShader> m_pAS; ///< Strong reference to the amplification shader - RefCntAutoPtr<IShader> m_pMS; ///< Strong reference to the mesh shader - - RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object - - std::array<IShader*, MAX_SHADERS_IN_PIPELINE> m_ppShaders = {}; ///< Array of pointers to the shaders used by this PSO - size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout - + virtual const GraphicsPipelineDesc& DILIGENT_CALL_TYPE GetGraphicsPipelineDesc() const override final + { + VERIFY_EXPR(this->m_Desc.IsAnyGraphicsPipeline()); + VERIFY_EXPR(m_pGraphicsPipelineDesc != nullptr); + return *m_pGraphicsPipelineDesc; + } protected: Int8 GetStaticVariableCountHelper(SHADER_TYPE ShaderType, const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& ResourceLayoutIndex) const @@ -512,143 +220,312 @@ protected: return LayoutInd; } -private: -#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ", GetPipelineTypeString(this->m_Desc.PipelineType), " PSO '", this->m_Desc.Name, "' is invalid: ", ##__VA_ARGS__) - void ValidateDesc() const + void ReserveSpaceForPipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) noexcept { - if (this->m_Desc.IsComputePipeline()) + MemPool.AddSpace<GraphicsPipelineDesc>(); + ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool); + + const auto& InputLayout = CreateInfo.GraphicsPipeline.InputLayout; + MemPool.AddSpace<LayoutElement>(InputLayout.NumElements); + for (Uint32 i = 0; i < InputLayout.NumElements; ++i) { - if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr) + auto& LayoutElem = InputLayout.LayoutElements[i]; + MemPool.AddSpaceForString(LayoutElem.HLSLSemantic); + m_BufferSlotsUsed = std::max(m_BufferSlotsUsed, static_cast<Uint8>(LayoutElem.BufferSlot + 1)); + } + + MemPool.AddSpace<Uint32>(m_BufferSlotsUsed); + } + + void ReserveSpaceForPipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) const noexcept + { + ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool); + } + + + template <typename ShaderImplType, typename TShaderStages> + 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<ShaderImplType>(pShader)); + VERIFY(m_ShaderStageTypes[m_NumShaderStages] == SHADER_TYPE_UNKNOWN, "This shader stage is already initialized."); + m_ShaderStageTypes[m_NumShaderStages++] = ShaderType; + } + }; + + switch (CreateInfo.PSODesc.PipelineType) + { + case PIPELINE_TYPE_GRAPHICS: { - LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null for compute pipelines"); + AddShaderStage(CreateInfo.pVS); + AddShaderStage(CreateInfo.pHS); + AddShaderStage(CreateInfo.pDS); + AddShaderStage(CreateInfo.pGS); + AddShaderStage(CreateInfo.pPS); + VERIFY(CreateInfo.pVS != nullptr, "Vertex shader must not be null"); + break; } + + case PIPELINE_TYPE_MESH: + { + AddShaderStage(CreateInfo.pAS); + AddShaderStage(CreateInfo.pMS); + AddShaderStage(CreateInfo.pPS); + VERIFY(CreateInfo.pMS != nullptr, "Mesh shader must not be null"); + break; + } + + default: + UNEXPECTED("unknown pipeline type"); } - else + + VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); + } + + template <typename ShaderImplType, typename TShaderStages> + 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(); + + VERIFY_EXPR(CreateInfo.PSODesc.PipelineType == PIPELINE_TYPE_COMPUTE); + VERIFY_EXPR(CreateInfo.pCS != nullptr); + VERIFY_EXPR(CreateInfo.pCS->GetDesc().ShaderType == SHADER_TYPE_COMPUTE); + + ShaderStages.emplace_back(SHADER_TYPE_COMPUTE, ValidatedCast<ShaderImplType>(CreateInfo.pCS)); + m_ShaderStageTypes[m_NumShaderStages++] = SHADER_TYPE_COMPUTE; + + VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages); + } + + + void InitializePipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) + { + this->m_pGraphicsPipelineDesc = MemPool.Copy(CreateInfo.GraphicsPipeline); + + auto& GraphicsPipeline = *this->m_pGraphicsPipelineDesc; + CorrectGraphicsPipelineDesc(GraphicsPipeline); + + CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool); + + m_pRenderPass = GraphicsPipeline.pRenderPass; + if (m_pRenderPass) { - const auto& GraphicsPipeline = this->m_Desc.GraphicsPipeline; - if (GraphicsPipeline.pRenderPass != nullptr) + const auto& RPDesc = m_pRenderPass->GetDesc(); + VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount); + const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex]; + + GraphicsPipeline.NumRenderTargets = static_cast<Uint8>(Subpass.RenderTargetAttachmentCount); + for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt) { - if (GraphicsPipeline.NumRenderTargets != 0) - LOG_PSO_ERROR_AND_THROW("NumRenderTargets must be 0 when explicit render pass is used"); - if (GraphicsPipeline.DSVFormat != TEX_FORMAT_UNKNOWN) - LOG_PSO_ERROR_AND_THROW("DSVFormat must be TEX_FORMAT_UNKNOWN when explicit render pass is used"); + const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt]; + if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); + GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; + } + } - for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt) + if (Subpass.pDepthStencilAttachment != nullptr) + { + const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment; + if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) { - if (GraphicsPipeline.RTVFormats[rt] != TEX_FORMAT_UNKNOWN) - LOG_PSO_ERROR_AND_THROW("RTVFormats[", rt, "] must be TEX_FORMAT_UNKNOWN when explicit render pass is used"); + VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); + GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; } + } + } + + const auto& InputLayout = GraphicsPipeline.InputLayout; + LayoutElement* pLayoutElements = MemPool.Allocate<LayoutElement>(InputLayout.NumElements); + for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem) + { + const auto& SrcElem = InputLayout.LayoutElements[Elem]; + pLayoutElements[Elem] = SrcElem; + VERIFY_EXPR(SrcElem.HLSLSemantic != nullptr); + pLayoutElements[Elem].HLSLSemantic = MemPool.CopyString(SrcElem.HLSLSemantic); + } + GraphicsPipeline.InputLayout.LayoutElements = pLayoutElements; + + + // Correct description and compute offsets and tight strides + std::array<Uint32, MAX_BUFFER_SLOTS> Strides, TightStrides = {}; + // Set all strides to an invalid value because an application may want to use 0 stride + for (auto& Stride : Strides) + Stride = LAYOUT_ELEMENT_AUTO_STRIDE; + + for (Uint32 i = 0; i < InputLayout.NumElements; ++i) + { + auto& LayoutElem = pLayoutElements[i]; - const auto& RPDesc = GraphicsPipeline.pRenderPass->GetDesc(); - if (GraphicsPipeline.SubpassIndex >= RPDesc.SubpassCount) - LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") exceeds the number of subpasses (", Uint32{RPDesc.SubpassCount}, ") in render pass '", RPDesc.Name, "'"); + if (LayoutElem.ValueType == VT_FLOAT32 || LayoutElem.ValueType == VT_FLOAT16) + LayoutElem.IsNormalized = false; // Floating point values cannot be normalized + + auto BuffSlot = LayoutElem.BufferSlot; + if (BuffSlot >= Strides.size()) + { + UNEXPECTED("Buffer slot (", BuffSlot, ") exceeds the maximum allowed value (", Strides.size() - 1, ")"); + continue; + } + VERIFY_EXPR(BuffSlot < m_BufferSlotsUsed); + + auto& CurrAutoStride = TightStrides[BuffSlot]; + // If offset is not explicitly specified, use current auto stride value + if (LayoutElem.RelativeOffset == LAYOUT_ELEMENT_AUTO_OFFSET) + { + LayoutElem.RelativeOffset = CurrAutoStride; + } + + // If stride is explicitly specified, use it for the current buffer slot + if (LayoutElem.Stride != LAYOUT_ELEMENT_AUTO_STRIDE) + { + // Verify that the value is consistent with the previously specified stride, if any + if (Strides[BuffSlot] != LAYOUT_ELEMENT_AUTO_STRIDE && Strides[BuffSlot] != LayoutElem.Stride) + { + LOG_ERROR_MESSAGE("Inconsistent strides are specified for buffer slot ", BuffSlot, + ". Input element at index ", LayoutElem.InputIndex, " explicitly specifies stride ", + LayoutElem.Stride, ", while current value is ", Strides[BuffSlot], + ". Specify consistent strides or use LAYOUT_ELEMENT_AUTO_STRIDE to allow " + "the engine compute strides automatically."); + } + Strides[BuffSlot] = LayoutElem.Stride; + } + + CurrAutoStride = std::max(CurrAutoStride, LayoutElem.RelativeOffset + LayoutElem.NumComponents * GetValueSize(LayoutElem.ValueType)); + } + + for (Uint32 i = 0; i < InputLayout.NumElements; ++i) + { + auto& LayoutElem = pLayoutElements[i]; + + auto BuffSlot = LayoutElem.BufferSlot; + // If no input elements explicitly specified stride for this buffer slot, use automatic stride + if (Strides[BuffSlot] == LAYOUT_ELEMENT_AUTO_STRIDE) + { + Strides[BuffSlot] = TightStrides[BuffSlot]; } else { - if (GraphicsPipeline.SubpassIndex != 0) - LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used"); + if (Strides[BuffSlot] < TightStrides[BuffSlot]) + { + LOG_ERROR_MESSAGE("Stride ", Strides[BuffSlot], " explicitly specified for slot ", BuffSlot, + " is smaller than the minimum stride ", TightStrides[BuffSlot], + " required to accomodate all input elements."); + } } + if (LayoutElem.Stride == LAYOUT_ELEMENT_AUTO_STRIDE) + LayoutElem.Stride = Strides[BuffSlot]; + } + + m_pStrides = MemPool.Allocate<Uint32>(m_BufferSlotsUsed); + + // Set strides for all unused slots to 0 + for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i) + { + auto Stride = Strides[i]; + m_pStrides[i] = Stride != LAYOUT_ELEMENT_AUTO_STRIDE ? Stride : 0; } } - void CheckRasterizerStateDesc() const + void InitializePipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo, + LinearAllocator& MemPool) { - const auto& RSDesc = this->m_Desc.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"); + CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool); } - void CheckAndCorrectDepthStencilDesc() +private: + static void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) noexcept { - auto& DSSDesc = this->m_Desc.GraphicsPipeline.DepthStencilDesc; - if (DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN) + if (SrcLayout.Variables != nullptr) { - if (DSSDesc.DepthEnable) - LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN when depth is enabled"); - else - DSSDesc.DepthFunc = DepthStencilStateDesc{}.DepthFunc; + MemPool.AddSpace<ShaderResourceVariableDesc>(SrcLayout.NumVariables); + for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) + { + VERIFY(SrcLayout.Variables[i].Name != nullptr, "Variable name can't be null"); + MemPool.AddSpaceForString(SrcLayout.Variables[i].Name); + } } - auto CheckAndCorrectStencilOpDesc = [&](StencilOpDesc& OpDesc, const char* FaceName) // + if (SrcLayout.ImmutableSamplers != nullptr) { - if (DSSDesc.StencilEnable) - { - if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); - if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilDepthFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); - if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilPassOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); - if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN) - LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFunc must not be COMPARISON_FUNC_UNKNOWN when stencil is enabled"); - } - else + MemPool.AddSpace<ImmutableSamplerDesc>(SrcLayout.NumImmutableSamplers); + for (Uint32 i = 0; i < SrcLayout.NumImmutableSamplers; ++i) { - if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED) - OpDesc.StencilFailOp = StencilOpDesc{}.StencilFailOp; - if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED) - OpDesc.StencilDepthFailOp = StencilOpDesc{}.StencilDepthFailOp; - if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED) - OpDesc.StencilPassOp = StencilOpDesc{}.StencilPassOp; - if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN) - OpDesc.StencilFunc = StencilOpDesc{}.StencilFunc; + VERIFY(SrcLayout.ImmutableSamplers[i].SamplerOrTextureName != nullptr, "Immutable sampler or texture name can't be null"); + MemPool.AddSpaceForString(SrcLayout.ImmutableSamplers[i].SamplerOrTextureName); } - }; - CheckAndCorrectStencilOpDesc(DSSDesc.FrontFace, "FrontFace"); - CheckAndCorrectStencilOpDesc(DSSDesc.BackFace, "BackFace"); + } } - void CheckAndCorrectBlendStateDesc() + static void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) { - auto& BlendDesc = this->m_Desc.GraphicsPipeline.BlendDesc; - for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt) + if (SrcLayout.Variables != nullptr) { - auto& RTDesc = BlendDesc.RenderTargets[rt]; - // clang-format off - const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0)); - const auto LogicOpEnable = RTDesc.LogicOperationEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0)); - // clang-format on - if (BlendEnable) + auto* Variables = MemPool.Allocate<ShaderResourceVariableDesc>(SrcLayout.NumVariables); + DstLayout.Variables = Variables; + for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i) { - if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlend must not be BLEND_FACTOR_UNDEFINED"); - if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlend must not be BLEND_FACTOR_UNDEFINED"); - if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOp must not be BLEND_OPERATION_UNDEFINED"); - - if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED"); - if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED"); - if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED) - LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED"); + const auto& SrcVar = SrcLayout.Variables[i]; + Variables[i] = SrcVar; + Variables[i].Name = MemPool.CopyString(SrcVar.Name); } - else + } + + if (SrcLayout.ImmutableSamplers != nullptr) + { + auto* ImmutableSamplers = MemPool.Allocate<ImmutableSamplerDesc>(SrcLayout.NumImmutableSamplers); + DstLayout.ImmutableSamplers = ImmutableSamplers; + for (Uint32 i = 0; i < SrcLayout.NumImmutableSamplers; ++i) { - if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED) - RTDesc.SrcBlend = RenderTargetBlendDesc{}.SrcBlend; - if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED) - RTDesc.DestBlend = RenderTargetBlendDesc{}.DestBlend; - if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED) - RTDesc.BlendOp = RenderTargetBlendDesc{}.BlendOp; - - if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED) - RTDesc.SrcBlendAlpha = RenderTargetBlendDesc{}.SrcBlendAlpha; - if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED) - RTDesc.DestBlendAlpha = RenderTargetBlendDesc{}.DestBlendAlpha; - if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED) - RTDesc.BlendOpAlpha = RenderTargetBlendDesc{}.BlendOpAlpha; - } + const auto& SrcSmplr = SrcLayout.ImmutableSamplers[i]; +#ifdef DILIGENT_DEVELOPMENT + { + const auto& BorderColor = SrcSmplr.Desc.BorderColor; + if (!((BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 0) || + (BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 1) || + (BorderColor[0] == 1 && BorderColor[1] == 1 && BorderColor[2] == 1 && BorderColor[3] == 1))) + { + LOG_WARNING_MESSAGE("Immutable sampler for variable \"", SrcSmplr.SamplerOrTextureName, "\" specifies border color (", + BorderColor[0], ", ", BorderColor[1], ", ", BorderColor[2], ", ", BorderColor[3], + "). D3D12 static samplers only allow transparent black (0,0,0,0), opaque black (0,0,0,1) or opaque white (1,1,1,1) as border colors"); + } + } +#endif - if (!LogicOpEnable) - RTDesc.LogicOp = RenderTargetBlendDesc{}.LogicOp; + ImmutableSamplers[i] = SrcSmplr; + ImmutableSamplers[i].SamplerOrTextureName = MemPool.CopyString(SrcSmplr.SamplerOrTextureName); + } } } -#undef LOG_PSO_ERROR_AND_THROW + +protected: + size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout + + Uint32* m_pStrides = nullptr; + Uint8 m_BufferSlotsUsed = 0; + + Uint8 m_NumShaderStages = 0; ///< Number of shader stages in this PSO + + /// Array of shader types for every shader stage used by this PSO + std::array<SHADER_TYPE, MAX_SHADERS_IN_PIPELINE> m_ShaderStageTypes = {}; + + RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object + + GraphicsPipelineDesc* m_pGraphicsPipelineDesc = nullptr; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp index 5648e39d..1130fbff 100644 --- a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp @@ -32,6 +32,7 @@ #include <vector> +#include "Atomics.hpp" #include "ShaderResourceVariable.h" #include "PipelineState.h" #include "StringTools.hpp" @@ -114,15 +115,15 @@ inline Uint32 GetAllowedTypeBits(const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVar return AllowedTypeBits; } -inline Int32 FindStaticSampler(const StaticSamplerDesc* StaticSamplers, - Uint32 NumStaticSamplers, - SHADER_TYPE ShaderType, - const char* ResourceName, - const char* SamplerSuffix) +inline Int32 FindImmutableSampler(const ImmutableSamplerDesc* ImtblSamplers, + Uint32 NumImtblSamplers, + SHADER_TYPE ShaderType, + const char* ResourceName, + const char* SamplerSuffix) { - for (Uint32 s = 0; s < NumStaticSamplers; ++s) + for (Uint32 s = 0; s < NumImtblSamplers; ++s) { - const auto& StSam = StaticSamplers[s]; + const auto& StSam = ImtblSamplers[s]; if (((StSam.ShaderStages & ShaderType) != 0) && StreqSuff(ResourceName, StSam.SamplerOrTextureName, SamplerSuffix)) return s; } @@ -214,6 +215,28 @@ inline const char* GetResourceTypeName<BUFFER_VIEW_TYPE>() return "buffer view"; } +inline RESOURCE_DIMENSION GetResourceViewDimension(const ITextureView* pTexView) +{ + VERIFY_EXPR(pTexView != nullptr); + return pTexView->GetDesc().TextureDim; +} + +inline RESOURCE_DIMENSION GetResourceViewDimension(const IBufferView* /*pBuffView*/) +{ + return RESOURCE_DIM_BUFFER; +} + +inline Uint32 GetResourceSampleCount(const ITextureView* pTexView) +{ + VERIFY_EXPR(pTexView != nullptr); + return const_cast<ITextureView*>(pTexView)->GetTexture()->GetDesc().SampleCount; +} + +inline Uint32 GetResourceSampleCount(const IBufferView* /*pBuffView*/) +{ + return 0; +} + template <typename ResourceAttribsType, typename ResourceViewImplType, typename ViewTypeEnumType> @@ -254,8 +277,6 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs, if (!IsExpectedViewType) { - std::string ExpectedViewTypeName; - std::stringstream ss; ss << "Error binding " << ExpectedResourceType << " '" << pViewImpl->GetDesc().Name << "' to variable '" << Attribs.GetPrintName(ArrayIndex) << '\''; @@ -279,11 +300,45 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs, BindingOK = false; } + + const auto ExpectedResourceDim = Attribs.GetResourceDimension(); + if (ExpectedResourceDim != RESOURCE_DIM_UNDEFINED) + { + auto ResourceDim = GetResourceViewDimension(pViewImpl); + if (ResourceDim != ExpectedResourceDim) + { + LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '", + Attribs.GetPrintName(ArrayIndex), "': incorrect resource dimension: ", + GetResourceDimString(ExpectedResourceDim), " is expected, but the actual dimension is ", + GetResourceDimString(ResourceDim)); + + BindingOK = false; + } + + if (ResourceDim == RESOURCE_DIM_TEX_2D || ResourceDim == RESOURCE_DIM_TEX_2D_ARRAY) + { + auto SampleCount = GetResourceSampleCount(pViewImpl); + auto IsMS = Attribs.IsMultisample(); + if (IsMS && SampleCount == 1) + { + LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '", + Attribs.GetPrintName(ArrayIndex), "': multisample texture is expected."); + BindingOK = false; + } + else if (!IsMS && SampleCount > 1) + { + LOG_ERROR_MESSAGE("Error binding ", ExpectedResourceType, " '", pViewImpl->GetDesc().Name, "' to variable '", + Attribs.GetPrintName(ArrayIndex), "': single-sample texture is expected."); + BindingOK = false; + } + } + } } if (VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && pCachedView != nullptr && pCachedView != pViewImpl) { - auto VarTypeStr = GetShaderVariableTypeLiteralName(VarType); + const auto* VarTypeStr = GetShaderVariableTypeLiteralName(VarType); + std::stringstream ss; ss << "Non-null resource '" << pCachedView->GetDesc().Name << "' is already bound to " << VarTypeStr << " shader variable '" << Attribs.GetPrintName(ArrayIndex) << '\''; @@ -305,6 +360,7 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs, BindingOK = false; } + return BindingOK; } @@ -340,7 +396,7 @@ template <typename ResourceLayoutType, struct ShaderVariableBase : public ResourceVariableBaseInterface { ShaderVariableBase(ResourceLayoutType& ParentResLayout) : - m_ParentResLayout(ParentResLayout) + m_ParentResLayout{ParentResLayout} { } diff --git a/Graphics/GraphicsEngine/include/TextureBase.hpp b/Graphics/GraphicsEngine/include/TextureBase.hpp index 1805f7d3..559df1ea 100644 --- a/Graphics/GraphicsEngine/include/TextureBase.hpp +++ b/Graphics/GraphicsEngine/include/TextureBase.hpp @@ -30,13 +30,14 @@ /// \file /// Implementation of the Diligent::TextureBase template class +#include <memory> + #include "Texture.h" #include "GraphicsTypes.h" #include "DeviceObjectBase.hpp" #include "GraphicsAccessories.hpp" #include "STDAllocator.hpp" #include "FormatString.hpp" -#include <memory> namespace Diligent { diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index a7596e3f..0ecbd92b 100644 --- a/Graphics/GraphicsEngine/interface/APIInfo.h +++ b/Graphics/GraphicsEngine/interface/APIInfo.h @@ -30,7 +30,7 @@ /// \file /// Diligent API information -#define DILIGENT_API_VERSION 240074 +#define DILIGENT_API_VERSION 240078 #include "../../../Primitives/interface/BasicTypes.h" @@ -39,64 +39,65 @@ DILIGENT_BEGIN_NAMESPACE(Diligent) /// Diligent API Info. This tructure can be used to verify API compatibility. struct APIInfo { - size_t StructSize DEFAULT_INITIALIZER(0); - int APIVersion DEFAULT_INITIALIZER(0); - size_t RenderTargetBlendDescSize DEFAULT_INITIALIZER(0); - size_t BlendStateDescSize DEFAULT_INITIALIZER(0); - size_t BufferDescSize DEFAULT_INITIALIZER(0); - size_t BufferDataSize DEFAULT_INITIALIZER(0); - size_t BufferFormatSize DEFAULT_INITIALIZER(0); - size_t BufferViewDescSize DEFAULT_INITIALIZER(0); - size_t StencilOpDescSize DEFAULT_INITIALIZER(0); - size_t DepthStencilStateDescSize DEFAULT_INITIALIZER(0); - size_t SamplerCapsSize DEFAULT_INITIALIZER(0); - size_t TextureCapsSize DEFAULT_INITIALIZER(0); - size_t DeviceCapsSize DEFAULT_INITIALIZER(0); - size_t DrawAttribsSize DEFAULT_INITIALIZER(0); - size_t DispatchComputeAttribsSize DEFAULT_INITIALIZER(0); - size_t ViewportSize DEFAULT_INITIALIZER(0); - size_t RectSize DEFAULT_INITIALIZER(0); - size_t CopyTextureAttribsSize DEFAULT_INITIALIZER(0); - size_t DeviceObjectAttribsSize DEFAULT_INITIALIZER(0); - size_t GraphicsAdapterInfoSize DEFAULT_INITIALIZER(0); - size_t DisplayModeAttribsSize DEFAULT_INITIALIZER(0); - size_t SwapChainDescSize DEFAULT_INITIALIZER(0); - size_t FullScreenModeDescSize DEFAULT_INITIALIZER(0); - size_t EngineCreateInfoSize DEFAULT_INITIALIZER(0); - size_t EngineGLCreateInfoSize DEFAULT_INITIALIZER(0); - size_t EngineD3D11CreateInfoSize DEFAULT_INITIALIZER(0); - size_t EngineD3D12CreateInfoSize DEFAULT_INITIALIZER(0); - size_t EngineVkCreateInfoSize DEFAULT_INITIALIZER(0); - size_t EngineMtlCreateInfoSize DEFAULT_INITIALIZER(0); - size_t BoxSize DEFAULT_INITIALIZER(0); - size_t TextureFormatAttribsSize DEFAULT_INITIALIZER(0); - size_t TextureFormatInfoSize DEFAULT_INITIALIZER(0); - size_t TextureFormatInfoExtSize DEFAULT_INITIALIZER(0); - size_t StateTransitionDescSize DEFAULT_INITIALIZER(0); - size_t LayoutElementSize DEFAULT_INITIALIZER(0); - size_t InputLayoutDescSize DEFAULT_INITIALIZER(0); - size_t SampleDescSize DEFAULT_INITIALIZER(0); - size_t ShaderResourceVariableDescSize DEFAULT_INITIALIZER(0); - size_t StaticSamplerDescSize DEFAULT_INITIALIZER(0); - size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0); - size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0); - size_t ComputePipelineDescSize DEFAULT_INITIALIZER(0); - size_t PipelineStateDescSize DEFAULT_INITIALIZER(0); - size_t RasterizerStateDescSize DEFAULT_INITIALIZER(0); - size_t ResourceMappingEntrySize DEFAULT_INITIALIZER(0); - size_t ResourceMappingDescSize DEFAULT_INITIALIZER(0); - size_t SamplerDescSize DEFAULT_INITIALIZER(0); - size_t ShaderDescSize DEFAULT_INITIALIZER(0); - size_t ShaderMacroSize DEFAULT_INITIALIZER(0); - size_t ShaderCreateInfoSize DEFAULT_INITIALIZER(0); - size_t ShaderResourceDescSize DEFAULT_INITIALIZER(0); - size_t DepthStencilClearValueSize DEFAULT_INITIALIZER(0); - size_t OptimizedClearValueSize DEFAULT_INITIALIZER(0); - size_t TextureDescSize DEFAULT_INITIALIZER(0); - size_t TextureSubResDataSize DEFAULT_INITIALIZER(0); - size_t TextureDataSize DEFAULT_INITIALIZER(0); - size_t MappedTextureSubresourceSize DEFAULT_INITIALIZER(0); - size_t TextureViewDescSize DEFAULT_INITIALIZER(0); + size_t StructSize DEFAULT_INITIALIZER(0); + int APIVersion DEFAULT_INITIALIZER(0); + size_t RenderTargetBlendDescSize DEFAULT_INITIALIZER(0); + size_t BlendStateDescSize DEFAULT_INITIALIZER(0); + size_t BufferDescSize DEFAULT_INITIALIZER(0); + size_t BufferDataSize DEFAULT_INITIALIZER(0); + size_t BufferFormatSize DEFAULT_INITIALIZER(0); + size_t BufferViewDescSize DEFAULT_INITIALIZER(0); + size_t StencilOpDescSize DEFAULT_INITIALIZER(0); + size_t DepthStencilStateDescSize DEFAULT_INITIALIZER(0); + size_t SamplerCapsSize DEFAULT_INITIALIZER(0); + size_t TextureCapsSize DEFAULT_INITIALIZER(0); + size_t DeviceCapsSize DEFAULT_INITIALIZER(0); + size_t DrawAttribsSize DEFAULT_INITIALIZER(0); + size_t DispatchComputeAttribsSize DEFAULT_INITIALIZER(0); + size_t ViewportSize DEFAULT_INITIALIZER(0); + size_t RectSize DEFAULT_INITIALIZER(0); + size_t CopyTextureAttribsSize DEFAULT_INITIALIZER(0); + size_t DeviceObjectAttribsSize DEFAULT_INITIALIZER(0); + size_t GraphicsAdapterInfoSize DEFAULT_INITIALIZER(0); + size_t DisplayModeAttribsSize DEFAULT_INITIALIZER(0); + size_t SwapChainDescSize DEFAULT_INITIALIZER(0); + size_t FullScreenModeDescSize DEFAULT_INITIALIZER(0); + size_t EngineCreateInfoSize DEFAULT_INITIALIZER(0); + size_t EngineGLCreateInfoSize DEFAULT_INITIALIZER(0); + size_t EngineD3D11CreateInfoSize DEFAULT_INITIALIZER(0); + size_t EngineD3D12CreateInfoSize DEFAULT_INITIALIZER(0); + size_t EngineVkCreateInfoSize DEFAULT_INITIALIZER(0); + size_t EngineMtlCreateInfoSize DEFAULT_INITIALIZER(0); + size_t BoxSize DEFAULT_INITIALIZER(0); + size_t TextureFormatAttribsSize DEFAULT_INITIALIZER(0); + size_t TextureFormatInfoSize DEFAULT_INITIALIZER(0); + size_t TextureFormatInfoExtSize DEFAULT_INITIALIZER(0); + size_t StateTransitionDescSize DEFAULT_INITIALIZER(0); + size_t LayoutElementSize DEFAULT_INITIALIZER(0); + size_t InputLayoutDescSize DEFAULT_INITIALIZER(0); + size_t SampleDescSize DEFAULT_INITIALIZER(0); + size_t ShaderResourceVariableDescSize DEFAULT_INITIALIZER(0); + size_t ImmutableSamplerDescSize DEFAULT_INITIALIZER(0); + size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0); + size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0); + size_t GraphicsPipelineStateCreateInfoSize DEFAULT_INITIALIZER(0); + size_t ComputePipelineStateCreateInfoSize DEFAULT_INITIALIZER(0); + size_t PipelineStateDescSize DEFAULT_INITIALIZER(0); + size_t RasterizerStateDescSize DEFAULT_INITIALIZER(0); + size_t ResourceMappingEntrySize DEFAULT_INITIALIZER(0); + size_t ResourceMappingDescSize DEFAULT_INITIALIZER(0); + size_t SamplerDescSize DEFAULT_INITIALIZER(0); + size_t ShaderDescSize DEFAULT_INITIALIZER(0); + size_t ShaderMacroSize DEFAULT_INITIALIZER(0); + size_t ShaderCreateInfoSize DEFAULT_INITIALIZER(0); + size_t ShaderResourceDescSize DEFAULT_INITIALIZER(0); + size_t DepthStencilClearValueSize DEFAULT_INITIALIZER(0); + size_t OptimizedClearValueSize DEFAULT_INITIALIZER(0); + size_t TextureDescSize DEFAULT_INITIALIZER(0); + size_t TextureSubResDataSize DEFAULT_INITIALIZER(0); + size_t TextureDataSize DEFAULT_INITIALIZER(0); + size_t MappedTextureSubresourceSize DEFAULT_INITIALIZER(0); + size_t TextureViewDescSize DEFAULT_INITIALIZER(0); }; typedef struct APIInfo APIInfo; diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 56db9e61..85dbcff6 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -105,7 +105,7 @@ DILIGENT_TYPED_ENUM(USAGE, Uint8) /// when it is created, since it cannot be changed after creation. \n /// D3D11 Counterpart: D3D11_USAGE_IMMUTABLE. OpenGL counterpart: GL_STATIC_DRAW /// \remarks Static buffers do not allow CPU access and must use CPU_ACCESS_NONE flag. - USAGE_STATIC = 0, + USAGE_IMMUTABLE = 0, /// A resource that requires read and write access by the GPU and can also be occasionally /// written by the CPU. \n @@ -213,16 +213,16 @@ DEFINE_FLAG_ENUM_OPERATORS(MAP_FLAGS) /// - TextureViewDesc to describe texture view type DILIGENT_TYPED_ENUM(RESOURCE_DIMENSION, Uint8) { - RESOURCE_DIM_UNDEFINED = 0, ///< Texture type undefined - RESOURCE_DIM_BUFFER, ///< Buffer - RESOURCE_DIM_TEX_1D, ///< One-dimensional texture - RESOURCE_DIM_TEX_1D_ARRAY, ///< One-dimensional texture array - RESOURCE_DIM_TEX_2D, ///< Two-dimensional texture - RESOURCE_DIM_TEX_2D_ARRAY, ///< Two-dimensional texture array - RESOURCE_DIM_TEX_3D, ///< Three-dimensional texture - RESOURCE_DIM_TEX_CUBE, ///< Cube-map texture - RESOURCE_DIM_TEX_CUBE_ARRAY, ///< Cube-map array texture - RESOURCE_DIM_NUM_DIMENSIONS ///< Helper value that stores the total number of texture types in the enumeration + RESOURCE_DIM_UNDEFINED = 0, ///< Texture type undefined + RESOURCE_DIM_BUFFER, ///< Buffer + RESOURCE_DIM_TEX_1D, ///< One-dimensional texture + RESOURCE_DIM_TEX_1D_ARRAY, ///< One-dimensional texture array + RESOURCE_DIM_TEX_2D, ///< Two-dimensional texture + RESOURCE_DIM_TEX_2D_ARRAY, ///< Two-dimensional texture array + RESOURCE_DIM_TEX_3D, ///< Three-dimensional texture + RESOURCE_DIM_TEX_CUBE, ///< Cube-map texture + RESOURCE_DIM_TEX_CUBE_ARRAY, ///< Cube-map array texture + RESOURCE_DIM_NUM_DIMENSIONS ///< Helper value that stores the total number of texture types in the enumeration }; /// Texture view type @@ -1517,6 +1517,17 @@ struct DeviceFeatures /// Indicates if device supports separable programs DEVICE_FEATURE_STATE SeparablePrograms DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + /// Indicates if device supports resource queries from shader objects. + + /// \ note This feature indicates if IShader::GetResourceCount() and IShader::GetResourceDesc() methods + /// can be used to query the list of resources of individual shader objects. + /// Shader variable queries from pipeline state and shader resource binding objects are always + /// available. + /// + /// The feature is always enabled in Direct3D11, Direct3D12 and Vulkan. It is enabled in + /// OpenGL when separable programs are available, and it is always disabled in Metal. + DEVICE_FEATURE_STATE ShaderResourceQueries DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + /// Indicates if device supports indirect draw commands DEVICE_FEATURE_STATE IndirectRendering DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); @@ -1621,6 +1632,7 @@ struct DeviceFeatures explicit DeviceFeatures(DEVICE_FEATURE_STATE State) noexcept : SeparablePrograms {State}, + ShaderResourceQueries {State}, IndirectRendering {State}, WireframeFill {State}, MultithreadedResourceCreation {State}, @@ -1653,7 +1665,7 @@ struct DeviceFeatures UniformBuffer8BitAccess {State} { # if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(*this) == 31, "Did you add a new feature to DeviceFeatures? Please handle its status above."); + static_assert(sizeof(*this) == 32, "Did you add a new feature to DeviceFeatures? Please handle its status above."); # endif } #endif @@ -1712,7 +1724,7 @@ struct GraphicsAdapterInfo /// The amount of local video memory that is inaccessible by CPU, in bytes. - /// \note Device-local memory is where USAGE_DEFAULT and USAGE_STATIC resources + /// \note Device-local memory is where USAGE_DEFAULT and USAGE_IMMUTABLE resources /// are typically allocated. /// /// On some devices it may not be possible to query the memory size, @@ -1881,6 +1893,11 @@ struct EngineGLCreateInfo DILIGENT_DERIVE(EngineCreateInfo) /// provide additional runtime checking, validation, and logging /// functionality while possibly incurring performance penalties bool CreateDebugContext DEFAULT_INITIALIZER(false); + + /// Force using non-separable programs. + + /// Setting this to true is typically needed for testing purposes only. + bool ForceNonSeparablePrograms DEFAULT_INITIALIZER(false); }; typedef struct EngineGLCreateInfo EngineGLCreateInfo; 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 2ea0d224..f953b851 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -96,32 +96,36 @@ struct ShaderResourceVariableDesc typedef struct ShaderResourceVariableDesc ShaderResourceVariableDesc; -/// Static sampler description -struct StaticSamplerDesc +/// Immutable sampler description. + +/// An immutable sampler is compiled into the pipeline state and can't be changed. +/// It is generally more efficient than a regular sampler and should be used +/// whenever possible. +struct ImmutableSamplerDesc { - /// Shader stages that this static sampler applies to. More than one shader stage can be specified. + /// Shader stages that this immutable sampler applies to. More than one shader stage can be specified. SHADER_TYPE ShaderStages DEFAULT_INITIALIZER(SHADER_TYPE_UNKNOWN); /// The name of the sampler itself or the name of the texture variable that - /// this static sampler is assigned to if combined texture samplers are used. + /// this immutable sampler is assigned to if combined texture samplers are used. const Char* SamplerOrTextureName DEFAULT_INITIALIZER(nullptr); /// Sampler description struct SamplerDesc Desc; #if DILIGENT_CPP_INTERFACE - StaticSamplerDesc()noexcept{} + ImmutableSamplerDesc()noexcept{} - StaticSamplerDesc(SHADER_TYPE _ShaderStages, - const Char* _SamplerOrTextureName, - const SamplerDesc& _Desc)noexcept : + ImmutableSamplerDesc(SHADER_TYPE _ShaderStages, + const Char* _SamplerOrTextureName, + const SamplerDesc& _Desc)noexcept : ShaderStages {_ShaderStages }, SamplerOrTextureName{_SamplerOrTextureName}, Desc {_Desc } {} #endif }; -typedef struct StaticSamplerDesc StaticSamplerDesc; +typedef struct ImmutableSamplerDesc ImmutableSamplerDesc; /// Pipeline layout description struct PipelineResourceLayoutDesc @@ -129,19 +133,19 @@ struct PipelineResourceLayoutDesc /// Default shader resource variable type. This type will be used if shader /// variable description is not found in the Variables array /// or if Variables == nullptr - SHADER_RESOURCE_VARIABLE_TYPE DefaultVariableType DEFAULT_INITIALIZER(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + SHADER_RESOURCE_VARIABLE_TYPE DefaultVariableType DEFAULT_INITIALIZER(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); /// Number of elements in Variables array - Uint32 NumVariables DEFAULT_INITIALIZER(0); + Uint32 NumVariables DEFAULT_INITIALIZER(0); /// Array of shader resource variable descriptions - const ShaderResourceVariableDesc* Variables DEFAULT_INITIALIZER(nullptr); + const ShaderResourceVariableDesc* Variables DEFAULT_INITIALIZER(nullptr); - /// Number of static samplers in StaticSamplers array - Uint32 NumStaticSamplers DEFAULT_INITIALIZER(0); + /// Number of immutable samplers in ImmutableSamplers array + Uint32 NumImmutableSamplers DEFAULT_INITIALIZER(0); - /// Array of static sampler descriptions - const StaticSamplerDesc* StaticSamplers DEFAULT_INITIALIZER(nullptr); + /// Array of immutable sampler descriptions + const ImmutableSamplerDesc* ImmutableSamplers DEFAULT_INITIALIZER(nullptr); }; typedef struct PipelineResourceLayoutDesc PipelineResourceLayoutDesc; @@ -151,29 +155,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; @@ -348,19 +329,9 @@ 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; - - // TODO (AZ): use pointer - /// Ray tracing pipeline state description. This memeber is ignored if PipelineType is not PIPELINE_TYPE_RAY_TRACING. - RayTracingPipelineDesc RayTracingPipeline; - #if DILIGENT_CPP_INTERFACE bool IsAnyGraphicsPipeline() const { return PipelineType == PIPELINE_TYPE_GRAPHICS || PipelineType == PIPELINE_TYPE_MESH; } - bool IsComputePipeline () const { return PipelineType == PIPELINE_TYPE_COMPUTE; } + bool IsComputePipeline() const { return PipelineType == PIPELINE_TYPE_COMPUTE; } #endif }; typedef struct PipelineStateDesc PipelineStateDesc; @@ -370,7 +341,7 @@ typedef struct PipelineStateDesc PipelineStateDesc; DILIGENT_TYPED_ENUM(PSO_CREATE_FLAGS, Uint32) { /// Null flag. - PSO_CREATE_FLAG_NONE = 0x00, + PSO_CREATE_FLAG_NONE = 0x00, /// Ignore missing variables. @@ -378,15 +349,15 @@ DILIGENT_TYPED_ENUM(PSO_CREATE_FLAGS, Uint32) /// provided as part of the pipeline resource layout description /// that is not found in any of the designated shader stages. /// Use this flag to silence these warnings. - PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES = 0x01, + PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES = 0x01, - /// Ignore missing static samplers. + /// Ignore missing immutable samplers. - /// By default, the engine outputs a warning for every static sampler + /// By default, the engine outputs a warning for every immutable sampler /// provided as part of the pipeline resource layout description /// that is not found in any of the designated shader stages. /// Use this flag to silence these warnings. - PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS = 0x02, + PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS = 0x02, }; DEFINE_FLAG_ENUM_OPERATORS(PSO_CREATE_FLAGS); @@ -398,10 +369,57 @@ 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); + +#if DILIGENT_CPP_INTERFACE + ComputePipelineStateCreateInfo() noexcept + { + PSODesc.PipelineType = PIPELINE_TYPE_COMPUTE; + } +#endif +}; +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}}; @@ -419,10 +437,13 @@ 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. + /// This method must only be called for a graphics or mesh pipeline. + VIRTUAL const GraphicsPipelineDesc REF METHOD(GetGraphicsPipelineDesc)(THIS) CONST PURE; /// Binds resources for all shaders in the pipeline state @@ -512,6 +533,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 027d0f5c..19d98a94 100644 --- a/Graphics/GraphicsEngine/interface/RenderDevice.h +++ b/Graphics/GraphicsEngine/interface/RenderDevice.h @@ -78,7 +78,7 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) /// \param [in] BuffDesc - Buffer description, see Diligent::BufferDesc for details. /// \param [in] pBuffData - Pointer to Diligent::BufferData structure that describes /// initial buffer data or nullptr if no data is provided. - /// Static buffers (USAGE_STATIC) must be initialized at creation time. + /// Immutable buffers (USAGE_IMMUTABLE) must be initialized at creation time. /// \param [out] ppBuffer - Address of the memory location where the pointer to the /// buffer interface will be stored. The function calls AddRef(), /// so that the new buffer will contain one reference and must be @@ -109,7 +109,7 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) /// \param [in] TexDesc - Texture description, see Diligent::TextureDesc for details. /// \param [in] pData - Pointer to Diligent::TextureData structure that describes /// initial texture data or nullptr if no data is provided. - /// Static textures (USAGE_STATIC) must be initialized at creation time. + /// Immutable textures (USAGE_IMMUTABLE) must be initialized at creation time. /// /// \param [out] ppTexture - Address of the memory location where the pointer to the /// texture interface will be stored. @@ -156,17 +156,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 - Graphics pipeline state create info, see Diligent::GraphicsPipelineStateCreateInfo for details. /// \param [out] ppPipelineState - Address of the memory location where the pointer to the /// pipeline state interface will be stored. /// The function calls AddRef(), so that the new object will contain /// 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 - Compute pipeline state create info, see Diligent::ComputePipelineStateCreateInfo for details. + /// \param [out] ppPipelineState - Address of the memory location where the pointer to the + /// pipeline state interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + VIRTUAL void METHOD(CreateComputePipelineState)(THIS_ + const ComputePipelineStateCreateInfo REF PSOCreateInfo, + IPipelineState** ppPipelineState) PURE; /// Creates a new fence object @@ -312,20 +322,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/interface/Shader.h b/Graphics/GraphicsEngine/interface/Shader.h index 03dc06f0..950ecc77 100644 --- a/Graphics/GraphicsEngine/interface/Shader.h +++ b/Graphics/GraphicsEngine/interface/Shader.h @@ -352,7 +352,9 @@ DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8) SHADER_RESOURCE_TYPE_SAMPLER, /// Input attachment in a render pass - SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT + SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT, + + SHADER_RESOURCE_TYPE_LAST = SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT }; // clang-format on diff --git a/Graphics/GraphicsEngine/src/APIInfo.cpp b/Graphics/GraphicsEngine/src/APIInfo.cpp index f71b943e..e4111327 100644 --- a/Graphics/GraphicsEngine/src/APIInfo.cpp +++ b/Graphics/GraphicsEngine/src/APIInfo.cpp @@ -87,10 +87,11 @@ static APIInfo InitAPIInfo() INIT_STRUCTURE_SIZE(InputLayoutDesc); INIT_STRUCTURE_SIZE(SampleDesc); INIT_STRUCTURE_SIZE(ShaderResourceVariableDesc); - INIT_STRUCTURE_SIZE(StaticSamplerDesc); + INIT_STRUCTURE_SIZE(ImmutableSamplerDesc); INIT_STRUCTURE_SIZE(PipelineResourceLayoutDesc); INIT_STRUCTURE_SIZE(GraphicsPipelineDesc); - INIT_STRUCTURE_SIZE(ComputePipelineDesc); + INIT_STRUCTURE_SIZE(GraphicsPipelineStateCreateInfo); + INIT_STRUCTURE_SIZE(ComputePipelineStateCreateInfo); INIT_STRUCTURE_SIZE(PipelineStateDesc); INIT_STRUCTURE_SIZE(RasterizerStateDesc); INIT_STRUCTURE_SIZE(ResourceMappingEntry); diff --git a/Graphics/GraphicsEngine/src/BufferBase.cpp b/Graphics/GraphicsEngine/src/BufferBase.cpp index c42fd698..aab770fd 100644 --- a/Graphics/GraphicsEngine/src/BufferBase.cpp +++ b/Graphics/GraphicsEngine/src/BufferBase.cpp @@ -74,7 +74,7 @@ void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps) switch (Desc.Usage) { - case USAGE_STATIC: + case USAGE_IMMUTABLE: case USAGE_DEFAULT: VERIFY_BUFFER(Desc.CPUAccessFlags == CPU_ACCESS_NONE, "static and default buffers can't have any CPU access flags set."); break; @@ -117,8 +117,8 @@ void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps) void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData) { - if (Desc.Usage == USAGE_STATIC && (pBuffData == nullptr || pBuffData->pData == nullptr)) - LOG_BUFFER_ERROR_AND_THROW("initial data must not be null as static buffers must be initialized at creation time."); + if (Desc.Usage == USAGE_IMMUTABLE && (pBuffData == nullptr || pBuffData->pData == nullptr)) + LOG_BUFFER_ERROR_AND_THROW("initial data must not be null as immutable buffers must be initialized at creation time."); if (Desc.Usage == USAGE_DYNAMIC && pBuffData != nullptr && pBuffData->pData != nullptr) LOG_BUFFER_ERROR_AND_THROW("initial data must be null for dynamic buffers."); diff --git a/Graphics/GraphicsEngine/src/PipelineStateBase.cpp b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp new file mode 100644 index 00000000..fedc332d --- /dev/null +++ b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp @@ -0,0 +1,260 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "PipelineStateBase.hpp" + +namespace Diligent +{ + +#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ", GetPipelineTypeString(PSODesc.PipelineType), " PSO '", PSODesc.Name, "' is invalid: ", ##__VA_ARGS__) + +namespace +{ + +void ValidateRasterizerStateDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false) +{ + const auto& RSDesc = GraphicsPipeline.RasterizerDesc; + if (RSDesc.FillMode == FILL_MODE_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED"); + if (RSDesc.CullMode == CULL_MODE_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED"); +} + +void ValidateDepthStencilDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false) +{ + const auto& DSSDesc = GraphicsPipeline.DepthStencilDesc; + if (DSSDesc.DepthEnable && DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN) + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN when depth is enabled"); + + auto CheckStencilOpDesc = [&](const StencilOpDesc& OpDesc, const char* FaceName) // + { + if (DSSDesc.StencilEnable) + { + if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); + if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilDepthFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); + if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilPassOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); + if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN) + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFunc must not be COMPARISON_FUNC_UNKNOWN when stencil is enabled"); + } + }; + CheckStencilOpDesc(DSSDesc.FrontFace, "FrontFace"); + CheckStencilOpDesc(DSSDesc.BackFace, "BackFace"); +} + +void CorrectDepthStencilDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept +{ + auto& DSSDesc = GraphicsPipeline.DepthStencilDesc; + if (!DSSDesc.DepthEnable && DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN) + DSSDesc.DepthFunc = DepthStencilStateDesc{}.DepthFunc; + + auto CorrectStencilOpDesc = [&](StencilOpDesc& OpDesc) // + { + if (!DSSDesc.StencilEnable) + { + if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED) + OpDesc.StencilFailOp = StencilOpDesc{}.StencilFailOp; + if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED) + OpDesc.StencilDepthFailOp = StencilOpDesc{}.StencilDepthFailOp; + if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED) + OpDesc.StencilPassOp = StencilOpDesc{}.StencilPassOp; + if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN) + OpDesc.StencilFunc = StencilOpDesc{}.StencilFunc; + } + }; + CorrectStencilOpDesc(DSSDesc.FrontFace); + CorrectStencilOpDesc(DSSDesc.BackFace); +} + +void ValidateBlendStateDesc(const PipelineStateDesc& PSODesc, const GraphicsPipelineDesc& GraphicsPipeline) noexcept(false) +{ + const auto& BlendDesc = GraphicsPipeline.BlendDesc; + for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt) + { + auto& RTDesc = BlendDesc.RenderTargets[rt]; + + const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0)); + if (BlendEnable) + { + if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlend must not be BLEND_FACTOR_UNDEFINED"); + if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlend must not be BLEND_FACTOR_UNDEFINED"); + if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOp must not be BLEND_OPERATION_UNDEFINED"); + + if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED"); + if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED"); + if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED) + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED"); + } + } +} + +void CorrectBlendStateDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept +{ + auto& BlendDesc = GraphicsPipeline.BlendDesc; + for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt) + { + auto& RTDesc = BlendDesc.RenderTargets[rt]; + // clang-format off + const auto BlendEnable = RTDesc.BlendEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0)); + const auto LogicOpEnable = RTDesc.LogicOperationEnable && (rt == 0 || (BlendDesc.IndependentBlendEnable && rt > 0)); + // clang-format on + if (!BlendEnable) + { + if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED) + RTDesc.SrcBlend = RenderTargetBlendDesc{}.SrcBlend; + if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED) + RTDesc.DestBlend = RenderTargetBlendDesc{}.DestBlend; + if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED) + RTDesc.BlendOp = RenderTargetBlendDesc{}.BlendOp; + + if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED) + RTDesc.SrcBlendAlpha = RenderTargetBlendDesc{}.SrcBlendAlpha; + if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED) + RTDesc.DestBlendAlpha = RenderTargetBlendDesc{}.DestBlendAlpha; + if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED) + RTDesc.BlendOpAlpha = RenderTargetBlendDesc{}.BlendOpAlpha; + } + + if (!LogicOpEnable) + RTDesc.LogicOp = RenderTargetBlendDesc{}.LogicOp; + } +} + +} // namespace + +#define VALIDATE_SHADER_TYPE(Shader, ExpectedType, ShaderName) \ + if (Shader != nullptr && Shader->GetDesc().ShaderType != ExpectedType) \ + { \ + LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(Shader->GetDesc().ShaderType), " is not a valid type for ", ShaderName, " shader"); \ + } + +void ValidateGraphicsPipelineCreateInfo(const GraphicsPipelineStateCreateInfo& CreateInfo) noexcept(false) +{ + const auto& PSODesc = CreateInfo.PSODesc; + if (PSODesc.PipelineType != PIPELINE_TYPE_GRAPHICS && PSODesc.PipelineType != PIPELINE_TYPE_MESH) + LOG_PSO_ERROR_AND_THROW("Pipeline type must be GRAPHICS or MESH"); + + const auto& GraphicsPipeline = CreateInfo.GraphicsPipeline; + + ValidateBlendStateDesc(PSODesc, GraphicsPipeline); + ValidateRasterizerStateDesc(PSODesc, GraphicsPipeline); + ValidateDepthStencilDesc(PSODesc, GraphicsPipeline); + + + if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) + { + if (CreateInfo.pVS == nullptr) + LOG_ERROR_AND_THROW("Vertex shader must not be null"); + + DEV_CHECK_ERR(CreateInfo.pAS == nullptr && CreateInfo.pMS == nullptr, "Mesh shaders are not supported in graphics pipeline"); + } + else if (PSODesc.PipelineType == PIPELINE_TYPE_MESH) + { + if (CreateInfo.pMS == nullptr) + LOG_ERROR_AND_THROW("Mesh shader must not be null"); + + DEV_CHECK_ERR(CreateInfo.pVS == nullptr && CreateInfo.pGS == nullptr && CreateInfo.pDS == nullptr && CreateInfo.pHS == nullptr, + "Vertex, geometry and tessellation shaders are not supported in a mesh pipeline"); + DEV_CHECK_ERR(GraphicsPipeline.InputLayout.NumElements == 0, "Input layout is ignored in a mesh pipeline"); + DEV_CHECK_ERR(GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_TRIANGLE_LIST || + GraphicsPipeline.PrimitiveTopology == PRIMITIVE_TOPOLOGY_UNDEFINED, + "Primitive topology is ignored in a mesh pipeline, set it to undefined or keep default value (triangle list)"); + } + + + VALIDATE_SHADER_TYPE(CreateInfo.pVS, SHADER_TYPE_VERTEX, "vertex") + VALIDATE_SHADER_TYPE(CreateInfo.pPS, SHADER_TYPE_PIXEL, "pixel") + VALIDATE_SHADER_TYPE(CreateInfo.pGS, SHADER_TYPE_GEOMETRY, "geometry") + VALIDATE_SHADER_TYPE(CreateInfo.pHS, SHADER_TYPE_HULL, "hull") + VALIDATE_SHADER_TYPE(CreateInfo.pDS, SHADER_TYPE_DOMAIN, "domain") + VALIDATE_SHADER_TYPE(CreateInfo.pAS, SHADER_TYPE_AMPLIFICATION, "amplification") + VALIDATE_SHADER_TYPE(CreateInfo.pMS, SHADER_TYPE_MESH, "mesh") + + + if (GraphicsPipeline.pRenderPass != nullptr) + { + if (GraphicsPipeline.NumRenderTargets != 0) + LOG_PSO_ERROR_AND_THROW("NumRenderTargets must be 0 when explicit render pass is used"); + if (GraphicsPipeline.DSVFormat != TEX_FORMAT_UNKNOWN) + LOG_PSO_ERROR_AND_THROW("DSVFormat must be TEX_FORMAT_UNKNOWN when explicit render pass is used"); + + for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt) + { + if (GraphicsPipeline.RTVFormats[rt] != TEX_FORMAT_UNKNOWN) + LOG_PSO_ERROR_AND_THROW("RTVFormats[", rt, "] must be TEX_FORMAT_UNKNOWN when explicit render pass is used"); + } + + const auto& RPDesc = GraphicsPipeline.pRenderPass->GetDesc(); + if (GraphicsPipeline.SubpassIndex >= RPDesc.SubpassCount) + LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") exceeds the number of subpasses (", Uint32{RPDesc.SubpassCount}, ") in render pass '", RPDesc.Name, "'"); + } + else + { + for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt) + { + auto RTVFmt = GraphicsPipeline.RTVFormats[rt]; + if (RTVFmt != TEX_FORMAT_UNKNOWN) + { + LOG_ERROR_MESSAGE("Render target format (", GetTextureFormatAttribs(RTVFmt).Name, ") of unused slot ", rt, + " must be set to TEX_FORMAT_UNKNOWN"); + } + } + + if (GraphicsPipeline.SubpassIndex != 0) + LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used"); + } +} + +void ValidateComputePipelineCreateInfo(const ComputePipelineStateCreateInfo& CreateInfo) noexcept(false) +{ + const auto& PSODesc = CreateInfo.PSODesc; + if (PSODesc.PipelineType != PIPELINE_TYPE_COMPUTE) + LOG_PSO_ERROR_AND_THROW("Pipeline type must be COMPUTE"); + + if (CreateInfo.pCS == nullptr) + LOG_ERROR_AND_THROW("Compute shader must not be null"); + + VALIDATE_SHADER_TYPE(CreateInfo.pCS, SHADER_TYPE_COMPUTE, "compute"); +} +#undef VALIDATE_SHADER_TYPE +#undef LOG_PSO_ERROR_AND_THROW + +void CorrectGraphicsPipelineDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept +{ + CorrectBlendStateDesc(GraphicsPipeline); + CorrectDepthStencilDesc(GraphicsPipeline); +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D11/include/D3D11TypeConversions.hpp b/Graphics/GraphicsEngineD3D11/include/D3D11TypeConversions.hpp index 5a87cfd7..96de94f9 100644 --- a/Graphics/GraphicsEngineD3D11/include/D3D11TypeConversions.hpp +++ b/Graphics/GraphicsEngineD3D11/include/D3D11TypeConversions.hpp @@ -79,7 +79,7 @@ inline D3D11_USAGE UsageToD3D11Usage(USAGE Usage) switch (Usage) { // clang-format off - case USAGE_STATIC: return D3D11_USAGE_IMMUTABLE; + case USAGE_IMMUTABLE: return D3D11_USAGE_IMMUTABLE; case USAGE_DEFAULT: return D3D11_USAGE_DEFAULT; case USAGE_DYNAMIC: return D3D11_USAGE_DYNAMIC; case USAGE_STAGING: return D3D11_USAGE_STAGING; @@ -93,7 +93,7 @@ inline USAGE D3D11UsageToUsage(D3D11_USAGE D3D11Usage) switch (D3D11Usage) { // clang-format off - case D3D11_USAGE_IMMUTABLE: return USAGE_STATIC; + case D3D11_USAGE_IMMUTABLE: return USAGE_IMMUTABLE; case D3D11_USAGE_DEFAULT: return USAGE_DEFAULT; case D3D11_USAGE_DYNAMIC: return USAGE_DYNAMIC; case D3D11_USAGE_STAGING: return USAGE_STAGING; diff --git a/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp index 02f922a6..520e9bb0 100644 --- a/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/PipelineStateD3D11Impl.hpp @@ -36,6 +36,7 @@ #include "ShaderResourceLayoutD3D11.hpp" #include "SRBMemoryAllocator.hpp" #include "RenderDeviceD3D11Impl.hpp" +#include "ShaderD3D11Impl.hpp" namespace Diligent { @@ -48,9 +49,12 @@ class PipelineStateD3D11Impl final : public PipelineStateBase<IPipelineStateD3D1 public: using TPipelineStateBase = PipelineStateBase<IPipelineStateD3D11, RenderDeviceD3D11Impl>; - 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; @@ -117,27 +121,45 @@ public: const ShaderResourceLayoutD3D11& GetStaticResourceLayout(Uint32 s) const { - VERIFY_EXPR(s < m_NumShaders); + VERIFY_EXPR(s < GetNumShaderStages()); return m_pStaticResourceLayouts[s]; } ShaderResourceCacheD3D11& GetStaticResourceCache(Uint32 s) { - VERIFY_EXPR(s < m_NumShaders); + VERIFY_EXPR(s < GetNumShaderStages()); return m_pStaticResourceCaches[s]; } - void SetStaticSamplers(ShaderResourceCacheD3D11& ResourceCache, Uint32 ShaderInd) const; + const ShaderD3D11Impl* GetShaderByType(SHADER_TYPE ShaderType) const; + const ShaderD3D11Impl* GetShader(Uint32 Index) const; + + void SetImmutableSamplers(ShaderResourceCacheD3D11& ResourceCache, Uint32 ShaderInd) const; private: + template <typename PSOCreateInfoType> + void InitInternalObjects(const PSOCreateInfoType& CreateInfo); + + void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + const std::vector<std::pair<SHADER_TYPE, ShaderD3D11Impl*>>& ShaderStages); + + void Destruct(); + CComPtr<ID3D11BlendState> m_pd3d11BlendState; CComPtr<ID3D11RasterizerState> m_pd3d11RasterizerState; CComPtr<ID3D11DepthStencilState> m_pd3d11DepthStencilState; CComPtr<ID3D11InputLayout> m_pd3d11InputLayout; + RefCntAutoPtr<ShaderD3D11Impl> m_pVS; + RefCntAutoPtr<ShaderD3D11Impl> m_pPS; + RefCntAutoPtr<ShaderD3D11Impl> m_pGS; + RefCntAutoPtr<ShaderD3D11Impl> m_pDS; + RefCntAutoPtr<ShaderD3D11Impl> m_pHS; + RefCntAutoPtr<ShaderD3D11Impl> m_pCS; + // The caches are indexed by the shader order in the PSO, not shader index - ShaderResourceCacheD3D11* m_pStaticResourceCaches = nullptr; - ShaderResourceLayoutD3D11* m_pStaticResourceLayouts = nullptr; + 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; @@ -146,20 +168,20 @@ private: // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; - std::array<Uint16, MAX_SHADERS_IN_PIPELINE + 1> m_StaticSamplerOffsets = {}; - struct StaticSamplerInfo + std::array<Uint16, MAX_SHADERS_IN_PIPELINE + 1> m_ImmutableSamplerOffsets = {}; + struct ImmutableSamplerInfo { const D3DShaderResourceAttribs& Attribs; RefCntAutoPtr<ISampler> pSampler; - StaticSamplerInfo(const D3DShaderResourceAttribs& _Attribs, - RefCntAutoPtr<ISampler> _pSampler) : + ImmutableSamplerInfo(const D3DShaderResourceAttribs& _Attribs, + RefCntAutoPtr<ISampler> _pSampler) : // clang-format off Attribs {_Attribs}, pSampler {std::move(_pSampler)} // clang-format on {} }; - std::vector<StaticSamplerInfo, STDAllocatorRawMem<StaticSamplerInfo>> m_StaticSamplers; + std::vector<ImmutableSamplerInfo, STDAllocatorRawMem<ImmutableSamplerInfo>> m_ImmutableSamplers; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D11/include/RenderDeviceD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/RenderDeviceD3D11Impl.hpp index 2d279b86..8565935d 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, @@ -132,6 +136,9 @@ public: Uint64 GetCommandQueueMask() const { return Uint64{1}; } private: + template <typename PSOCreateInfoType> + void CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState); + virtual void TestTextureFormat(TEXTURE_FORMAT TexFormat) override final; EngineD3D11CreateInfo m_EngineAttribs; diff --git a/Graphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.hpp index eb97dfdc..21437e0f 100644 --- a/Graphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/ShaderResourceBindingD3D11Impl.hpp @@ -100,6 +100,8 @@ public: } private: + void Destruct(); + // The caches are indexed by the shader order in the PSO, not shader index ShaderResourceCacheD3D11* m_pBoundResourceCaches = nullptr; ShaderResourceLayoutD3D11* m_pResourceLayouts = nullptr; diff --git a/Graphics/GraphicsEngineD3D11/include/ShaderResourceCacheD3D11.hpp b/Graphics/GraphicsEngineD3D11/include/ShaderResourceCacheD3D11.hpp index dc70eec1..7aa7126d 100644 --- a/Graphics/GraphicsEngineD3D11/include/ShaderResourceCacheD3D11.hpp +++ b/Graphics/GraphicsEngineD3D11/include/ShaderResourceCacheD3D11.hpp @@ -51,7 +51,7 @@ namespace Diligent class ShaderResourceCacheD3D11 { public: - ShaderResourceCacheD3D11() + ShaderResourceCacheD3D11() noexcept {} ~ShaderResourceCacheD3D11(); diff --git a/Graphics/GraphicsEngineD3D11/include/ShaderResourceLayoutD3D11.hpp b/Graphics/GraphicsEngineD3D11/include/ShaderResourceLayoutD3D11.hpp index 4b4d13b2..9b2c2d9b 100644 --- a/Graphics/GraphicsEngineD3D11/include/ShaderResourceLayoutD3D11.hpp +++ b/Graphics/GraphicsEngineD3D11/include/ShaderResourceLayoutD3D11.hpp @@ -47,14 +47,19 @@ namespace Diligent class ShaderResourceLayoutD3D11 { public: - ShaderResourceLayoutD3D11(IObject& Owner, - std::shared_ptr<const ShaderResourcesD3D11> pSrcResources, - const PipelineResourceLayoutDesc& ResourceLayout, - const SHADER_RESOURCE_VARIABLE_TYPE* VarTypes, - Uint32 NumVarTypes, - ShaderResourceCacheD3D11& ResourceCache, - IMemoryAllocator& ResCacheDataAllocator, - IMemoryAllocator& ResLayoutDataAllocator); + ShaderResourceLayoutD3D11(IObject& Owner, + ShaderResourceCacheD3D11& ResourceCache) noexcept : + m_Owner{Owner}, + m_ResourceCache{ResourceCache} + { + } + + void Initialize(std::shared_ptr<const ShaderResourcesD3D11> pSrcResources, + const PipelineResourceLayoutDesc& ResourceLayout, + const SHADER_RESOURCE_VARIABLE_TYPE* VarTypes, + Uint32 NumVarTypes, + IMemoryAllocator& ResCacheDataAllocator, + IMemoryAllocator& ResLayoutDataAllocator); ~ShaderResourceLayoutD3D11(); // clang-format off @@ -68,7 +73,7 @@ public: static size_t GetRequiredMemorySize(const ShaderResourcesD3D11& SrcResources, const PipelineResourceLayoutDesc& ResourceLayout, const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes); + Uint32 NumAllowedTypes) noexcept; void CopyResources(ShaderResourceCacheD3D11& DstCache) const; diff --git a/Graphics/GraphicsEngineD3D11/src/BufferD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/BufferD3D11Impl.cpp index de7c843d..16e77806 100644 --- a/Graphics/GraphicsEngineD3D11/src/BufferD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/BufferD3D11Impl.cpp @@ -62,8 +62,8 @@ BufferD3D11Impl::BufferD3D11Impl(IReferenceCounters* pRefCounters, LOG_ERROR_AND_THROW("Unified resources are not supported in Direct3D11"); } - if (m_Desc.Usage == USAGE_STATIC) - VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for static buffers"); + if (m_Desc.Usage == USAGE_IMMUTABLE) + VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for immutable buffers"); if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER) { diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index c396b15c..9286f3f8 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); + const 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; @@ -179,9 +181,9 @@ void DeviceContextD3D11Impl::TransitionAndCommitShaderResources(IPipelineState* { #ifdef DILIGENT_DEVELOPMENT bool ResourcesPresent = false; - for (Uint32 s = 0; s < pPipelineStateD3D11->GetNumShaders(); ++s) + for (Uint32 s = 0; s < pPipelineStateD3D11->GetNumShaderStages(); ++s) { - auto* pShaderD3D11 = pPipelineStateD3D11->GetShader<ShaderD3D11Impl>(s); + auto* pShaderD3D11 = pPipelineStateD3D11->GetShader(s); if (pShaderD3D11->GetD3D11Resources()->GetTotalResources() > 0) ResourcesPresent = true; } @@ -206,7 +208,7 @@ void DeviceContextD3D11Impl::TransitionAndCommitShaderResources(IPipelineState* #endif auto NumShaders = pShaderResBindingD3D11->GetNumActiveShaders(); - VERIFY(NumShaders == pPipelineStateD3D11->GetNumShaders(), "Number of active shaders in shader resource binding is not consistent with the number of shaders in the pipeline state"); + VERIFY(NumShaders == pPipelineStateD3D11->GetNumShaderStages(), "Number of active shaders in shader resource binding is not consistent with the number of shaders in the pipeline state"); #ifdef DILIGENT_DEVELOPMENT { @@ -233,7 +235,7 @@ void DeviceContextD3D11Impl::TransitionAndCommitShaderResources(IPipelineState* const auto ShaderTypeInd = GetShaderTypeIndex(ShaderType); #ifdef DILIGENT_DEVELOPMENT - auto* pShaderD3D11 = pPipelineStateD3D11->GetShader<ShaderD3D11Impl>(s); + auto* pShaderD3D11 = pPipelineStateD3D11->GetShader(s); VERIFY_EXPR(ShaderType == pShaderD3D11->GetDesc().ShaderType); #endif @@ -380,7 +382,7 @@ void DeviceContextD3D11Impl::TransitionAndCommitShaderResources(IPipelineState* const auto ShaderTypeInd = GetShaderTypeIndex(ShaderType); #ifdef DILIGENT_DEVELOPMENT - auto* pShaderD3D11 = pPipelineStateD3D11->GetShader<ShaderD3D11Impl>(s); + auto* pShaderD3D11 = pPipelineStateD3D11->GetShader(s); VERIFY_EXPR(ShaderType == pShaderD3D11->GetDesc().ShaderType); #endif @@ -671,9 +673,9 @@ void DeviceContextD3D11Impl::SetBlendFactors(const float* pBlendFactors) { Uint32 SampleMask = 0xFFFFFFFF; ID3D11BlendState* pd3d11BS = nullptr; - if (m_pPipelineState) + if (m_pPipelineState && m_pPipelineState->GetDesc().IsAnyGraphicsPipeline()) { - 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 39a6ca4a..108f149c 100644 --- a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp @@ -31,49 +31,74 @@ #include "RenderDeviceD3D11Impl.hpp" #include "ShaderResourceBindingD3D11Impl.hpp" #include "EngineMemory.h" -#include "ShaderD3D11Impl.hpp" namespace Diligent { -PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, - RenderDeviceD3D11Impl* pRenderDeviceD3D11, - const PipelineStateCreateInfo& CreateInfo) : +template <typename PSOCreateInfoType> +void PipelineStateD3D11Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo) +{ + m_ResourceLayoutIndex.fill(-1); + + std::vector<std::pair<SHADER_TYPE, ShaderD3D11Impl*>> ShaderStages; + ExtractShaders<ShaderD3D11Impl>(CreateInfo, ShaderStages); + + const auto NumShaderStages = GetNumShaderStages(); + VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size()); + + LinearAllocator MemPool{GetRawAllocator()}; + + MemPool.AddSpace<ShaderResourceCacheD3D11>(NumShaderStages); + MemPool.AddSpace<ShaderResourceLayoutD3D11>(NumShaderStages); + + ReserveSpaceForPipelineDesc(CreateInfo, MemPool); + + MemPool.Reserve(); + + m_pStaticResourceCaches = MemPool.ConstructArray<ShaderResourceCacheD3D11>(NumShaderStages); + + // The memory is now owned by PipelineStateD3D11Impl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_pStaticResourceCaches); + (void)Ptr; + + m_pStaticResourceLayouts = MemPool.Allocate<ShaderResourceLayoutD3D11>(NumShaderStages); + for (Uint32 i = 0; i < NumShaderStages; ++i) + new (m_pStaticResourceLayouts + i) ShaderResourceLayoutD3D11{*this, m_pStaticResourceCaches[i]}; // noexcept + + InitializePipelineDesc(CreateInfo, MemPool); + + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects + + InitResourceLayouts(CreateInfo, ShaderStages); +} + + +PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D11Impl* pRenderDeviceD3D11, + const GraphicsPipelineStateCreateInfo& CreateInfo) : // clang-format off TPipelineStateBase { pRefCounters, pRenderDeviceD3D11, - CreateInfo.PSODesc + CreateInfo }, m_SRBMemAllocator{GetRawAllocator()}, - m_StaticSamplers (STD_ALLOCATOR_RAW_MEM(StaticSamplerInfo, GetRawAllocator(), "Allocator for vector<StaticSamplerInfo>")) + m_ImmutableSamplers (STD_ALLOCATOR_RAW_MEM(ImmutableSamplerInfo, GetRawAllocator(), "Allocator for vector<ImmutableSamplerInfo>")) // clang-format on { - m_ResourceLayoutIndex.fill(-1); - - if (m_Desc.IsComputePipeline()) + try { - auto* pCS = ValidatedCast<ShaderD3D11Impl>(m_Desc.ComputePipeline.pCS); - m_pCS = pCS; - if (m_pCS == nullptr) - { - LOG_ERROR_AND_THROW("Compute shader is null"); - } + InitInternalObjects(CreateInfo); - 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) - { + auto& GraphicsPipeline = GetGraphicsPipelineDesc(); #define INIT_SHADER(ShortName, ExpectedType) \ do \ { \ - auto* pShader = ValidatedCast<ShaderD3D11Impl>(m_Desc.GraphicsPipeline.p##ShortName); \ + auto* pShader = ValidatedCast<ShaderD3D11Impl>(CreateInfo.p##ShortName); \ m_p##ShortName = pShader; \ if (m_p##ShortName && m_p##ShortName->GetDesc().ShaderType != ExpectedType) \ { \ @@ -98,22 +123,22 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR auto* pDeviceD3D11 = pRenderDeviceD3D11->GetD3D11Device(); D3D11_BLEND_DESC D3D11BSDesc = {}; - BlendStateDesc_To_D3D11_BLEND_DESC(m_Desc.GraphicsPipeline.BlendDesc, 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); + 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); + 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; + const auto& InputLayout = GraphicsPipeline.InputLayout; if (InputLayout.NumElements > 0) { std::vector<D3D11_INPUT_ELEMENT_DESC, STDAllocatorRawMem<D3D11_INPUT_ELEMENT_DESC>> d311InputElements(STD_ALLOCATOR_RAW_MEM(D3D11_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector<D3D11_INPUT_ELEMENT_DESC>")); @@ -127,75 +152,141 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR "Failed to create the Direct3D11 input layout"); } } - else + catch (...) + { + Destruct(); + throw; + } +} + +PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D11Impl* pRenderDeviceD3D11, + const ComputePipelineStateCreateInfo& CreateInfo) : + // clang-format off + TPipelineStateBase + { + pRefCounters, + pRenderDeviceD3D11, + CreateInfo + }, + m_SRBMemAllocator{GetRawAllocator()}, + m_ImmutableSamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerInfo, GetRawAllocator(), "Allocator for vector<ImmutableSamplerInfo>")) +// clang-format on +{ + try + { + InitInternalObjects(CreateInfo); + + m_pCS = ValidatedCast<ShaderD3D11Impl>(CreateInfo.pCS); + if (m_pCS == nullptr) + { + LOG_ERROR_AND_THROW("Compute shader is null"); + } + + if (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 = m_pCS->GetD3D11Resources()->GetHash(); + } + catch (...) { - UNEXPECTED(GetPipelineTypeString(m_Desc.PipelineType), " pipelines are not supported by Direct3D11 backend"); + Destruct(); + throw; } +} - m_pStaticResourceLayouts = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceLayoutD3D11", ShaderResourceLayoutD3D11, m_NumShaders); - m_pStaticResourceCaches = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceCacheD3D11", ShaderResourceCacheD3D11, m_NumShaders); +PipelineStateD3D11Impl::~PipelineStateD3D11Impl() +{ + Destruct(); +} +void PipelineStateD3D11Impl::Destruct() +{ + if (m_pStaticResourceLayouts != nullptr) + { + for (Uint32 l = 0; l < GetNumShaderStages(); ++l) + { + m_pStaticResourceLayouts[l].~ShaderResourceLayoutD3D11(); + } + } + + if (m_pStaticResourceCaches != nullptr) + { + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) + { + m_pStaticResourceCaches[s].Destroy(GetRawAllocator()); + m_pStaticResourceCaches[s].~ShaderResourceCacheD3D11(); + } + } + + // All subobjects are allocated in contiguous chunks of memory. + if (auto* pRawMem = m_pStaticResourceCaches) + GetRawAllocator().Free(pRawMem); +} + +IMPLEMENT_QUERY_INTERFACE(PipelineStateD3D11Impl, IID_PipelineStateD3D11, TPipelineStateBase) + + +void PipelineStateD3D11Impl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + const std::vector<std::pair<SHADER_TYPE, ShaderD3D11Impl*>>& ShaderStages) +{ const auto& ResourceLayout = m_Desc.ResourceLayout; #ifdef DILIGENT_DEVELOPMENT { const ShaderResources* pResources[MAX_SHADERS_IN_PIPELINE] = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < ShaderStages.size(); ++s) { - auto* pShader = GetShader<const ShaderD3D11Impl>(s); + auto* pShader = ShaderStages[s].second; pResources[s] = &(*pShader->GetD3D11Resources()); } - ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, m_NumShaders, + ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, GetNumShaderStages(), (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS) == 0); } #endif - decltype(m_StaticSamplers) StaticSamplers(STD_ALLOCATOR_RAW_MEM(StaticSamplerInfo, GetRawAllocator(), "Allocator for vector<StaticSamplerInfo>")); + decltype(m_ImmutableSamplers) ImmutableSamplers{STD_ALLOCATOR_RAW_MEM(ImmutableSamplerInfo, GetRawAllocator(), "Allocator for vector<ImmutableSamplerInfo>")}; + std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderResLayoutDataSizes = {}; std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderResCacheDataSizes = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < ShaderStages.size(); ++s) { - const auto* pShader = GetShader<const ShaderD3D11Impl>(s); - const auto& ShaderDesc = pShader->GetDesc(); - const auto& ShaderResources = *pShader->GetD3D11Resources(); - VERIFY_EXPR(ShaderDesc.ShaderType == ShaderResources.GetShaderType()); + const auto* pShader = ShaderStages[s].second; + const auto& ShaderDesc = pShader->GetDesc(); + const auto& Resources = *pShader->GetD3D11Resources(); + VERIFY_EXPR(ShaderDesc.ShaderType == Resources.GetShaderType()); - new (m_pStaticResourceCaches + s) ShaderResourceCacheD3D11; - // Do not initialize the cache as this will be performed by the resource layout + // The cache will be initialized by the resource layout // Shader resource layout will only contain dynamic and mutable variables const SHADER_RESOURCE_VARIABLE_TYPE StaticVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; - // clang-format off - new (m_pStaticResourceLayouts + s) - ShaderResourceLayoutD3D11 - { - *this, - pShader->GetD3D11Resources(), - m_Desc.ResourceLayout, - StaticVarTypes, - _countof(StaticVarTypes), - m_pStaticResourceCaches[s], - GetRawAllocator(), - GetRawAllocator() - }; - // clang-format on - - // Initialize static samplers - for (Uint32 sam = 0; sam < ShaderResources.GetNumSamplers(); ++sam) + m_pStaticResourceLayouts[s].Initialize( + pShader->GetD3D11Resources(), + m_Desc.ResourceLayout, + StaticVarTypes, + _countof(StaticVarTypes), + GetRawAllocator(), + GetRawAllocator() // + ); + + // Initialize immutable samplers + for (Uint32 sam = 0; sam < Resources.GetNumSamplers(); ++sam) { - const auto& SamplerAttribs = ShaderResources.GetSampler(sam); - constexpr bool LogStaticSamplerArrayError = true; - auto SrcStaticSamplerInd = ShaderResources.FindStaticSampler(SamplerAttribs, ResourceLayout, LogStaticSamplerArrayError); - if (SrcStaticSamplerInd >= 0) + const auto& SamplerAttribs = Resources.GetSampler(sam); + constexpr bool LogImtblSamplerArrayError = true; + auto SrcImtblSamplerInd = Resources.FindImmutableSampler(SamplerAttribs, ResourceLayout, LogImtblSamplerArrayError); + if (SrcImtblSamplerInd >= 0) { - const auto& SrcStaticSamplerInfo = ResourceLayout.StaticSamplers[SrcStaticSamplerInd]; - RefCntAutoPtr<ISampler> pStaticSampler; - pRenderDeviceD3D11->CreateSampler(SrcStaticSamplerInfo.Desc, &pStaticSampler); - StaticSamplers.emplace_back(SamplerAttribs, std::move(pStaticSampler)); + const auto& SrcImtblSamplerInfo = ResourceLayout.ImmutableSamplers[SrcImtblSamplerInd]; + + RefCntAutoPtr<ISampler> pImbtlSampler; + GetDevice()->CreateSampler(SrcImtblSamplerInfo.Desc, &pImbtlSampler); + ImmutableSamplers.emplace_back(SamplerAttribs, std::move(pImbtlSampler)); } } - m_StaticSamplerOffsets[s + 1] = static_cast<Uint16>(StaticSamplers.size()); + m_ImmutableSamplerOffsets[s + 1] = static_cast<Uint16>(ImmutableSamplers.size()); if (m_Desc.SRBAllocationGranularity > 1) { @@ -204,8 +295,8 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC // }; - ShaderResLayoutDataSizes[s] = ShaderResourceLayoutD3D11::GetRequiredMemorySize(ShaderResources, ResourceLayout, SRBVarTypes, _countof(SRBVarTypes)); - ShaderResCacheDataSizes[s] = ShaderResourceCacheD3D11::GetRequriedMemorySize(ShaderResources); + ShaderResLayoutDataSizes[s] = ShaderResourceLayoutD3D11::GetRequiredMemorySize(Resources, ResourceLayout, SRBVarTypes, _countof(SRBVarTypes)); + ShaderResCacheDataSizes[s] = ShaderResourceCacheD3D11::GetRequriedMemorySize(Resources); } auto ShaderInd = GetShaderTypePipelineIndex(ShaderDesc.ShaderType, m_Desc.PipelineType); @@ -214,40 +305,20 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR if (m_Desc.SRBAllocationGranularity > 1) { - m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, m_NumShaders, ShaderResLayoutDataSizes.data(), m_NumShaders, ShaderResCacheDataSizes.data()); + m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderResLayoutDataSizes.data(), GetNumShaderStages(), ShaderResCacheDataSizes.data()); } - m_StaticSamplers.reserve(StaticSamplers.size()); - for (auto& Sam : StaticSamplers) - m_StaticSamplers.emplace_back(std::move(Sam)); + m_ImmutableSamplers.reserve(ImmutableSamplers.size()); + for (auto& ImtblSam : ImmutableSamplers) + m_ImmutableSamplers.emplace_back(std::move(ImtblSam)); - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { - // Initialize static samplers in the static resource cache to avoid warning messages - SetStaticSamplers(m_pStaticResourceCaches[s], s); + // Initialize immutable samplers in the static resource cache to avoid warning messages + SetImmutableSamplers(m_pStaticResourceCaches[s], s); } } - -PipelineStateD3D11Impl::~PipelineStateD3D11Impl() -{ - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - m_pStaticResourceCaches[s].Destroy(GetRawAllocator()); - m_pStaticResourceCaches[s].~ShaderResourceCacheD3D11(); - } - GetRawAllocator().Free(m_pStaticResourceCaches); - - for (Uint32 l = 0; l < m_NumShaders; ++l) - { - m_pStaticResourceLayouts[l].~ShaderResourceLayoutD3D11(); - } - GetRawAllocator().Free(m_pStaticResourceLayouts); -} - -IMPLEMENT_QUERY_INTERFACE(PipelineStateD3D11Impl, IID_PipelineStateD3D11, TPipelineStateBase) - - ID3D11BlendState* PipelineStateD3D11Impl::GetD3D11BlendState() { return m_pd3d11BlendState; @@ -270,9 +341,8 @@ ID3D11InputLayout* PipelineStateD3D11Impl::GetD3D11InputLayout() void PipelineStateD3D11Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) { - auto* pRenderDeviceD3D11 = ValidatedCast<RenderDeviceD3D11Impl>(GetDevice()); - auto& SRBAllocator = pRenderDeviceD3D11->GetSRBAllocator(); - auto pShaderResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingD3D11Impl instance", ShaderResourceBindingD3D11Impl)(this, false); + auto& SRBAllocator = GetDevice()->GetSRBAllocator(); + auto pShaderResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingD3D11Impl instance", ShaderResourceBindingD3D11Impl)(this, false); if (InitStaticResources) pShaderResBinding->InitializeStaticResources(nullptr); pShaderResBinding->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(static_cast<IShaderResourceBinding**>(ppShaderResourceBinding))); @@ -289,13 +359,13 @@ bool PipelineStateD3D11Impl::IsCompatibleWith(const IPipelineState* pPSO) const if (m_ShaderResourceLayoutHash != pPSOD3D11->m_ShaderResourceLayoutHash) return false; - if (m_NumShaders != pPSOD3D11->m_NumShaders) + if (GetNumShaderStages() != pPSOD3D11->GetNumShaderStages()) return false; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { - auto* pShader0 = GetShader<const ShaderD3D11Impl>(s); - auto* pShader1 = pPSOD3D11->GetShader<const ShaderD3D11Impl>(s); + auto* pShader0 = GetShader(s); + auto* pShader1 = pPSOD3D11->GetShader(s); if (pShader0->GetDesc().ShaderType != pShader1->GetDesc().ShaderType) return false; const auto& Res0 = *pShader0->GetD3D11Resources(); @@ -352,7 +422,7 @@ ID3D11ComputeShader* PipelineStateD3D11Impl::GetD3D11ComputeShader() void PipelineStateD3D11Impl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { auto& StaticResLayout = m_pStaticResourceLayouts[s]; if ((ShaderFlags & StaticResLayout.GetShaderType()) != 0) @@ -366,7 +436,7 @@ Uint32 PipelineStateD3D11Impl::GetStaticVariableCount(SHADER_TYPE ShaderType) co if (LayoutInd < 0) return 0; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= GetNumShaderStages()); return m_pStaticResourceLayouts[LayoutInd].GetTotalResourceCount(); } @@ -376,7 +446,7 @@ IShaderResourceVariable* PipelineStateD3D11Impl::GetStaticVariableByName(SHADER_ if (LayoutInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= GetNumShaderStages()); return m_pStaticResourceLayouts[LayoutInd].GetShaderVariable(Name); } @@ -386,23 +456,48 @@ IShaderResourceVariable* PipelineStateD3D11Impl::GetStaticVariableByIndex(SHADER if (LayoutInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) <= GetNumShaderStages()); return m_pStaticResourceLayouts[LayoutInd].GetShaderVariable(Index); } -void PipelineStateD3D11Impl::SetStaticSamplers(ShaderResourceCacheD3D11& ResourceCache, Uint32 ShaderInd) const +void PipelineStateD3D11Impl::SetImmutableSamplers(ShaderResourceCacheD3D11& ResourceCache, Uint32 ShaderInd) const { auto NumCachedSamplers = ResourceCache.GetSamplerCount(); - for (Uint32 s = m_StaticSamplerOffsets[ShaderInd]; s < m_StaticSamplerOffsets[ShaderInd + 1]; ++s) + for (Uint32 s = m_ImmutableSamplerOffsets[ShaderInd]; s < m_ImmutableSamplerOffsets[ShaderInd + 1]; ++s) { - auto& SamplerInfo = m_StaticSamplers[s]; + auto& SamplerInfo = m_ImmutableSamplers[s]; const auto& SamAttribs = SamplerInfo.Attribs; auto* pSamplerD3D11Impl = SamplerInfo.pSampler.RawPtr<SamplerD3D11Impl>(); - // Limiting EndBindPoint is required when initializing static samplers in a Shader's static cache + // Limiting EndBindPoint is required when initializing immutable samplers in a Shader's static cache auto EndBindPoint = std::min(static_cast<Uint32>(SamAttribs.BindPoint) + SamAttribs.BindCount, NumCachedSamplers); for (Uint32 BindPoint = SamAttribs.BindPoint; BindPoint < EndBindPoint; ++BindPoint) ResourceCache.SetSampler(BindPoint, pSamplerD3D11Impl); } } +const ShaderD3D11Impl* PipelineStateD3D11Impl::GetShaderByType(SHADER_TYPE ShaderType) const +{ + switch (ShaderType) + { + // clang-format off + case SHADER_TYPE_VERTEX: return m_pVS; + case SHADER_TYPE_PIXEL: return m_pPS; + case SHADER_TYPE_GEOMETRY: return m_pGS; + case SHADER_TYPE_HULL: return m_pHS; + case SHADER_TYPE_DOMAIN: return m_pDS; + case SHADER_TYPE_COMPUTE: return m_pCS; + default: UNEXPECTED("unsupported shader type"); return nullptr; + // clang-format on + } +} + +const ShaderD3D11Impl* PipelineStateD3D11Impl::GetShader(Uint32 Index) const +{ + if (Index < GetNumShaderStages()) + return GetShaderByType(GetShaderStageType(Index)); + + UNEXPECTED("Shader index is out of range"); + return nullptr; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp index d0d4957b..06cda6ad 100644 --- a/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp @@ -177,7 +177,7 @@ RenderDeviceD3D11Impl::RenderDeviceD3D11Impl(IReferenceCounters* pRefCo #undef UNSUPPORTED_FEATURE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 31, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif auto& TexCaps = m_DeviceCaps.TexCaps; @@ -255,7 +255,7 @@ void RenderDeviceD3D11Impl::CreateBufferFromD3DResource(ID3D11Buffer* pd3d11Buff CreateDeviceObject("buffer", BuffDesc, ppBuffer, [&]() // { - BufferD3D11Impl* pBufferD3D11(NEW_RC_OBJ(m_BufObjAllocator, "BufferD3D11Impl instance", BufferD3D11Impl)(m_BuffViewObjAllocator, this, BuffDesc, InitialState, pd3d11Buffer)); + BufferD3D11Impl* pBufferD3D11{NEW_RC_OBJ(m_BufObjAllocator, "BufferD3D11Impl instance", BufferD3D11Impl)(m_BuffViewObjAllocator, this, BuffDesc, InitialState, pd3d11Buffer)}; pBufferD3D11->QueryInterface(IID_Buffer, reinterpret_cast<IObject**>(ppBuffer)); pBufferD3D11->CreateDefaultViews(); OnCreateDeviceObject(pBufferD3D11); @@ -267,7 +267,7 @@ void RenderDeviceD3D11Impl::CreateBuffer(const BufferDesc& BuffDesc, const Buffe CreateDeviceObject("buffer", BuffDesc, ppBuffer, [&]() // { - BufferD3D11Impl* pBufferD3D11(NEW_RC_OBJ(m_BufObjAllocator, "BufferD3D11Impl instance", BufferD3D11Impl)(m_BuffViewObjAllocator, this, BuffDesc, pBuffData)); + BufferD3D11Impl* pBufferD3D11{NEW_RC_OBJ(m_BufObjAllocator, "BufferD3D11Impl instance", BufferD3D11Impl)(m_BuffViewObjAllocator, this, BuffDesc, pBuffData)}; pBufferD3D11->QueryInterface(IID_Buffer, reinterpret_cast<IObject**>(ppBuffer)); pBufferD3D11->CreateDefaultViews(); OnCreateDeviceObject(pBufferD3D11); @@ -279,7 +279,7 @@ void RenderDeviceD3D11Impl::CreateShader(const ShaderCreateInfo& ShaderCI, IShad CreateDeviceObject("shader", ShaderCI.Desc, ppShader, [&]() // { - ShaderD3D11Impl* pShaderD3D11(NEW_RC_OBJ(m_ShaderObjAllocator, "ShaderD3D11Impl instance", ShaderD3D11Impl)(this, ShaderCI)); + ShaderD3D11Impl* pShaderD3D11{NEW_RC_OBJ(m_ShaderObjAllocator, "ShaderD3D11Impl instance", ShaderD3D11Impl)(this, ShaderCI)}; pShaderD3D11->QueryInterface(IID_Shader, reinterpret_cast<IObject**>(ppShader)); OnCreateDeviceObject(pShaderD3D11); @@ -296,7 +296,7 @@ void RenderDeviceD3D11Impl::CreateTexture1DFromD3DResource(ID3D11Texture1D* pd3d CreateDeviceObject("texture", TexDesc, ppTexture, [&]() // { - TextureBaseD3D11* pTextureD3D11 = NEW_RC_OBJ(m_TexObjAllocator, "Texture1D_D3D11 instance", Texture1D_D3D11)(m_TexViewObjAllocator, this, InitialState, pd3d11Texture); + TextureBaseD3D11* pTextureD3D11{NEW_RC_OBJ(m_TexObjAllocator, "Texture1D_D3D11 instance", Texture1D_D3D11)(m_TexViewObjAllocator, this, InitialState, pd3d11Texture)}; pTextureD3D11->QueryInterface(IID_Texture, reinterpret_cast<IObject**>(ppTexture)); pTextureD3D11->CreateDefaultViews(); OnCreateDeviceObject(pTextureD3D11); @@ -313,7 +313,7 @@ void RenderDeviceD3D11Impl::CreateTexture2DFromD3DResource(ID3D11Texture2D* pd3d CreateDeviceObject("texture", TexDesc, ppTexture, [&]() // { - TextureBaseD3D11* pTextureD3D11 = NEW_RC_OBJ(m_TexObjAllocator, "Texture2D_D3D11 instance", Texture2D_D3D11)(m_TexViewObjAllocator, this, InitialState, pd3d11Texture); + TextureBaseD3D11* pTextureD3D11{NEW_RC_OBJ(m_TexObjAllocator, "Texture2D_D3D11 instance", Texture2D_D3D11)(m_TexViewObjAllocator, this, InitialState, pd3d11Texture)}; pTextureD3D11->QueryInterface(IID_Texture, reinterpret_cast<IObject**>(ppTexture)); pTextureD3D11->CreateDefaultViews(); OnCreateDeviceObject(pTextureD3D11); @@ -330,7 +330,7 @@ void RenderDeviceD3D11Impl::CreateTexture3DFromD3DResource(ID3D11Texture3D* pd3d CreateDeviceObject("texture", TexDesc, ppTexture, [&]() // { - TextureBaseD3D11* pTextureD3D11 = NEW_RC_OBJ(m_TexObjAllocator, "Texture3D_D3D11 instance", Texture3D_D3D11)(m_TexViewObjAllocator, this, InitialState, pd3d11Texture); + TextureBaseD3D11* pTextureD3D11{NEW_RC_OBJ(m_TexObjAllocator, "Texture3D_D3D11 instance", Texture3D_D3D11)(m_TexViewObjAllocator, this, InitialState, pd3d11Texture)}; pTextureD3D11->QueryInterface(IID_Texture, reinterpret_cast<IObject**>(ppTexture)); pTextureD3D11->CreateDefaultViews(); OnCreateDeviceObject(pTextureD3D11); @@ -378,7 +378,7 @@ void RenderDeviceD3D11Impl::CreateSampler(const SamplerDesc& SamplerDesc, ISampl m_SamplersRegistry.Find(SamplerDesc, reinterpret_cast<IDeviceObject**>(ppSampler)); if (*ppSampler == nullptr) { - SamplerD3D11Impl* pSamplerD3D11(NEW_RC_OBJ(m_SamplerObjAllocator, "SamplerD3D11Impl instance", SamplerD3D11Impl)(this, SamplerDesc)); + SamplerD3D11Impl* pSamplerD3D11{NEW_RC_OBJ(m_SamplerObjAllocator, "SamplerD3D11Impl instance", SamplerD3D11Impl)(this, SamplerDesc)}; pSamplerD3D11->QueryInterface(IID_Sampler, reinterpret_cast<IObject**>(ppSampler)); OnCreateDeviceObject(pSamplerD3D11); m_SamplersRegistry.Add(SamplerDesc, *ppSampler); @@ -386,23 +386,35 @@ void RenderDeviceD3D11Impl::CreateSampler(const SamplerDesc& SamplerDesc, ISampl }); } -void RenderDeviceD3D11Impl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +template <typename PSOCreateInfoType> +void RenderDeviceD3D11Impl::CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState) { CreateDeviceObject("Pipeline state", PSOCreateInfo.PSODesc, ppPipelineState, [&]() // { - PipelineStateD3D11Impl* pPipelineStateD3D11(NEW_RC_OBJ(m_PSOAllocator, "PipelineStateD3D11Impl instance", PipelineStateD3D11Impl)(this, PSOCreateInfo)); + PipelineStateD3D11Impl* pPipelineStateD3D11{NEW_RC_OBJ(m_PSOAllocator, "PipelineStateD3D11Impl instance", PipelineStateD3D11Impl)(this, PSOCreateInfo)}; pPipelineStateD3D11->QueryInterface(IID_PipelineState, reinterpret_cast<IObject**>(ppPipelineState)); OnCreateDeviceObject(pPipelineStateD3D11); }); } + +void RenderDeviceD3D11Impl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState); +} + +void RenderDeviceD3D11Impl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState); +} + void RenderDeviceD3D11Impl::CreateFence(const FenceDesc& Desc, IFence** ppFence) { CreateDeviceObject("Fence", Desc, ppFence, [&]() // { - FenceD3D11Impl* pFenceD3D11(NEW_RC_OBJ(m_FenceAllocator, "FenceD3D11Impl instance", FenceD3D11Impl)(this, Desc)); + FenceD3D11Impl* pFenceD3D11{NEW_RC_OBJ(m_FenceAllocator, "FenceD3D11Impl instance", FenceD3D11Impl)(this, Desc)}; pFenceD3D11->QueryInterface(IID_Fence, reinterpret_cast<IObject**>(ppFence)); OnCreateDeviceObject(pFenceD3D11); }); @@ -413,7 +425,7 @@ void RenderDeviceD3D11Impl::CreateQuery(const QueryDesc& Desc, IQuery** ppQuery) CreateDeviceObject("Query", Desc, ppQuery, [&]() // { - QueryD3D11Impl* pQueryD3D11(NEW_RC_OBJ(m_QueryAllocator, "QueryD3D11Impl instance", QueryD3D11Impl)(this, Desc)); + QueryD3D11Impl* pQueryD3D11{NEW_RC_OBJ(m_QueryAllocator, "QueryD3D11Impl instance", QueryD3D11Impl)(this, Desc)}; pQueryD3D11->QueryInterface(IID_Query, reinterpret_cast<IObject**>(ppQuery)); OnCreateDeviceObject(pQueryD3D11); }); @@ -424,7 +436,7 @@ void RenderDeviceD3D11Impl::CreateRenderPass(const RenderPassDesc& Desc, IRender CreateDeviceObject("RenderPass", Desc, ppRenderPass, [&]() // { - RenderPassD3D11Impl* pRenderPassD3D11(NEW_RC_OBJ(m_RenderPassAllocator, "RenderPassD3D11Impl instance", RenderPassD3D11Impl)(this, Desc)); + RenderPassD3D11Impl* pRenderPassD3D11{NEW_RC_OBJ(m_RenderPassAllocator, "RenderPassD3D11Impl instance", RenderPassD3D11Impl)(this, Desc)}; pRenderPassD3D11->QueryInterface(IID_RenderPass, reinterpret_cast<IObject**>(ppRenderPass)); OnCreateDeviceObject(pRenderPassD3D11); }); @@ -435,7 +447,7 @@ void RenderDeviceD3D11Impl::CreateFramebuffer(const FramebufferDesc& Desc, IFram CreateDeviceObject("Framebuffer", Desc, ppFramebuffer, [&]() // { - FramebufferD3D11Impl* pFramebufferD3D11(NEW_RC_OBJ(m_FramebufferAllocator, "FramebufferD3D11Impl instance", FramebufferD3D11Impl)(this, Desc)); + FramebufferD3D11Impl* pFramebufferD3D11{NEW_RC_OBJ(m_FramebufferAllocator, "FramebufferD3D11Impl instance", FramebufferD3D11Impl)(this, Desc)}; pFramebufferD3D11->QueryInterface(IID_Framebuffer, reinterpret_cast<IObject**>(ppFramebuffer)); OnCreateDeviceObject(pFramebufferD3D11); }); diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp index 62fd2df7..46833c81 100644 --- a/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/ShaderResourceBindingD3D11Impl.cpp @@ -31,6 +31,7 @@ #include "DeviceContextD3D11Impl.hpp" #include "RenderDeviceD3D11Impl.hpp" #include "ShaderD3D11Impl.hpp" +#include "LinearAllocator.hpp" namespace Diligent { @@ -49,74 +50,104 @@ ShaderResourceBindingD3D11Impl::ShaderResourceBindingD3D11Impl(IReferenceCounter m_bIsStaticResourcesBound{false} // clang-format on { - m_ResourceLayoutIndex.fill(-1); - m_NumActiveShaders = static_cast<Uint8>(pPSO->GetNumShaders()); + try + { + m_ResourceLayoutIndex.fill(-1); + m_NumActiveShaders = static_cast<Uint8>(pPSO->GetNumShaderStages()); - // clang-format off - m_pResourceLayouts = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceLayoutD3D11", ShaderResourceLayoutD3D11, m_NumActiveShaders); - m_pBoundResourceCaches = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceCacheD3D11", ShaderResourceCacheD3D11, m_NumActiveShaders); - // clang-format on + LinearAllocator MemPool{GetRawAllocator()}; + MemPool.AddSpace<ShaderResourceCacheD3D11>(m_NumActiveShaders); + MemPool.AddSpace<ShaderResourceLayoutD3D11>(m_NumActiveShaders); - const auto& PSODesc = pPSO->GetDesc(); + MemPool.Reserve(); - // Reserve memory for resource layouts - for (Uint8 s = 0; s < m_NumActiveShaders; ++s) - { - auto* pShaderD3D11 = pPSO->GetShader<ShaderD3D11Impl>(s); - - auto& SRBMemAllocator = pPSO->GetSRBMemoryAllocator(); - auto& ResCacheDataAllocator = SRBMemAllocator.GetResourceCacheDataAllocator(s); - auto& ResLayoutDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s); - - // Initialize resource cache to have enough space to contain all shader resources, including static ones - // Static resources are copied before resources are committed - const auto& Resources = *pShaderD3D11->GetD3D11Resources(); - new (m_pBoundResourceCaches + s) ShaderResourceCacheD3D11; - m_pBoundResourceCaches[s].Initialize(Resources, ResCacheDataAllocator); - - // Shader resource layout will only contain dynamic and mutable variables - // http://diligentgraphics.com/diligent-engine/architecture/d3d11/shader-resource-cache#Shader-Resource-Cache-Initialization - SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; - // clang-format off - new (m_pResourceLayouts + s) - ShaderResourceLayoutD3D11 - { - *this, + m_pBoundResourceCaches = MemPool.ConstructArray<ShaderResourceCacheD3D11>(m_NumActiveShaders); + + // The memory is now owned by ShaderResourceBindingD3D11Impl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_pBoundResourceCaches); + (void)Ptr; + + m_pResourceLayouts = MemPool.Allocate<ShaderResourceLayoutD3D11>(m_NumActiveShaders); + for (Uint8 s = 0; s < m_NumActiveShaders; ++s) + new (m_pResourceLayouts + s) ShaderResourceLayoutD3D11{*this, m_pBoundResourceCaches[s]}; // noexcept + + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects + + const auto& PSODesc = pPSO->GetDesc(); + + // Reserve memory for resource layouts + for (Uint8 s = 0; s < m_NumActiveShaders; ++s) + { + auto* pShaderD3D11 = pPSO->GetShader(s); + + auto& SRBMemAllocator = pPSO->GetSRBMemoryAllocator(); + auto& ResCacheDataAllocator = SRBMemAllocator.GetResourceCacheDataAllocator(s); + auto& ResLayoutDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s); + + // Initialize resource cache to have enough space to contain all shader resources, including static ones + // Static resources are copied before resources are committed + const auto& Resources = *pShaderD3D11->GetD3D11Resources(); + m_pBoundResourceCaches[s].Initialize(Resources, ResCacheDataAllocator); + + // Shader resource layout will only contain dynamic and mutable variables + // http://diligentgraphics.com/diligent-engine/architecture/d3d11/shader-resource-cache#Shader-Resource-Cache-Initialization + SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + m_pResourceLayouts[s].Initialize( pShaderD3D11->GetD3D11Resources(), PSODesc.ResourceLayout, VarTypes, _countof(VarTypes), - m_pBoundResourceCaches[s], ResCacheDataAllocator, - ResLayoutDataAllocator - }; - // clang-format on + ResLayoutDataAllocator // + ); - const auto ShaderType = pShaderD3D11->GetDesc().ShaderType; - const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, PSODesc.PipelineType); - VERIFY_EXPR(ShaderType == m_pResourceLayouts[s].GetShaderType()); - m_ShaderTypes[s] = ShaderType; + const auto ShaderType = pShaderD3D11->GetDesc().ShaderType; + const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, PSODesc.PipelineType); + VERIFY_EXPR(ShaderType == m_pResourceLayouts[s].GetShaderType()); + m_ShaderTypes[s] = ShaderType; - m_ResourceLayoutIndex[ShaderInd] = s; + m_ResourceLayoutIndex[ShaderInd] = s; + } + } + catch (...) + { + Destruct(); + throw; } } ShaderResourceBindingD3D11Impl::~ShaderResourceBindingD3D11Impl() { - auto* pPSOD3D11Impl = ValidatedCast<PipelineStateD3D11Impl>(m_pPSO); - for (Uint32 s = 0; s < m_NumActiveShaders; ++s) + Destruct(); +} + +void ShaderResourceBindingD3D11Impl::Destruct() +{ + if (m_pResourceLayouts != nullptr) + { + for (Int32 l = 0; l < m_NumActiveShaders; ++l) + { + m_pResourceLayouts[l].~ShaderResourceLayoutD3D11(); + } + } + + if (m_pBoundResourceCaches != nullptr) { - auto& Allocator = pPSOD3D11Impl->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(s); - m_pBoundResourceCaches[s].Destroy(Allocator); - m_pBoundResourceCaches[s].~ShaderResourceCacheD3D11(); + auto& SRBMemAllocator = m_pPSO->GetSRBMemoryAllocator(); + for (Uint32 s = 0; s < m_NumActiveShaders; ++s) + { + auto& Allocator = SRBMemAllocator.GetResourceCacheDataAllocator(s); + m_pBoundResourceCaches[s].Destroy(Allocator); + m_pBoundResourceCaches[s].~ShaderResourceCacheD3D11(); + } } - GetRawAllocator().Free(m_pBoundResourceCaches); - for (Int32 l = 0; l < m_NumActiveShaders; ++l) + if (void* pRawMem = m_pBoundResourceCaches) { - m_pResourceLayouts[l].~ShaderResourceLayoutD3D11(); + GetRawAllocator().Free(pRawMem); } - GetRawAllocator().Free(m_pResourceLayouts); } IMPLEMENT_QUERY_INTERFACE(ShaderResourceBindingD3D11Impl, IID_ShaderResourceBindingD3D11, TBase) @@ -151,14 +182,13 @@ void ShaderResourceBindingD3D11Impl::InitializeStaticResources(const IPipelineSt } const auto* pPSOD3D11 = ValidatedCast<const PipelineStateD3D11Impl>(pPipelineState); - auto ppShaders = pPSOD3D11->GetShaders(); - auto NumShaders = pPSOD3D11->GetNumShaders(); + auto NumShaders = pPSOD3D11->GetNumShaderStages(); VERIFY_EXPR(NumShaders == m_NumActiveShaders); for (Uint32 shader = 0; shader < NumShaders; ++shader) { const auto& StaticResLayout = pPSOD3D11->GetStaticResourceLayout(shader); - auto* pShaderD3D11 = ValidatedCast<ShaderD3D11Impl>(ppShaders[shader]); + auto* pShaderD3D11 = pPSOD3D11->GetShader(shader); #ifdef DILIGENT_DEVELOPMENT if (!StaticResLayout.dvpVerifyBindings()) { @@ -178,7 +208,7 @@ void ShaderResourceBindingD3D11Impl::InitializeStaticResources(const IPipelineSt } #endif StaticResLayout.CopyResources(m_pBoundResourceCaches[shader]); - pPSOD3D11->SetStaticSamplers(m_pBoundResourceCaches[shader], shader); + pPSOD3D11->SetImmutableSamplers(m_pBoundResourceCaches[shader], shader); } m_bIsStaticResourcesBound = true; diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderResourceCacheD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderResourceCacheD3D11.cpp index 28086285..3aaf82b7 100755 --- a/Graphics/GraphicsEngineD3D11/src/ShaderResourceCacheD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/ShaderResourceCacheD3D11.cpp @@ -148,61 +148,60 @@ void ShaderResourceCacheD3D11::Initialize(Uint32 CBCount, Uint32 SRVCount, Uint3 void ShaderResourceCacheD3D11::Destroy(IMemoryAllocator& MemAllocator)
{
- VERIFY(IsInitialized(), "Resource cache is not initialized");
+ if (!IsInitialized())
+ return;
+
VERIFY(m_pdbgMemoryAllocator == &MemAllocator, "The allocator does not match the one used to create resources");
- if (IsInitialized())
+ // Explicitly destory all objects
+ auto CBCount = GetCBCount();
+ if (CBCount != 0)
{
- // Explicitly destory all objects
- auto CBCount = GetCBCount();
- if (CBCount != 0)
- {
- CachedCB* CBs = nullptr;
- ID3D11Buffer** d3d11CBs = nullptr;
- GetCBArrays(CBs, d3d11CBs);
- for (size_t cb = 0; cb < CBCount; ++cb)
- CBs[cb].~CachedCB();
- }
+ CachedCB* CBs = nullptr;
+ ID3D11Buffer** d3d11CBs = nullptr;
+ GetCBArrays(CBs, d3d11CBs);
+ for (size_t cb = 0; cb < CBCount; ++cb)
+ CBs[cb].~CachedCB();
+ }
- auto SRVCount = GetSRVCount();
- if (SRVCount != 0)
- {
- CachedResource* SRVResources = nullptr;
- ID3D11ShaderResourceView** d3d11SRVs = nullptr;
- GetSRVArrays(SRVResources, d3d11SRVs);
- for (size_t srv = 0; srv < SRVCount; ++srv)
- SRVResources[srv].~CachedResource();
- }
+ auto SRVCount = GetSRVCount();
+ if (SRVCount != 0)
+ {
+ CachedResource* SRVResources = nullptr;
+ ID3D11ShaderResourceView** d3d11SRVs = nullptr;
+ GetSRVArrays(SRVResources, d3d11SRVs);
+ for (size_t srv = 0; srv < SRVCount; ++srv)
+ SRVResources[srv].~CachedResource();
+ }
- auto SamplerCount = GetSamplerCount();
- if (SamplerCount != 0)
- {
- CachedSampler* Samplers = nullptr;
- ID3D11SamplerState** d3d11Samplers = nullptr;
- GetSamplerArrays(Samplers, d3d11Samplers);
- for (size_t sam = 0; sam < SamplerCount; ++sam)
- Samplers[sam].~CachedSampler();
- }
+ auto SamplerCount = GetSamplerCount();
+ if (SamplerCount != 0)
+ {
+ CachedSampler* Samplers = nullptr;
+ ID3D11SamplerState** d3d11Samplers = nullptr;
+ GetSamplerArrays(Samplers, d3d11Samplers);
+ for (size_t sam = 0; sam < SamplerCount; ++sam)
+ Samplers[sam].~CachedSampler();
+ }
- auto UAVCount = GetUAVCount();
- if (UAVCount != 0)
- {
- CachedResource* UAVResources = nullptr;
- ID3D11UnorderedAccessView** d3d11UAVs = nullptr;
- GetUAVArrays(UAVResources, d3d11UAVs);
- for (size_t uav = 0; uav < UAVCount; ++uav)
- UAVResources[uav].~CachedResource();
- }
+ auto UAVCount = GetUAVCount();
+ if (UAVCount != 0)
+ {
+ CachedResource* UAVResources = nullptr;
+ ID3D11UnorderedAccessView** d3d11UAVs = nullptr;
+ GetUAVArrays(UAVResources, d3d11UAVs);
+ for (size_t uav = 0; uav < UAVCount; ++uav)
+ UAVResources[uav].~CachedResource();
+ }
- m_SRVOffset = InvalidResourceOffset;
- m_SamplerOffset = InvalidResourceOffset;
- m_UAVOffset = InvalidResourceOffset;
- m_MemoryEndOffset = InvalidResourceOffset;
+ m_SRVOffset = InvalidResourceOffset;
+ m_SamplerOffset = InvalidResourceOffset;
+ m_UAVOffset = InvalidResourceOffset;
+ m_MemoryEndOffset = InvalidResourceOffset;
- if (m_pResourceData != nullptr)
- MemAllocator.Free(m_pResourceData);
- m_pResourceData = nullptr;
- }
+ if (m_pResourceData != nullptr)
+ MemAllocator.Free(m_pResourceData);
+ m_pResourceData = nullptr;
}
ShaderResourceCacheD3D11::~ShaderResourceCacheD3D11()
diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderResourceLayoutD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderResourceLayoutD3D11.cpp index fd6c7299..f7c1958d 100755 --- a/Graphics/GraphicsEngineD3D11/src/ShaderResourceLayoutD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/ShaderResourceLayoutD3D11.cpp @@ -84,11 +84,11 @@ ShaderResourceLayoutD3D11::~ShaderResourceLayoutD3D11() size_t ShaderResourceLayoutD3D11::GetRequiredMemorySize(const ShaderResourcesD3D11& SrcResources,
const PipelineResourceLayoutDesc& ResourceLayout,
const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes)
+ Uint32 NumAllowedTypes) noexcept
{
- // Skip static samplers as they are initialized directly in the resource cache by the PSO
- constexpr bool CountStaticSamplers = false;
- auto ResCounters = SrcResources.CountResources(ResourceLayout, AllowedVarTypes, NumAllowedTypes, CountStaticSamplers);
+ // Skip immutable samplers as they are initialized directly in the resource cache by the PSO
+ constexpr bool CountImtblSamplers = false;
+ auto ResCounters = SrcResources.CountResources(ResourceLayout, AllowedVarTypes, NumAllowedTypes, CountImtblSamplers);
// clang-format off
auto MemSize = ResCounters.NumCBs * sizeof(ConstBuffBindInfo) +
ResCounters.NumTexSRVs * sizeof(TexSRVBindInfo) +
@@ -101,28 +101,23 @@ size_t ShaderResourceLayoutD3D11::GetRequiredMemorySize(const ShaderResourcesD3D }
-ShaderResourceLayoutD3D11::ShaderResourceLayoutD3D11(IObject& Owner,
- std::shared_ptr<const ShaderResourcesD3D11> pSrcResources,
- const PipelineResourceLayoutDesc& ResourceLayout,
- const SHADER_RESOURCE_VARIABLE_TYPE* VarTypes,
- Uint32 NumVarTypes,
- ShaderResourceCacheD3D11& ResourceCache,
- IMemoryAllocator& ResCacheDataAllocator,
- IMemoryAllocator& ResLayoutDataAllocator) :
- // clang-format off
- m_Owner {Owner},
- m_pResources {std::move(pSrcResources)},
- m_ResourceCache {ResourceCache}
-// clang-format on
+void ShaderResourceLayoutD3D11::Initialize(std::shared_ptr<const ShaderResourcesD3D11> pSrcResources,
+ const PipelineResourceLayoutDesc& ResourceLayout,
+ const SHADER_RESOURCE_VARIABLE_TYPE* VarTypes,
+ Uint32 NumVarTypes,
+ IMemoryAllocator& ResCacheDataAllocator,
+ IMemoryAllocator& ResLayoutDataAllocator)
{
+ m_pResources = std::move(pSrcResources);
+
// http://diligentgraphics.com/diligent-engine/architecture/d3d11/shader-resource-layout#Shader-Resource-Layout-Initialization
const auto AllowedTypeBits = GetAllowedTypeBits(VarTypes, NumVarTypes);
// Count total number of resources of allowed types
- // Skip static samplers as they are initialized directly in the resource cache by the PSO
- constexpr bool CountStaticSamplers = false;
- auto ResCounters = m_pResources->CountResources(ResourceLayout, VarTypes, NumVarTypes, CountStaticSamplers);
+ // Skip immutable samplers as they are initialized directly in the resource cache by the PSO
+ constexpr bool CountImtblSamplers = false;
+ auto ResCounters = m_pResources->CountResources(ResourceLayout, VarTypes, NumVarTypes, CountImtblSamplers);
// Initialize offsets
size_t CurrentOffset = 0;
@@ -192,12 +187,12 @@ ShaderResourceLayoutD3D11::ShaderResourceLayoutD3D11(IObject& auto VarType = m_pResources->FindVariableType(Sampler, ResourceLayout);
if (IsAllowedType(VarType, AllowedTypeBits))
{
- // Constructor of PipelineStateD3D11Impl initializes static samplers and will log the error, if any
- constexpr bool LogStaticSamplerArrayError = false;
- auto StaticSamplerInd = m_pResources->FindStaticSampler(Sampler, ResourceLayout, LogStaticSamplerArrayError);
- if (StaticSamplerInd >= 0)
+ // Constructor of PipelineStateD3D11Impl initializes immutable samplers and will log the error, if any
+ constexpr bool LogImtblSamplerArrayError = false;
+ auto ImtblSamplerInd = m_pResources->FindImmutableSampler(Sampler, ResourceLayout, LogImtblSamplerArrayError);
+ if (ImtblSamplerInd >= 0)
{
- // Skip static samplers as they are initialized directly in the resource cache by the PSO
+ // Skip immutble samplers as they are initialized directly in the resource cache by the PSO
return;
}
// Initialize current sampler in place, increment sampler counter
@@ -241,10 +236,10 @@ ShaderResourceLayoutD3D11::ShaderResourceLayoutD3D11(IObject& AssignedSamplerIndex = TexSRVBindInfo::InvalidSamplerIndex;
#ifdef DILIGENT_DEBUG
// Shader error will be logged by the PipelineStateD3D11Impl
- constexpr bool LogStaticSamplerArrayError = false;
- if (m_pResources->FindStaticSampler(AssignedSamplerAttribs, ResourceLayout, LogStaticSamplerArrayError) < 0)
+ constexpr bool LogImtblSamplerArrayError = false;
+ if (m_pResources->FindImmutableSampler(AssignedSamplerAttribs, ResourceLayout, LogImtblSamplerArrayError) < 0)
{
- UNEXPECTED("Unable to find non-static sampler assigned to texture SRV '", TexSRV.Name, "'.");
+ UNEXPECTED("Unable to find non-immutable sampler assigned to texture SRV '", TexSRV.Name, "'.");
}
#endif
}
@@ -252,10 +247,10 @@ ShaderResourceLayoutD3D11::ShaderResourceLayoutD3D11(IObject& {
#ifdef DILIGENT_DEBUG
// Shader error will be logged by the PipelineStateD3D11Impl
- constexpr bool LogStaticSamplerArrayError = false;
- if (m_pResources->FindStaticSampler(AssignedSamplerAttribs, ResourceLayout, LogStaticSamplerArrayError) >= 0)
+ constexpr bool LogImtblSamplerArrayError = false;
+ if (m_pResources->FindImmutableSampler(AssignedSamplerAttribs, ResourceLayout, LogImtblSamplerArrayError) >= 0)
{
- UNEXPECTED("Static sampler '", AssignedSamplerAttribs.Name, "' is assigned to texture SRV '", TexSRV.Name, "'.");
+ UNEXPECTED("Immutable sampler '", AssignedSamplerAttribs.Name, "' is assigned to texture SRV '", TexSRV.Name, "'.");
}
#endif
}
@@ -412,7 +407,7 @@ void ShaderResourceLayoutD3D11::CopyResources(ShaderResourceCacheD3D11& DstCache [&](const SamplerBindInfo& sam) //
{
- //VERIFY(!sam.IsStaticSampler, "Variables are not created for static samplers");
+ //VERIFY(!sam.IsImmutableSampler, "Variables are not created for immutable samplers");
for (auto SamSlot = sam.m_Attribs.BindPoint; SamSlot < sam.m_Attribs.BindPoint + sam.m_Attribs.BindCount; ++SamSlot)
{
VERIFY_EXPR(SamSlot < m_ResourceCache.GetSamplerCount() && SamSlot < DstCache.GetSamplerCount());
@@ -429,7 +424,7 @@ void ShaderResourceLayoutD3D11::ConstBuffBindInfo::BindResource(IDeviceObject* p // We cannot use ValidatedCast<> here as the resource retrieved from the
// resource mapping can be of wrong type
- RefCntAutoPtr<BufferD3D11Impl> pBuffD3D11Impl(pBuffer, IID_BufferD3D11);
+ RefCntAutoPtr<BufferD3D11Impl> pBuffD3D11Impl{pBuffer, IID_BufferD3D11};
#ifdef DILIGENT_DEVELOPMENT
{
auto& CachedCB = m_ParentResLayout.m_ResourceCache.GetCB(m_Attribs.BindPoint + ArrayIndex);
@@ -448,18 +443,19 @@ void ShaderResourceLayoutD3D11::TexSRVBindInfo::BindResource(IDeviceObject* pVie // We cannot use ValidatedCast<> here as the resource retrieved from the
// resource mapping can be of wrong type
- RefCntAutoPtr<TextureViewD3D11Impl> pViewD3D11(pView, IID_TextureViewD3D11);
+ RefCntAutoPtr<TextureViewD3D11Impl> pViewD3D11{pView, IID_TextureViewD3D11};
#ifdef DILIGENT_DEVELOPMENT
{
auto& CachedSRV = ResourceCache.GetSRV(m_Attribs.BindPoint + ArrayIndex);
- VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewD3D11.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, CachedSRV.pView.RawPtr(), m_ParentResLayout.GetShaderName());
+ VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewD3D11.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE},
+ CachedSRV.pView.RawPtr(), m_ParentResLayout.GetShaderName());
}
#endif
if (ValidSamplerAssigned())
{
auto& Sampler = m_ParentResLayout.GetResource<SamplerBindInfo>(SamplerIndex);
- //VERIFY(!Sampler.IsStaticSampler, "Static samplers are not assigned to texture SRVs as they are initialized directly in the shader resource cache");
+ //VERIFY(!Sampler.IsImmutableSampler, "Immutable samplers are not assigned to texture SRVs as they are initialized directly in the shader resource cache");
VERIFY_EXPR(Sampler.m_Attribs.BindCount == m_Attribs.BindCount || Sampler.m_Attribs.BindCount == 1);
auto SamplerBindPoint = Sampler.m_Attribs.BindPoint + (Sampler.m_Attribs.BindCount != 1 ? ArrayIndex : 0);
@@ -501,11 +497,11 @@ void ShaderResourceLayoutD3D11::SamplerBindInfo::BindResource(IDeviceObject* pSa "Array index (", ArrayIndex, ") is out of range for variable '", m_Attribs.Name,
"'. Max allowed index: ", m_Attribs.BindCount - 1);
auto& ResourceCache = m_ParentResLayout.m_ResourceCache;
- //VERIFY(!IsStaticSampler, "Cannot bind sampler to a static sampler");
+ //VERIFY(!IsImmutableSampler, "Cannot bind sampler to an immutable sampler");
// We cannot use ValidatedCast<> here as the resource retrieved from the
// resource mapping can be of wrong type
- RefCntAutoPtr<SamplerD3D11Impl> pSamplerD3D11(pSampler, IID_SamplerD3D11);
+ RefCntAutoPtr<SamplerD3D11Impl> pSamplerD3D11{pSampler, IID_SamplerD3D11};
#ifdef DILIGENT_DEVELOPMENT
if (pSampler && !pSamplerD3D11)
@@ -548,11 +544,13 @@ void ShaderResourceLayoutD3D11::BuffSRVBindInfo::BindResource(IDeviceObject* pVi // We cannot use ValidatedCast<> here as the resource retrieved from the
// resource mapping can be of wrong type
- RefCntAutoPtr<BufferViewD3D11Impl> pViewD3D11(pView, IID_BufferViewD3D11);
+ RefCntAutoPtr<BufferViewD3D11Impl> pViewD3D11{pView, IID_BufferViewD3D11};
#ifdef DILIGENT_DEVELOPMENT
{
auto& CachedSRV = ResourceCache.GetSRV(m_Attribs.BindPoint + ArrayIndex);
- VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewD3D11.RawPtr(), {BUFFER_VIEW_SHADER_RESOURCE}, CachedSRV.pView.RawPtr(), m_ParentResLayout.GetShaderName());
+ VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewD3D11.RawPtr(), {BUFFER_VIEW_SHADER_RESOURCE},
+ CachedSRV.pView.RawPtr(), m_ParentResLayout.GetShaderName());
+ VerifyBufferViewModeD3D(pViewD3D11.RawPtr(), m_Attribs, m_ParentResLayout.GetShaderName());
}
#endif
ResourceCache.SetBufSRV(m_Attribs.BindPoint + ArrayIndex, std::move(pViewD3D11));
@@ -568,11 +566,12 @@ void ShaderResourceLayoutD3D11::TexUAVBindInfo::BindResource(IDeviceObject* pVie // We cannot use ValidatedCast<> here as the resource retrieved from the
// resource mapping can be of wrong type
- RefCntAutoPtr<TextureViewD3D11Impl> pViewD3D11(pView, IID_TextureViewD3D11);
+ RefCntAutoPtr<TextureViewD3D11Impl> pViewD3D11{pView, IID_TextureViewD3D11};
#ifdef DILIGENT_DEVELOPMENT
{
auto& CachedUAV = ResourceCache.GetUAV(m_Attribs.BindPoint + ArrayIndex);
- VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewD3D11.RawPtr(), {TEXTURE_VIEW_UNORDERED_ACCESS}, CachedUAV.pView.RawPtr(), m_ParentResLayout.GetShaderName());
+ VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewD3D11.RawPtr(), {TEXTURE_VIEW_UNORDERED_ACCESS},
+ CachedUAV.pView.RawPtr(), m_ParentResLayout.GetShaderName());
}
#endif
ResourceCache.SetTexUAV(m_Attribs.BindPoint + ArrayIndex, std::move(pViewD3D11));
@@ -588,11 +587,13 @@ void ShaderResourceLayoutD3D11::BuffUAVBindInfo::BindResource(IDeviceObject* pVi // We cannot use ValidatedCast<> here as the resource retrieved from the
// resource mapping can be of wrong type
- RefCntAutoPtr<BufferViewD3D11Impl> pViewD3D11(pView, IID_BufferViewD3D11);
+ RefCntAutoPtr<BufferViewD3D11Impl> pViewD3D11{pView, IID_BufferViewD3D11};
#ifdef DILIGENT_DEVELOPMENT
{
auto& CachedUAV = ResourceCache.GetUAV(m_Attribs.BindPoint + ArrayIndex);
- VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewD3D11.RawPtr(), {BUFFER_VIEW_UNORDERED_ACCESS}, CachedUAV.pView.RawPtr(), m_ParentResLayout.GetShaderName());
+ VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewD3D11.RawPtr(), {BUFFER_VIEW_UNORDERED_ACCESS},
+ CachedUAV.pView.RawPtr(), m_ParentResLayout.GetShaderName());
+ VerifyBufferViewModeD3D(pViewD3D11.RawPtr(), m_Attribs, m_ParentResLayout.GetShaderName());
}
#endif
ResourceCache.SetBufUAV(m_Attribs.BindPoint + ArrayIndex, std::move(pViewD3D11));
@@ -731,7 +732,7 @@ IShaderResourceVariable* ShaderResourceLayoutD3D11::GetShaderVariable(const Char if (!m_pResources->IsUsingCombinedTextureSamplers())
{
- // Static samplers are never created in the resource layout
+ // Immutable samplers are never created in the resource layout
if (auto* pSampler = GetResourceByName<SamplerBindInfo>(Name))
return pSampler;
}
diff --git a/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp index 7a744b57..0e9b217b 100644 --- a/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp @@ -51,8 +51,8 @@ TextureBaseD3D11::TextureBaseD3D11(IReferenceCounters* pRefCounters, } // clang-format on { - if (m_Desc.Usage == USAGE_STATIC && (pInitData == nullptr || pInitData->pSubResources == nullptr)) - LOG_ERROR_AND_THROW("Static textures must be initialized with data at creation time: pInitData can't be null"); + if (m_Desc.Usage == USAGE_IMMUTABLE && (pInitData == nullptr || pInitData->pSubResources == nullptr)) + LOG_ERROR_AND_THROW("Immutable textures must be initialized with data at creation time: pInitData can't be null"); SetState(RESOURCE_STATE_UNDEFINED); } diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp index a53a625d..fa761fc7 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<IPipelineStateD3D1 public: using TPipelineStateBase = PipelineStateBase<IPipelineStateD3D12, RenderDeviceD3D12Impl>; - 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; @@ -95,19 +97,19 @@ public: const ShaderResourceLayoutD3D12& GetShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < GetNumShaderStages()); return m_pShaderResourceLayouts[ShaderInd]; } const ShaderResourceLayoutD3D12& GetStaticShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return m_pShaderResourceLayouts[m_NumShaders + ShaderInd]; + VERIFY_EXPR(ShaderInd < GetNumShaderStages()); + return m_pShaderResourceLayouts[GetNumShaderStages() + ShaderInd]; } ShaderResourceCacheD3D12& GetStaticShaderResCache(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < GetNumShaderStages()); return m_pStaticResourceCaches[ShaderInd]; } @@ -119,15 +121,34 @@ public: } private: + struct D3D12PipelineShaderStageInfo + { + const SHADER_TYPE Type; + ShaderD3D12Impl* const pShader; + D3D12PipelineShaderStageInfo(SHADER_TYPE _Type, + ShaderD3D12Impl* _pShader) : + Type{_Type}, + pShader{_pShader} + {} + }; + + template <typename PSOCreateInfoType> + void InitInternalObjects(const PSOCreateInfoType& CreateInfo, std::vector<D3D12PipelineShaderStageInfo>& ShaderStages); + + void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + std::vector<D3D12PipelineShaderStageInfo>& ShaderStages); + + void Destruct(); + CComPtr<ID3D12PipelineState> 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 4dfc86c7..7bdc7801 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, @@ -174,6 +177,9 @@ public: D3D_FEATURE_LEVEL GetD3DFeatureLevel() const; private: + template <typename PSOCreateInfoType> + void CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState); + virtual void TestTextureFormat(TEXTURE_FORMAT TexFormat) override final; void FreeCommandContext(PooledCommandContext&& Ctx); diff --git a/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp b/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp index 2bf6d0b3..232bce65 100644 --- a/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp @@ -302,7 +302,7 @@ class RootSignature public: RootSignature(); - void AllocateStaticSamplers(const PipelineResourceLayoutDesc& ResourceLayout); + void AllocateImmutableSamplers(const PipelineResourceLayoutDesc& ResourceLayout); void Finalize(ID3D12Device* pd3d12Device); @@ -312,10 +312,10 @@ public: void InitResourceCache(class RenderDeviceD3D12Impl* pDeviceD3D12Impl, class ShaderResourceCacheD3D12& ResourceCache, IMemoryAllocator& CacheMemAllocator) const; - void InitStaticSampler(SHADER_TYPE ShaderType, - const char* SamplerName, - const char* SamplerSuffix, - const D3DShaderResourceAttribs& ShaderResAttribs); + void InitImmutableSampler(SHADER_TYPE ShaderType, + const char* SamplerName, + const char* SamplerSuffix, + const D3DShaderResourceAttribs& ShaderResAttribs); void AllocateResourceSlot(SHADER_TYPE ShaderType, PIPELINE_TYPE PipelineType, @@ -481,22 +481,22 @@ private: RootParamsManager m_RootParams; - struct StaticSamplerAttribs + struct ImmutableSamplerAttribs { - StaticSamplerDesc SamplerDesc; + ImmutableSamplerDesc SamplerDesc; UINT ShaderRegister = static_cast<UINT>(-1); UINT ArraySize = 0; UINT RegisterSpace = 0; D3D12_SHADER_VISIBILITY ShaderVisibility = static_cast<D3D12_SHADER_VISIBILITY>(-1); - StaticSamplerAttribs() noexcept {} - StaticSamplerAttribs(const StaticSamplerDesc& SamDesc, D3D12_SHADER_VISIBILITY Visibility) noexcept : + ImmutableSamplerAttribs() noexcept {} + ImmutableSamplerAttribs(const ImmutableSamplerDesc& SamDesc, D3D12_SHADER_VISIBILITY Visibility) noexcept : SamplerDesc(SamDesc), ShaderVisibility(Visibility) {} }; - // Note: sizeof(m_StaticSamplers) == 56 (MS compiler, release x64) - std::vector<StaticSamplerAttribs, STDAllocatorRawMem<StaticSamplerAttribs>> m_StaticSamplers; + // Note: sizeof(m_ImmutableSamplers) == 56 (MS compiler, release x64) + std::vector<ImmutableSamplerAttribs, STDAllocatorRawMem<ImmutableSamplerAttribs>> m_ImmutableSamplers; IMemoryAllocator& m_MemAllocator; diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp index 846cb329..7be3372d 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp @@ -78,6 +78,8 @@ public: } private: + void Destruct(); + ShaderResourceCacheD3D12 m_ShaderResourceCache; ShaderVariableManagerD3D12* m_pShaderVarMgrs = nullptr; diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp index 1a0362ab..8a8f7b25 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp @@ -110,7 +110,7 @@ public: SRBResources }; - ShaderResourceCacheD3D12(DbgCacheContentType dbgContentType) + ShaderResourceCacheD3D12(DbgCacheContentType dbgContentType) noexcept // clang-format off #ifdef DILIGENT_DEBUG : m_DbgContentType diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp index e043cf4a..719345fc 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp @@ -112,21 +112,24 @@ namespace Diligent class ShaderResourceLayoutD3D12 final { public: - // There are two modes a layout can be constructed: + explicit ShaderResourceLayoutD3D12(IObject& Owner) noexcept : + m_Owner{Owner} + {} + + // There are two modes a layout can be initialized: // - initialize static resource layout and initialize shader resource cache to hold static resources // - initialize reference layouts that address all types of resources (static, mutable, dynamic). // Root indices and descriptor table offsets are assigned during the initialization; // no shader resource cache is provided - ShaderResourceLayoutD3D12(IObject& Owner, - ID3D12Device* pd3d12Device, - PIPELINE_TYPE PipelineType, - const PipelineResourceLayoutDesc& ResourceLayout, - std::shared_ptr<const ShaderResourcesD3D12> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const SHADER_RESOURCE_VARIABLE_TYPE* const VarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheD3D12* pResourceCache, - class RootSignature* pRootSig); + void Initialize(ID3D12Device* pd3d12Device, + PIPELINE_TYPE PipelineType, + const PipelineResourceLayoutDesc& ResourceLayout, + std::shared_ptr<const ShaderResourcesD3D12> pSrcResources, + IMemoryAllocator& LayoutDataAllocator, + const SHADER_RESOURCE_VARIABLE_TYPE* const VarTypes, + Uint32 NumAllowedTypes, + ShaderResourceCacheD3D12* pResourceCache, + class RootSignature* pRootSig); // clang-format off ShaderResourceLayoutD3D12 (const ShaderResourceLayoutD3D12&) = delete; @@ -273,6 +276,8 @@ public: SHADER_TYPE GetShaderType() const { return m_pResources->GetShaderType(); } + const ShaderResourcesD3D12& GetResources() const { return *m_pResources; } + private: const D3D12Resource& GetAssignedSampler(const D3D12Resource& TexSrv) const; D3D12Resource& GetAssignedSampler(const D3D12Resource& TexSrv); diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderVariableD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderVariableD3D12.hpp index 213748d9..c30d8296 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderVariableD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderVariableD3D12.hpp @@ -76,12 +76,16 @@ class ShaderVariableD3D12Impl; class ShaderVariableManagerD3D12 { public: - ShaderVariableManagerD3D12(IObject& Owner, - const ShaderResourceLayoutD3D12& Layout, - IMemoryAllocator& Allocator, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheD3D12& ResourceCache); + ShaderVariableManagerD3D12(IObject& Owner, + ShaderResourceCacheD3D12& ResourceCache) noexcept : + m_Owner{Owner}, + m_ResourceCache{ResourceCache} + {} + + void Initialize(const ShaderResourceLayoutD3D12& Layout, + IMemoryAllocator& Allocator, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes); ~ShaderVariableManagerD3D12(); void Destroy(IMemoryAllocator& Allocator); @@ -120,7 +124,7 @@ private: Uint32 m_NumVariables = 0; #ifdef DILIGENT_DEBUG - IMemoryAllocator& m_DbgAllocator; + IMemoryAllocator* m_pDbgAllocator = nullptr; #endif // clang-format on }; diff --git a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp index c89a7423..d7cd54b6 100644 --- a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp @@ -68,8 +68,8 @@ BufferD3D12Impl::BufferD3D12Impl(IReferenceCounters* pRefCounters, LOG_ERROR_AND_THROW("Unified resources are not supported in Direct3D12"); } - if (m_Desc.Usage == USAGE_STATIC) - VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for static buffers"); + if (m_Desc.Usage == USAGE_IMMUTABLE) + VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for immutable buffers"); if (m_Desc.Usage == USAGE_DYNAMIC) VERIFY(pBuffData == nullptr || pBuffData->pData == nullptr, "Initial data must be null for dynamic buffers"); diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp index c833f68e..89c495b9 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp @@ -321,7 +321,7 @@ D3D12_STATIC_BORDER_COLOR BorderColorToD3D12StaticBorderColor(const Float32 Bord StaticBorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE; else { - LOG_ERROR_MESSAGE("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."); + LOG_ERROR_MESSAGE("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."); } return StaticBorderColor; } diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index af0b1113..b89b226c 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -211,49 +211,60 @@ 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 +975,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 138b6b3d..2d31e70d 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -98,155 +98,85 @@ private: std::array<D3D12_PRIMITIVE_TOPOLOGY_TYPE, PRIMITIVE_TOPOLOGY_NUM_TOPOLOGIES> m_Map; }; -PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, - RenderDeviceD3D12Impl* pDeviceD3D12, - const PipelineStateCreateInfo& CreateInfo) : - TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo.PSODesc}, - m_SRBMemAllocator{GetRawAllocator()} +template <typename PSOCreateInfoType> +void PipelineStateD3D12Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo, + std::vector<D3D12PipelineShaderStageInfo>& ShaderStages) { m_ResourceLayoutIndex.fill(-1); - auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); - const auto& ResourceLayout = m_Desc.ResourceLayout; - m_RootSig.AllocateStaticSamplers(ResourceLayout); - - { - auto& ShaderResLayoutAllocator = GetRawAllocator(); - m_pShaderResourceLayouts = ALLOCATE(ShaderResLayoutAllocator, "Raw memory for ShaderResourceLayoutD3D12", ShaderResourceLayoutD3D12, m_NumShaders * 2); - } - - { - auto& ShaderResCacheAllocator = GetRawAllocator(); - m_pStaticResourceCaches = ALLOCATE(ShaderResCacheAllocator, "Raw memory for ShaderResourceCacheD3D12", ShaderResourceCacheD3D12, m_NumShaders); - } - - { - auto& ShaderVarMgrAllocator = GetRawAllocator(); - m_pStaticVarManagers = ALLOCATE(ShaderVarMgrAllocator, "Raw memory for ShaderVariableManagerD3D12", ShaderVariableManagerD3D12, m_NumShaders); - } + ExtractShaders<ShaderD3D12Impl>(CreateInfo, ShaderStages); -#ifdef DILIGENT_DEVELOPMENT - { - const ShaderResources* pResources[MAX_SHADERS_IN_PIPELINE] = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - const auto* pShader = GetShader<const ShaderD3D12Impl>(s); - pResources[s] = &(*pShader->GetShaderResources()); - } - ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, m_NumShaders, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); - } -#endif + LinearAllocator MemPool{GetRawAllocator()}; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - auto* pShaderD3D12 = GetShader<ShaderD3D12Impl>(s); - auto ShaderType = pShaderD3D12->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); + const auto NumShaderStages = GetNumShaderStages(); + VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size()); - m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); + MemPool.AddSpace<ShaderResourceCacheD3D12>(NumShaderStages); + MemPool.AddSpace<ShaderResourceLayoutD3D12>(NumShaderStages * 2); + MemPool.AddSpace<ShaderVariableManagerD3D12>(NumShaderStages); - new (m_pShaderResourceLayouts + s) - ShaderResourceLayoutD3D12 // - { - *this, - pDeviceD3D12->GetD3D12Device(), - m_Desc.PipelineType, - ResourceLayout, - pShaderD3D12->GetShaderResources(), - GetRawAllocator(), - nullptr, - 0, - nullptr, - &m_RootSig // - }; + ReserveSpaceForPipelineDesc(CreateInfo, MemPool); - new (m_pStaticResourceCaches + s) ShaderResourceCacheD3D12{ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources}; + MemPool.Reserve(); - const SHADER_RESOURCE_VARIABLE_TYPE StaticVarType[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; - new (m_pShaderResourceLayouts + m_NumShaders + s) - ShaderResourceLayoutD3D12 // - { - *this, - pDeviceD3D12->GetD3D12Device(), - m_Desc.PipelineType, - ResourceLayout, - pShaderD3D12->GetShaderResources(), - GetRawAllocator(), - StaticVarType, - _countof(StaticVarType), - m_pStaticResourceCaches + s, - nullptr // - }; + m_pStaticResourceCaches = MemPool.ConstructArray<ShaderResourceCacheD3D12>(NumShaderStages, ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources); - new (m_pStaticVarManagers + s) - ShaderVariableManagerD3D12 // - { - *this, - GetStaticShaderResLayout(s), - GetRawAllocator(), - nullptr, - 0, - GetStaticShaderResCache(s) // - }; - } - m_RootSig.Finalize(pd3d12Device); + // The memory is now owned by PipelineStateD3D12Impl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_pStaticResourceCaches); + (void)Ptr; - switch (m_Desc.PipelineType) - { - case PIPELINE_TYPE_COMPUTE: - { - auto& ComputePipeline = m_Desc.ComputePipeline; + m_pShaderResourceLayouts = MemPool.ConstructArray<ShaderResourceLayoutD3D12>(NumShaderStages * 2, std::ref(*this)); - if (ComputePipeline.pCS == nullptr) - LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc"); + m_pStaticVarManagers = MemPool.Allocate<ShaderVariableManagerD3D12>(NumShaderStages); + for (Uint32 s = 0; s < NumShaderStages; ++s) + new (m_pStaticVarManagers + s) ShaderVariableManagerD3D12{*this, GetStaticShaderResCache(s)}; - D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {}; + InitializePipelineDesc(CreateInfo, MemPool); - auto* pByteCode = ValidatedCast<ShaderD3D12Impl>(ComputePipeline.pCS)->GetShaderByteCode(); - d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); - d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); + m_RootSig.AllocateImmutableSamplers(CreateInfo.PSODesc.ResourceLayout); - // 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; + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects - d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; - d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; + InitResourceLayouts(CreateInfo, ShaderStages); +} - // 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(); +PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDeviceD3D12, + const GraphicsPipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + try + { + std::vector<D3D12PipelineShaderStageInfo> ShaderStages; - HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(static_cast<ID3D12PipelineState**>(&m_pd3d12PSO))); - if (FAILED(hr)) - LOG_ERROR_AND_THROW("Failed to create pipeline state"); - break; - } + InitInternalObjects(CreateInfo, ShaderStages); - case PIPELINE_TYPE_GRAPHICS: + auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); + if (m_Desc.PipelineType == PIPELINE_TYPE_GRAPHICS) { - const auto& GraphicsPipeline = m_Desc.GraphicsPipeline; + const auto& GraphicsPipeline = GetGraphicsPipelineDesc(); D3D12_GRAPHICS_PIPELINE_STATE_DESC d3d12PSODesc = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (const auto& Stage : ShaderStages) { - auto* pShaderD3D12 = GetShader<ShaderD3D12Impl>(s); + 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 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"); } @@ -269,7 +199,7 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR std::vector<D3D12_INPUT_ELEMENT_DESC, STDAllocatorRawMem<D3D12_INPUT_ELEMENT_DESC>> d312InputElements(STD_ALLOCATOR_RAW_MEM(D3D12_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector<D3D12_INPUT_ELEMENT_DESC>")); - const auto& InputLayout = m_Desc.GraphicsPipeline.InputLayout; + const auto& InputLayout = GetGraphicsPipelineDesc().InputLayout; if (InputLayout.NumElements > 0) { LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(InputLayout, d312InputElements); @@ -310,13 +240,12 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR HRESULT hr = pd3d12Device->CreateGraphicsPipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(static_cast<ID3D12PipelineState**>(&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: + else if (m_Desc.PipelineType == PIPELINE_TYPE_MESH) { - const auto& GraphicsPipeline = m_Desc.GraphicsPipeline; + const auto& GraphicsPipeline = GetGraphicsPipelineDesc(); struct MESH_SHADER_PIPELINE_STATE_DESC { @@ -337,18 +266,19 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR }; MESH_SHADER_PIPELINE_STATE_DESC d3d12PSODesc = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (const auto& Stage : ShaderStages) { - auto* pShaderD3D12 = GetShader<ShaderD3D12Impl>(s); + 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 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"); } @@ -394,27 +324,192 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR 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: + 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()); + } + } + catch (...) + { + Destruct(); + throw; } +} - if (*m_Desc.Name != 0) +PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDeviceD3D12, + const ComputePipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + try { - 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()); + std::vector<D3D12PipelineShaderStageInfo> ShaderStages; + + InitInternalObjects(CreateInfo, ShaderStages); + + auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); + + 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<void**>(static_cast<ID3D12PipelineState**>(&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()); + } + } + catch (...) + { + Destruct(); + throw; + } +} + +PipelineStateD3D12Impl::~PipelineStateD3D12Impl() +{ + Destruct(); +} + +void PipelineStateD3D12Impl::Destruct() +{ + auto& ShaderResLayoutAllocator = GetRawAllocator(); + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) + { + if (m_pStaticVarManagers != nullptr) + { + m_pStaticVarManagers[s].Destroy(GetRawAllocator()); + m_pStaticVarManagers[s].~ShaderVariableManagerD3D12(); + } + + if (m_pShaderResourceLayouts != nullptr) + { + m_pShaderResourceLayouts[s].~ShaderResourceLayoutD3D12(); + m_pShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutD3D12(); + } + + if (m_pStaticResourceCaches != nullptr) + { + m_pStaticResourceCaches[s].~ShaderResourceCacheD3D12(); + } + } + // All internal objects are allocated in contiguous chunks of memory. + if (auto* pRawMem = m_pStaticResourceCaches) + { + ShaderResLayoutAllocator.Free(pRawMem); } + if (m_pd3d12PSO) + { + // 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::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + std::vector<D3D12PipelineShaderStageInfo>& ShaderStages) +{ + auto pd3d12Device = GetDevice()->GetD3D12Device(); + const auto& ResourceLayout = m_Desc.ResourceLayout; + +#ifdef DILIGENT_DEVELOPMENT + { + const ShaderResources* pResources[MAX_SHADERS_IN_PIPELINE] = {}; + for (size_t s = 0; s < ShaderStages.size(); ++s) + { + const auto* pShader = ShaderStages[s].pShader; + pResources[s] = &(*pShader->GetShaderResources()); + } + ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, GetNumShaderStages(), + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS) == 0); + } +#endif + + for (size_t s = 0; s < ShaderStages.size(); ++s) + { + auto* pShaderD3D12 = ShaderStages[s].pShader; + auto ShaderType = pShaderD3D12->GetDesc().ShaderType; + auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); + + m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); + + m_pShaderResourceLayouts[s].Initialize( + pd3d12Device, + m_Desc.PipelineType, + ResourceLayout, + pShaderD3D12->GetShaderResources(), + GetRawAllocator(), + nullptr, + 0, + nullptr, + &m_RootSig // + ); + + const SHADER_RESOURCE_VARIABLE_TYPE StaticVarType[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; + m_pShaderResourceLayouts[GetNumShaderStages() + s].Initialize( + pd3d12Device, + m_Desc.PipelineType, + ResourceLayout, + pShaderD3D12->GetShaderResources(), + GetRawAllocator(), + StaticVarType, + _countof(StaticVarType), + m_pStaticResourceCaches + s, + nullptr // + ); + + m_pStaticVarManagers[s].Initialize( + GetStaticShaderResLayout(static_cast<Uint32>(s)), + GetRawAllocator(), + nullptr, + 0 // + ); + } + m_RootSig.Finalize(pd3d12Device); + if (m_Desc.SRBAllocationGranularity > 1) { std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVarMgrDataSizes = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { std::array<SHADER_RESOURCE_VARIABLE_TYPE, 2> AllowedVarTypes = { @@ -427,34 +522,12 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR } auto CacheMemorySize = m_RootSig.GetResourceCacheRequiredMemSize(); - m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, m_NumShaders, ShaderVarMgrDataSizes.data(), 1, &CacheMemorySize); + m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderVarMgrDataSizes.data(), 1, &CacheMemorySize); } m_ShaderResourceLayoutHash = m_RootSig.GetHash(); } -PipelineStateD3D12Impl::~PipelineStateD3D12Impl() -{ - auto& ShaderResLayoutAllocator = GetRawAllocator(); - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - m_pStaticVarManagers[s].Destroy(GetRawAllocator()); - m_pStaticVarManagers[s].~ShaderVariableManagerD3D12(); - m_pStaticResourceCaches[s].~ShaderResourceCacheD3D12(); - m_pShaderResourceLayouts[s].~ShaderResourceLayoutD3D12(); - m_pShaderResourceLayouts[m_NumShaders + s].~ShaderResourceLayoutD3D12(); - } - ShaderResLayoutAllocator.Free(m_pStaticVarManagers); - ShaderResLayoutAllocator.Free(m_pStaticResourceCaches); - ShaderResLayoutAllocator.Free(m_pShaderResourceLayouts); - - // 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(); @@ -480,23 +553,22 @@ bool PipelineStateD3D12Impl::IsCompatibleWith(const IPipelineState* pPSO) const #ifdef DILIGENT_DEBUG { bool IsCompatibleShaders = true; - if (m_NumShaders != pPSOD3D12->m_NumShaders) + if (GetNumShaderStages() != pPSOD3D12->GetNumShaderStages()) IsCompatibleShaders = false; if (IsCompatibleShaders) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { - auto* pShader0 = GetShader<const ShaderD3D12Impl>(s); - auto* pShader1 = pPSOD3D12->GetShader<const ShaderD3D12Impl>(s); - if (pShader0->GetDesc().ShaderType != pShader1->GetDesc().ShaderType) + if (GetShaderStageType(s) != pPSOD3D12->GetShaderStageType(s)) { IsCompatibleShaders = false; break; } - const ShaderResourcesD3D12* pRes0 = pShader0->GetShaderResources().get(); - const ShaderResourcesD3D12* pRes1 = pShader1->GetShaderResources().get(); - if (!pRes0->IsCompatibleWith(*pRes1)) + + const auto& Res0 = GetShaderResLayout(s).GetResources(); + const auto& Res1 = pPSOD3D12->GetShaderResLayout(s).GetResources(); + if (!Res0.IsCompatibleWith(Res1)) { IsCompatibleShaders = false; break; @@ -607,7 +679,7 @@ bool PipelineStateD3D12Impl::ContainsShaderResources() const void PipelineStateD3D12Impl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { auto ShaderType = GetStaticShaderResLayout(s).GetShaderType(); if ((ShaderFlags & ShaderType) != 0) @@ -621,7 +693,7 @@ Uint32 PipelineStateD3D12Impl::GetStaticVariableCount(SHADER_TYPE ShaderType) co if (LayoutInd < 0) return 0; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderStages()); return m_pStaticVarManagers[LayoutInd].GetVariableCount(); } @@ -631,7 +703,7 @@ IShaderResourceVariable* PipelineStateD3D12Impl::GetStaticVariableByName(SHADER_ if (LayoutInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderStages()); return m_pStaticVarManagers[LayoutInd].GetVariable(Name); } @@ -641,7 +713,7 @@ IShaderResourceVariable* PipelineStateD3D12Impl::GetStaticVariableByIndex(SHADER if (LayoutInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < m_NumShaders); + VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderStages()); return m_pStaticVarManagers[LayoutInd].GetVariable(Index); } diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 6e4b828e..61ad5871 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -298,7 +298,7 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo #undef CHECK_REQUIRED_FEATURE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 31, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif auto& TexCaps = m_DeviceCaps.TexCaps; @@ -535,23 +535,35 @@ void RenderDeviceD3D12Impl::TestTextureFormat(TEXTURE_FORMAT TexFormat) IMPLEMENT_QUERY_INTERFACE(RenderDeviceD3D12Impl, IID_RenderDeviceD3D12, TRenderDeviceBase) -void RenderDeviceD3D12Impl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +template <typename PSOCreateInfoType> +void RenderDeviceD3D12Impl::CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState) { CreateDeviceObject("Pipeline State", PSOCreateInfo.PSODesc, ppPipelineState, [&]() // { - PipelineStateD3D12Impl* pPipelineStateD3D12(NEW_RC_OBJ(m_PSOAllocator, "PipelineStateD3D12Impl instance", PipelineStateD3D12Impl)(this, PSOCreateInfo)); + PipelineStateD3D12Impl* pPipelineStateD3D12{NEW_RC_OBJ(m_PSOAllocator, "PipelineStateD3D12Impl instance", PipelineStateD3D12Impl)(this, PSOCreateInfo)}; pPipelineStateD3D12->QueryInterface(IID_PipelineState, reinterpret_cast<IObject**>(ppPipelineState)); OnCreateDeviceObject(pPipelineStateD3D12); }); } + +void RenderDeviceD3D12Impl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState); +} + +void RenderDeviceD3D12Impl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState); +} + void RenderDeviceD3D12Impl::CreateBufferFromD3DResource(ID3D12Resource* pd3d12Buffer, const BufferDesc& BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) { CreateDeviceObject("buffer", BuffDesc, ppBuffer, [&]() // { - BufferD3D12Impl* pBufferD3D12(NEW_RC_OBJ(m_BufObjAllocator, "BufferD3D12Impl instance", BufferD3D12Impl)(m_BuffViewObjAllocator, this, BuffDesc, InitialState, pd3d12Buffer)); + BufferD3D12Impl* pBufferD3D12{NEW_RC_OBJ(m_BufObjAllocator, "BufferD3D12Impl instance", BufferD3D12Impl)(m_BuffViewObjAllocator, this, BuffDesc, InitialState, pd3d12Buffer)}; pBufferD3D12->QueryInterface(IID_Buffer, reinterpret_cast<IObject**>(ppBuffer)); pBufferD3D12->CreateDefaultViews(); OnCreateDeviceObject(pBufferD3D12); @@ -563,7 +575,7 @@ void RenderDeviceD3D12Impl::CreateBuffer(const BufferDesc& BuffDesc, const Buffe CreateDeviceObject("buffer", BuffDesc, ppBuffer, [&]() // { - BufferD3D12Impl* pBufferD3D12(NEW_RC_OBJ(m_BufObjAllocator, "BufferD3D12Impl instance", BufferD3D12Impl)(m_BuffViewObjAllocator, this, BuffDesc, pBuffData)); + BufferD3D12Impl* pBufferD3D12{NEW_RC_OBJ(m_BufObjAllocator, "BufferD3D12Impl instance", BufferD3D12Impl)(m_BuffViewObjAllocator, this, BuffDesc, pBuffData)}; pBufferD3D12->QueryInterface(IID_Buffer, reinterpret_cast<IObject**>(ppBuffer)); pBufferD3D12->CreateDefaultViews(); OnCreateDeviceObject(pBufferD3D12); @@ -576,7 +588,7 @@ void RenderDeviceD3D12Impl::CreateShader(const ShaderCreateInfo& ShaderCI, IShad CreateDeviceObject("shader", ShaderCI.Desc, ppShader, [&]() // { - ShaderD3D12Impl* pShaderD3D12(NEW_RC_OBJ(m_ShaderObjAllocator, "ShaderD3D12Impl instance", ShaderD3D12Impl)(this, ShaderCI)); + ShaderD3D12Impl* pShaderD3D12{NEW_RC_OBJ(m_ShaderObjAllocator, "ShaderD3D12Impl instance", ShaderD3D12Impl)(this, ShaderCI)}; pShaderD3D12->QueryInterface(IID_Shader, reinterpret_cast<IObject**>(ppShader)); OnCreateDeviceObject(pShaderD3D12); @@ -590,7 +602,7 @@ void RenderDeviceD3D12Impl::CreateTextureFromD3DResource(ID3D12Resource* pd3d12T CreateDeviceObject("texture", TexDesc, ppTexture, [&]() // { - TextureD3D12Impl* pTextureD3D12 = NEW_RC_OBJ(m_TexObjAllocator, "TextureD3D12Impl instance", TextureD3D12Impl)(m_TexViewObjAllocator, this, TexDesc, InitialState, pd3d12Texture); + TextureD3D12Impl* pTextureD3D12{NEW_RC_OBJ(m_TexObjAllocator, "TextureD3D12Impl instance", TextureD3D12Impl)(m_TexViewObjAllocator, this, TexDesc, InitialState, pd3d12Texture)}; pTextureD3D12->QueryInterface(IID_Texture, reinterpret_cast<IObject**>(ppTexture)); pTextureD3D12->CreateDefaultViews(); @@ -603,7 +615,7 @@ void RenderDeviceD3D12Impl::CreateTexture(const TextureDesc& TexDesc, ID3D12Reso CreateDeviceObject("texture", TexDesc, ppTexture, [&]() // { - TextureD3D12Impl* pTextureD3D12 = NEW_RC_OBJ(m_TexObjAllocator, "TextureD3D12Impl instance", TextureD3D12Impl)(m_TexViewObjAllocator, this, TexDesc, InitialState, pd3d12Texture); + TextureD3D12Impl* pTextureD3D12{NEW_RC_OBJ(m_TexObjAllocator, "TextureD3D12Impl instance", TextureD3D12Impl)(m_TexViewObjAllocator, this, TexDesc, InitialState, pd3d12Texture)}; pTextureD3D12->QueryInterface(IID_TextureD3D12, reinterpret_cast<IObject**>(ppTexture)); }); } @@ -613,7 +625,7 @@ void RenderDeviceD3D12Impl::CreateTexture(const TextureDesc& TexDesc, const Text CreateDeviceObject("texture", TexDesc, ppTexture, [&]() // { - TextureD3D12Impl* pTextureD3D12 = NEW_RC_OBJ(m_TexObjAllocator, "TextureD3D12Impl instance", TextureD3D12Impl)(m_TexViewObjAllocator, this, TexDesc, pData); + TextureD3D12Impl* pTextureD3D12{NEW_RC_OBJ(m_TexObjAllocator, "TextureD3D12Impl instance", TextureD3D12Impl)(m_TexViewObjAllocator, this, TexDesc, pData)}; pTextureD3D12->QueryInterface(IID_Texture, reinterpret_cast<IObject**>(ppTexture)); pTextureD3D12->CreateDefaultViews(); @@ -629,7 +641,7 @@ void RenderDeviceD3D12Impl::CreateSampler(const SamplerDesc& SamplerDesc, ISampl m_SamplersRegistry.Find(SamplerDesc, reinterpret_cast<IDeviceObject**>(ppSampler)); if (*ppSampler == nullptr) { - SamplerD3D12Impl* pSamplerD3D12(NEW_RC_OBJ(m_SamplerObjAllocator, "SamplerD3D12Impl instance", SamplerD3D12Impl)(this, SamplerDesc)); + SamplerD3D12Impl* pSamplerD3D12{NEW_RC_OBJ(m_SamplerObjAllocator, "SamplerD3D12Impl instance", SamplerD3D12Impl)(this, SamplerDesc)}; pSamplerD3D12->QueryInterface(IID_Sampler, reinterpret_cast<IObject**>(ppSampler)); OnCreateDeviceObject(pSamplerD3D12); m_SamplersRegistry.Add(SamplerDesc, *ppSampler); @@ -642,7 +654,7 @@ void RenderDeviceD3D12Impl::CreateFence(const FenceDesc& Desc, IFence** ppFence) CreateDeviceObject("Fence", Desc, ppFence, [&]() // { - FenceD3D12Impl* pFenceD3D12(NEW_RC_OBJ(m_FenceAllocator, "FenceD3D12Impl instance", FenceD3D12Impl)(this, Desc)); + FenceD3D12Impl* pFenceD3D12{NEW_RC_OBJ(m_FenceAllocator, "FenceD3D12Impl instance", FenceD3D12Impl)(this, Desc)}; pFenceD3D12->QueryInterface(IID_Fence, reinterpret_cast<IObject**>(ppFence)); OnCreateDeviceObject(pFenceD3D12); }); @@ -653,7 +665,7 @@ void RenderDeviceD3D12Impl::CreateQuery(const QueryDesc& Desc, IQuery** ppQuery) CreateDeviceObject("Query", Desc, ppQuery, [&]() // { - QueryD3D12Impl* pQueryD3D12(NEW_RC_OBJ(m_QueryAllocator, "QueryD3D12Impl instance", QueryD3D12Impl)(this, Desc)); + QueryD3D12Impl* pQueryD3D12{NEW_RC_OBJ(m_QueryAllocator, "QueryD3D12Impl instance", QueryD3D12Impl)(this, Desc)}; pQueryD3D12->QueryInterface(IID_Query, reinterpret_cast<IObject**>(ppQuery)); OnCreateDeviceObject(pQueryD3D12); }); @@ -664,7 +676,7 @@ void RenderDeviceD3D12Impl::CreateRenderPass(const RenderPassDesc& Desc, IRender CreateDeviceObject("RenderPass", Desc, ppRenderPass, [&]() // { - RenderPassD3D12Impl* pRenderPassD3D12(NEW_RC_OBJ(m_RenderPassAllocator, "RenderPassD3D12Impl instance", RenderPassD3D12Impl)(this, Desc)); + RenderPassD3D12Impl* pRenderPassD3D12{NEW_RC_OBJ(m_RenderPassAllocator, "RenderPassD3D12Impl instance", RenderPassD3D12Impl)(this, Desc)}; pRenderPassD3D12->QueryInterface(IID_RenderPass, reinterpret_cast<IObject**>(ppRenderPass)); OnCreateDeviceObject(pRenderPassD3D12); }); @@ -675,7 +687,7 @@ void RenderDeviceD3D12Impl::CreateFramebuffer(const FramebufferDesc& Desc, IFram CreateDeviceObject("Framebuffer", Desc, ppFramebuffer, [&]() // { - FramebufferD3D12Impl* pFramebufferD3D12(NEW_RC_OBJ(m_FramebufferAllocator, "FramebufferD3D12Impl instance", FramebufferD3D12Impl)(this, Desc)); + FramebufferD3D12Impl* pFramebufferD3D12{NEW_RC_OBJ(m_FramebufferAllocator, "FramebufferD3D12Impl instance", FramebufferD3D12Impl)(this, Desc)}; pFramebufferD3D12->QueryInterface(IID_Framebuffer, reinterpret_cast<IObject**>(ppFramebuffer)); OnCreateDeviceObject(pFramebufferD3D12); }); diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index bba639f8..2afb9eb1 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -166,7 +166,7 @@ size_t RootSignature::RootParamsManager::GetHash() const RootSignature::RootSignature() : m_RootParams{GetRawAllocator()}, m_MemAllocator{GetRawAllocator()}, - m_StaticSamplers(STD_ALLOCATOR_RAW_MEM(StaticSamplerAttribs, GetRawAllocator(), "Allocator for vector<StaticSamplerAttribs>")) + m_ImmutableSamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerAttribs, GetRawAllocator(), "Allocator for vector<ImmutableSamplerAttribs>")) { m_SrvCbvUavRootTablesMap.fill(InvalidRootTableIndex); m_SamplerRootTablesMap.fill(InvalidRootTableIndex); @@ -282,29 +282,30 @@ D3D12_DESCRIPTOR_HEAP_TYPE HeapTypeFromRangeType(D3D12_DESCRIPTOR_RANGE_TYPE Ran } -void RootSignature::InitStaticSampler(SHADER_TYPE ShaderType, - const char* SamplerName, - const char* SamplerSuffix, - const D3DShaderResourceAttribs& SamplerAttribs) +void RootSignature::InitImmutableSampler(SHADER_TYPE ShaderType, + const char* SamplerName, + const char* SamplerSuffix, + const D3DShaderResourceAttribs& SamplerAttribs) { auto ShaderVisibility = GetShaderVisibility(ShaderType); auto SamplerFound = false; - for (auto& StSmplr : m_StaticSamplers) + for (auto& ImtblSmplr : m_ImmutableSamplers) { - if (StSmplr.ShaderVisibility == ShaderVisibility && - StreqSuff(SamplerName, StSmplr.SamplerDesc.SamplerOrTextureName, SamplerSuffix)) + if (ImtblSmplr.ShaderVisibility == ShaderVisibility && + StreqSuff(SamplerName, ImtblSmplr.SamplerDesc.SamplerOrTextureName, SamplerSuffix)) { - StSmplr.ShaderRegister = SamplerAttribs.BindPoint; - StSmplr.ArraySize = SamplerAttribs.BindCount; - StSmplr.RegisterSpace = 0; - SamplerFound = true; + ImtblSmplr.ShaderRegister = SamplerAttribs.BindPoint; + ImtblSmplr.ArraySize = SamplerAttribs.BindCount; + ImtblSmplr.RegisterSpace = 0; + + SamplerFound = true; break; } } if (!SamplerFound) { - LOG_ERROR("Unable to find static sampler \'", SamplerName, '\''); + LOG_ERROR("Unable to find immutable sampler \'", SamplerName, '\''); } } @@ -446,19 +447,19 @@ void RootSignature::dbgVerifyRootParameters() const } #endif -void RootSignature::AllocateStaticSamplers(const PipelineResourceLayoutDesc& ResourceLayout) +void RootSignature::AllocateImmutableSamplers(const PipelineResourceLayoutDesc& ResourceLayout) { - if (ResourceLayout.NumStaticSamplers > 0) + if (ResourceLayout.NumImmutableSamplers > 0) { - m_StaticSamplers.reserve(ResourceLayout.NumStaticSamplers); - for (Uint32 sam = 0; sam < ResourceLayout.NumStaticSamplers; ++sam) + m_ImmutableSamplers.reserve(ResourceLayout.NumImmutableSamplers); + for (Uint32 sam = 0; sam < ResourceLayout.NumImmutableSamplers; ++sam) { - const auto& StSamDesc = ResourceLayout.StaticSamplers[sam]; - Uint32 ShaderStages = StSamDesc.ShaderStages; + const auto& ImtblSamDesc = ResourceLayout.ImmutableSamplers[sam]; + Uint32 ShaderStages = ImtblSamDesc.ShaderStages; while (ShaderStages != 0) { auto Stage = ShaderStages & ~(ShaderStages - 1); - m_StaticSamplers.emplace_back(StSamDesc, GetShaderVisibility(static_cast<SHADER_TYPE>(Stage))); + m_ImmutableSamplers.emplace_back(ImtblSamDesc, GetShaderVisibility(static_cast<SHADER_TYPE>(Stage))); ShaderStages &= ~Stage; } } @@ -516,19 +517,19 @@ void RootSignature::Finalize(ID3D12Device* pd3d12Device) rootSignatureDesc.pParameters = D3D12Parameters.size() ? D3D12Parameters.data() : nullptr; UINT TotalD3D12StaticSamplers = 0; - for (const auto& StSam : m_StaticSamplers) - TotalD3D12StaticSamplers += StSam.ArraySize; + for (const auto& ImtblSam : m_ImmutableSamplers) + TotalD3D12StaticSamplers += ImtblSam.ArraySize; rootSignatureDesc.NumStaticSamplers = TotalD3D12StaticSamplers; rootSignatureDesc.pStaticSamplers = nullptr; std::vector<D3D12_STATIC_SAMPLER_DESC, STDAllocatorRawMem<D3D12_STATIC_SAMPLER_DESC>> D3D12StaticSamplers(STD_ALLOCATOR_RAW_MEM(D3D12_STATIC_SAMPLER_DESC, GetRawAllocator(), "Allocator for vector<D3D12_STATIC_SAMPLER_DESC>")); D3D12StaticSamplers.reserve(TotalD3D12StaticSamplers); - if (!m_StaticSamplers.empty()) + if (!m_ImmutableSamplers.empty()) { - for (size_t s = 0; s < m_StaticSamplers.size(); ++s) + for (size_t s = 0; s < m_ImmutableSamplers.size(); ++s) { - const auto& StSmplrDesc = m_StaticSamplers[s]; - const auto& SamDesc = StSmplrDesc.SamplerDesc.Desc; - for (UINT ArrInd = 0; ArrInd < StSmplrDesc.ArraySize; ++ArrInd) + const auto& ImtblSmplrDesc = m_ImmutableSamplers[s]; + const auto& SamDesc = ImtblSmplrDesc.SamplerDesc.Desc; + for (UINT ArrInd = 0; ArrInd < ImtblSmplrDesc.ArraySize; ++ArrInd) { D3D12StaticSamplers.emplace_back( D3D12_STATIC_SAMPLER_DESC // @@ -543,18 +544,18 @@ void RootSignature::Finalize(ID3D12Device* pd3d12Device) BorderColorToD3D12StaticBorderColor(SamDesc.BorderColor), SamDesc.MinLOD, SamDesc.MaxLOD, - StSmplrDesc.ShaderRegister + ArrInd, - StSmplrDesc.RegisterSpace, - StSmplrDesc.ShaderVisibility // - } // + ImtblSmplrDesc.ShaderRegister + ArrInd, + ImtblSmplrDesc.RegisterSpace, + ImtblSmplrDesc.ShaderVisibility // + } // ); } } rootSignatureDesc.pStaticSamplers = D3D12StaticSamplers.data(); - // Release static samplers array, we no longer need it - std::vector<StaticSamplerAttribs, STDAllocatorRawMem<StaticSamplerAttribs>> EmptySamplers(STD_ALLOCATOR_RAW_MEM(StaticSamplerAttribs, GetRawAllocator(), "Allocator for vector<StaticSamplerAttribs>")); - m_StaticSamplers.swap(EmptySamplers); + // Release immutable samplers array, we no longer need it + std::vector<ImmutableSamplerAttribs, STDAllocatorRawMem<ImmutableSamplerAttribs>> EmptySamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerAttribs, GetRawAllocator(), "Allocator for vector<ImmutableSamplerAttribs>")); + m_ImmutableSamplers.swap(EmptySamplers); VERIFY_EXPR(D3D12StaticSamplers.size() == TotalD3D12StaticSamplers); } @@ -640,7 +641,7 @@ void RootSignature::InitResourceCache(RenderDeviceD3D12Impl* pDeviceD3D12Impl DEV_CHECK_ERR(!SamplerHeapSpace.IsNull(), "Failed to allocate ", TotalSamplerDescriptors, " GPU-visible Sampler descriptor", (TotalSamplerDescriptors > 1 ? "s" : ""), - ". Consider using static samplers in the Pipeline State Object or " + ". Consider using immutable samplers in the Pipeline State Object or " "increasing GPUDescriptorHeapSize[1] in EngineD3D12CreateInfo."); } VERIFY_EXPR(TotalSamplerDescriptors == 0 && SamplerHeapSpace.IsNull() || SamplerHeapSpace.GetNumHandles() == TotalSamplerDescriptors); @@ -965,7 +966,7 @@ void RootSignature::CommitDescriptorHandlesInternal_SMD(RenderDeviceD3D12Impl* DEV_CHECK_ERR(DynamicSamplerDescriptors.GetDescriptorHeap() != nullptr, "Failed to allocate ", NumDynamicSamplerDescriptors, " dynamic GPU-visible Sampler descriptor", (NumDynamicSamplerDescriptors > 1 ? "s" : ""), - ". Consider using static samplers in the Pipeline State Object, increasing GPUDescriptorHeapDynamicSize[1] in " + ". Consider using immutable samplers in the Pipeline State Object, increasing GPUDescriptorHeapDynamicSize[1] in " "EngineD3D12CreateInfo, or optimizing dynamic resource utilization by using static or mutable shader resource variables instead."); } diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp index 257a4688..1511bd01 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp @@ -30,6 +30,7 @@ #include "PipelineStateD3D12Impl.hpp" #include "ShaderD3D12Impl.hpp" #include "RenderDeviceD3D12Impl.hpp" +#include "LinearAllocator.hpp" namespace Diligent { @@ -45,56 +46,76 @@ ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounter IsPSOInternal }, m_ShaderResourceCache{ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources}, - m_NumShaders {static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaders())} + m_NumShaders {static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaderStages())} // clang-format on { - m_ResourceLayoutIndex.fill(-1); - auto* ppShaders = pPSO->GetShaders(); + try + { + m_ResourceLayoutIndex.fill(-1); - auto* pRenderDeviceD3D12Impl = ValidatedCast<RenderDeviceD3D12Impl>(pPSO->GetDevice()); - auto& ResCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0); - pPSO->GetRootSignature().InitResourceCache(pRenderDeviceD3D12Impl, m_ShaderResourceCache, ResCacheDataAllocator); + LinearAllocator MemPool{GetRawAllocator()}; + MemPool.AddSpace<ShaderVariableManagerD3D12>(m_NumShaders); + MemPool.Reserve(); + m_pShaderVarMgrs = MemPool.ConstructArray<ShaderVariableManagerD3D12>(m_NumShaders, std::ref(*this), std::ref(m_ShaderResourceCache)); - m_pShaderVarMgrs = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerD3D12", ShaderVariableManagerD3D12, m_NumShaders); + // The memory is now owned by ShaderResourceBindingD3D12Impl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_pShaderVarMgrs); + (void)Ptr; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - auto* pShader = ppShaders[s]; - auto ShaderType = pShader->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPSO->GetDesc().PipelineType); - - auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); - - // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object - const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; - const auto& SrcLayout = pPSO->GetShaderResLayout(s); - // Create shader variable manager in place - new (m_pShaderVarMgrs + s) - ShaderVariableManagerD3D12 // - { - *this, + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects + + auto* pRenderDeviceD3D12Impl = ValidatedCast<RenderDeviceD3D12Impl>(pPSO->GetDevice()); + auto& ResCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0); + pPSO->GetRootSignature().InitResourceCache(pRenderDeviceD3D12Impl, m_ShaderResourceCache, ResCacheDataAllocator); + + for (Uint32 s = 0; s < m_NumShaders; ++s) + { + const auto ShaderType = pPSO->GetShaderStageType(s); + const auto& SrcLayout = pPSO->GetShaderResLayout(s); + const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPSO->GetDesc().PipelineType); + + auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); + + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object + const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + m_pShaderVarMgrs[s].Initialize( SrcLayout, VarDataAllocator, AllowedVarTypes, - _countof(AllowedVarTypes), - m_ShaderResourceCache // - }; + _countof(AllowedVarTypes) // + ); - m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); + m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); + } + } + catch (...) + { + Destruct(); + throw; } } + ShaderResourceBindingD3D12Impl::~ShaderResourceBindingD3D12Impl() { - auto* pPSO = ValidatedCast<PipelineStateD3D12Impl>(m_pPSO); - for (Uint32 s = 0; s < m_NumShaders; ++s) + Destruct(); +} + +void ShaderResourceBindingD3D12Impl::Destruct() +{ + if (m_pShaderVarMgrs != nullptr) { - auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); - m_pShaderVarMgrs[s].Destroy(VarDataAllocator); - m_pShaderVarMgrs[s].~ShaderVariableManagerD3D12(); + auto& SRBMemAllocator = m_pPSO->GetSRBMemoryAllocator(); + for (Uint32 s = 0; s < m_NumShaders; ++s) + { + auto& VarDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s); + m_pShaderVarMgrs[s].Destroy(VarDataAllocator); + m_pShaderVarMgrs[s].~ShaderVariableManagerD3D12(); + } + GetRawAllocator().Free(m_pShaderVarMgrs); } - - GetRawAllocator().Free(m_pShaderVarMgrs); } IMPLEMENT_QUERY_INTERFACE(ShaderResourceBindingD3D12Impl, IID_ShaderResourceBindingD3D12, TBase) @@ -189,20 +210,20 @@ void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const IPipelineSt } auto* pPSO12 = ValidatedCast<const PipelineStateD3D12Impl>(pPSO); - auto NumShaders = pPSO12->GetNumShaders(); + auto NumShaders = pPSO12->GetNumShaderStages(); // Copy static resources for (Uint32 s = 0; s < NumShaders; ++s) { const auto& ShaderResLayout = pPSO12->GetShaderResLayout(s); auto& StaticResLayout = pPSO12->GetStaticShaderResLayout(s); auto& StaticResCache = pPSO12->GetStaticShaderResCache(s); + #ifdef DILIGENT_DEVELOPMENT if (!StaticResLayout.dvpVerifyBindings(StaticResCache)) { - auto* pShader = pPSO12->GetShader<ShaderD3D12Impl>(s); LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", pPSO12->GetDesc().Name, - "' will not be successfully initialized because not all static resource bindings in shader '", - pShader->GetDesc().Name, + "' will not be successfully initialized because not all static resource bindings in shader type '", + GetShaderTypeLiteralName(pPSO12->GetShaderStageType(s)), "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method."); } diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp index 6c313882..c0428e7e 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp @@ -38,6 +38,7 @@ #include "RootSignature.hpp" #include "PipelineStateD3D12Impl.hpp" #include "ShaderResourceVariableBase.hpp" +#include "ShaderVariableD3DBase.hpp" namespace Diligent { @@ -112,22 +113,19 @@ void ShaderResourceLayoutD3D12::AllocateMemory(IMemoryAllocator& // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-Shader-Resource-Layouts-in-a-Pipeline-State -ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject& Owner, - ID3D12Device* pd3d12Device, - PIPELINE_TYPE PipelineType, - const PipelineResourceLayoutDesc& ResourceLayout, - std::shared_ptr<const ShaderResourcesD3D12> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const SHADER_RESOURCE_VARIABLE_TYPE* const AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheD3D12* pResourceCache, - RootSignature* pRootSig) : - // clang-format off - m_Owner {Owner}, - m_pd3d12Device {pd3d12Device}, - m_pResources {std::move(pSrcResources)} -// clang-format on +void ShaderResourceLayoutD3D12::Initialize(ID3D12Device* pd3d12Device, + PIPELINE_TYPE PipelineType, + const PipelineResourceLayoutDesc& ResourceLayout, + std::shared_ptr<const ShaderResourcesD3D12> pSrcResources, + IMemoryAllocator& LayoutDataAllocator, + const SHADER_RESOURCE_VARIABLE_TYPE* const AllowedVarTypes, + Uint32 NumAllowedTypes, + ShaderResourceCacheD3D12* pResourceCache, + RootSignature* pRootSig) { + m_pd3d12Device = pd3d12Device; + m_pResources = std::move(pSrcResources); + VERIFY_EXPR((pResourceCache != nullptr) ^ (pRootSig != nullptr)); const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); @@ -148,10 +146,11 @@ ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject& auto VarType = m_pResources->FindVariableType(Sam, ResourceLayout); if (IsAllowedType(VarType, AllowedTypeBits)) { - constexpr bool LogStaticSamplerArrayError = true; - auto StaticSamplerInd = m_pResources->FindStaticSampler(Sam, ResourceLayout, LogStaticSamplerArrayError); - // Skip static samplers - if (StaticSamplerInd < 0) + constexpr bool LogImtblSamplerArrayError = true; + + auto ImtblSamplerInd = m_pResources->FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError); + // Skip immutable samplers + if (ImtblSamplerInd < 0) ++SamplerCount[VarType]; } }, @@ -236,7 +235,7 @@ ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject& VERIFY(RootIndex != D3D12Resource::InvalidRootIndex, "Root index must be valid"); VERIFY(Offset != D3D12Resource::InvalidOffset, "Offset must be valid"); - // Static samplers are never copied, and SamplerId == InvalidSamplerId + // Immutable samplers are never copied, and SamplerId == InvalidSamplerId auto& NewResource = (ResType == CachedResourceType::Sampler) ? GetSampler(VarType, CurrSampler[VarType]++) : GetSrvCbvUav(VarType, CurrCbvSrvUav[VarType]++); @@ -257,12 +256,13 @@ ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject& if (IsAllowedType(VarType, AllowedTypeBits)) { // The error (if any) have already been logged when counting the resources - constexpr bool LogStaticSamplerArrayError = false; - auto StaticSamplerInd = m_pResources->FindStaticSampler(Sam, ResourceLayout, LogStaticSamplerArrayError); - if (StaticSamplerInd >= 0) + constexpr bool LogImtblSamplerArrayError = false; + + auto ImtblSamplerInd = m_pResources->FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError); + if (ImtblSamplerInd >= 0) { if (pRootSig != nullptr) - pRootSig->InitStaticSampler(m_pResources->GetShaderType(), Sam.Name, m_pResources->GetCombinedSamplerSuffix(), Sam); + pRootSig->InitImmutableSampler(m_pResources->GetShaderType(), Sam.Name, m_pResources->GetCombinedSamplerSuffix(), Sam); } else { @@ -289,18 +289,19 @@ ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject& ") of the sampler '", SamplerAttribs.Name, "' that is assigned to it"); // The error (if any) have already been logged when counting the resources - constexpr bool LogStaticSamplerArrayError = false; - auto StaticSamplerInd = m_pResources->FindStaticSampler(SamplerAttribs, ResourceLayout, LogStaticSamplerArrayError); - if (StaticSamplerInd >= 0) + constexpr bool LogImtblSamplerArrayError = false; + + auto ImtblSamplerInd = m_pResources->FindImmutableSampler(SamplerAttribs, ResourceLayout, LogImtblSamplerArrayError); + if (ImtblSamplerInd >= 0) { - // Static samplers are never copied, and SamplerId == InvalidSamplerId + // Immutable samplers are never copied, and SamplerId == InvalidSamplerId #ifdef DILIGENT_DEBUG auto SamplerCount = GetTotalSamplerCount(); for (Uint32 s = 0; s < SamplerCount; ++s) { const auto& Sampler = GetSampler(s); if (strcmp(Sampler.Attribs.Name, SamplerAttribs.Name) == 0) - LOG_ERROR("Static sampler '", Sampler.Attribs.Name, "' was found among resources. This seems to be a bug"); + LOG_ERROR("Immutable sampler '", Sampler.Attribs.Name, "' was found among resources. This seems to be a bug"); } #endif } @@ -429,6 +430,11 @@ template <> struct ResourceViewTraits<ITextureViewD3D12> { static const INTERFACE_ID& IID; + + static bool VerifyView(ITextureViewD3D12* pViewD3D12, const D3DShaderResourceAttribs& Attribs, const char* ShaderName) + { + return true; + } }; const INTERFACE_ID& ResourceViewTraits<ITextureViewD3D12>::IID = IID_TextureViewD3D12; @@ -436,6 +442,11 @@ template <> struct ResourceViewTraits<IBufferViewD3D12> { static const INTERFACE_ID& IID; + + static bool VerifyView(IBufferViewD3D12* pViewD3D12, const D3DShaderResourceAttribs& Attribs, const char* ShaderName) + { + return VerifyBufferViewModeD3D(pViewD3D12, Attribs, ShaderName); + } }; const INTERFACE_ID& ResourceViewTraits<IBufferViewD3D12>::IID = IID_BufferViewD3D12; @@ -451,9 +462,10 @@ void ShaderResourceLayoutD3D12::D3D12Resource::CacheResourceView(IDeviceObject* { // We cannot use ValidatedCast<> here as the resource retrieved from the // resource mapping can be of wrong type - RefCntAutoPtr<TResourceViewType> pViewD3D12(pView, ResourceViewTraits<TResourceViewType>::IID); + RefCntAutoPtr<TResourceViewType> pViewD3D12{pView, ResourceViewTraits<TResourceViewType>::IID}; #ifdef DILIGENT_DEVELOPMENT VerifyResourceViewBinding(Attribs, GetVariableType(), ArrayIndex, pView, pViewD3D12.RawPtr(), {dbgExpectedViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); + ResourceViewTraits<TResourceViewType>::VerifyView(pViewD3D12, Attribs, ParentResLayout.GetShaderName()); #endif if (pViewD3D12) { @@ -607,7 +619,7 @@ void ShaderResourceLayoutD3D12::D3D12Resource::BindResource(IDeviceObject* if (ValidSamplerAssigned()) { auto& Sam = ParentResLayout.GetAssignedSampler(*this); - //VERIFY( !Sam.Attribs.IsStaticSampler(), "Static samplers should never be assigned space in the cache" ); + //VERIFY( !Sam.Attribs.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache" ); VERIFY_EXPR(Attribs.BindCount == Sam.Attribs.BindCount || Sam.Attribs.BindCount == 1); auto SamplerArrInd = Sam.Attribs.BindCount > 1 ? ArrayIndex : 0; @@ -781,7 +793,7 @@ void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderR { const auto& SamInfo = DstLayout.GetAssignedSampler(res); - //VERIFY(!SamInfo.Attribs.IsStaticSampler(), "Static samplers should never be assigned space in the cache"); + //VERIFY(!SamInfo.Attribs.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache"); VERIFY(SamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid"); VERIFY_EXPR(SamInfo.Attribs.BindCount == res.Attribs.BindCount || SamInfo.Attribs.BindCount == 1); @@ -908,7 +920,7 @@ bool ShaderResourceLayoutD3D12::dvpVerifyBindings(const ShaderResourceCacheD3D12 { VERIFY(res.GetResType() == CachedResourceType::TexSRV, "Sampler can only be assigned to a texture SRV"); const auto& SamInfo = GetAssignedSampler(res); - //VERIFY(!SamInfo.Attribs.IsStaticSampler(), "Static samplers should never be assigned space in the cache" ); + //VERIFY(!SamInfo.Attribs.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache" ); VERIFY(SamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid"); for (Uint32 ArrInd = 0; ArrInd < SamInfo.Attribs.BindCount; ++ArrInd) diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderVariableD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderVariableD3D12.cpp index f7c23096..fd58eacf 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderVariableD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderVariableD3D12.cpp @@ -54,20 +54,15 @@ size_t ShaderVariableManagerD3D12::GetRequiredMemorySize(const ShaderResourceLay } // Creates shader variable for every resource from SrcLayout whose type is one AllowedVarTypes -ShaderVariableManagerD3D12::ShaderVariableManagerD3D12(IObject& Owner, - const ShaderResourceLayoutD3D12& SrcLayout, - IMemoryAllocator& Allocator, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheD3D12& ResourceCache) : - // clang-format off - m_Owner {Owner}, - m_ResourceCache {ResourceCache} +void ShaderVariableManagerD3D12::Initialize(const ShaderResourceLayoutD3D12& SrcLayout, + IMemoryAllocator& Allocator, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes) +{ #ifdef DILIGENT_DEBUG - , m_DbgAllocator {Allocator} + m_pDbgAllocator = &Allocator; #endif -// clang-format on -{ + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); VERIFY_EXPR(m_NumVariables == 0); auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, m_NumVariables); @@ -113,10 +108,10 @@ ShaderVariableManagerD3D12::~ShaderVariableManagerD3D12() void ShaderVariableManagerD3D12::Destroy(IMemoryAllocator& Allocator) { - VERIFY(&m_DbgAllocator == &Allocator, "Incosistent alloctor"); - if (m_pVariables != nullptr) { + VERIFY(m_pDbgAllocator == &Allocator, "Incosistent alloctor"); + for (Uint32 v = 0; v < m_NumVariables; ++v) m_pVariables[v].~ShaderVariableD3D12Impl(); Allocator.Free(m_pVariables); diff --git a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp index a4033f51..22829770 100644 --- a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp @@ -135,8 +135,8 @@ TextureD3D12Impl::TextureD3D12Impl(IReferenceCounters* pRefCounters, const TextureData* pInitData /*= nullptr*/) : TTextureBase{pRefCounters, TexViewObjAllocator, pRenderDeviceD3D12, TexDesc} { - if (m_Desc.Usage == USAGE_STATIC && (pInitData == nullptr || pInitData->pSubResources == nullptr)) - LOG_ERROR_AND_THROW("Static textures must be initialized with data at creation time: pInitData can't be null"); + if (m_Desc.Usage == USAGE_IMMUTABLE && (pInitData == nullptr || pInitData->pSubResources == nullptr)) + LOG_ERROR_AND_THROW("Immutable textures must be initialized with data at creation time: pInitData can't be null"); if ((m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0) { @@ -149,7 +149,7 @@ TextureD3D12Impl::TextureD3D12Impl(IReferenceCounters* pRefCounters, D3D12_RESOURCE_DESC Desc = GetD3D12TextureDesc(); auto* pd3d12Device = pRenderDeviceD3D12->GetD3D12Device(); - if (m_Desc.Usage == USAGE_STATIC || m_Desc.Usage == USAGE_DEFAULT || m_Desc.Usage == USAGE_DYNAMIC) + if (m_Desc.Usage == USAGE_IMMUTABLE || m_Desc.Usage == USAGE_DEFAULT || m_Desc.Usage == USAGE_DYNAMIC) { D3D12_CLEAR_VALUE ClearValue = {}; D3D12_CLEAR_VALUE* pClearValue = nullptr; diff --git a/Graphics/GraphicsEngineD3DBase/include/RenderDeviceD3DBase.hpp b/Graphics/GraphicsEngineD3DBase/include/RenderDeviceD3DBase.hpp index 104533c9..ea4a43bb 100644 --- a/Graphics/GraphicsEngineD3DBase/include/RenderDeviceD3DBase.hpp +++ b/Graphics/GraphicsEngineD3DBase/include/RenderDeviceD3DBase.hpp @@ -160,6 +160,7 @@ public: auto& Features = this->m_DeviceCaps.Features; Features.SeparablePrograms = DEVICE_FEATURE_STATE_ENABLED; + Features.ShaderResourceQueries = DEVICE_FEATURE_STATE_ENABLED; Features.IndirectRendering = DEVICE_FEATURE_STATE_ENABLED; Features.WireframeFill = DEVICE_FEATURE_STATE_ENABLED; Features.MultithreadedResourceCreation = DEVICE_FEATURE_STATE_ENABLED; diff --git a/Graphics/GraphicsEngineD3DBase/include/ShaderResources.hpp b/Graphics/GraphicsEngineD3DBase/include/ShaderResources.hpp index b5446ec3..efbff703 100644 --- a/Graphics/GraphicsEngineD3DBase/include/ShaderResources.hpp +++ b/Graphics/GraphicsEngineD3DBase/include/ShaderResources.hpp @@ -192,6 +192,10 @@ public: return static_cast<D3D_SRV_DIMENSION>(SRVDimension); } + RESOURCE_DIMENSION GetResourceDimension() const; + + bool IsMultisample() const; + bool IsCombinedWithSampler() const { return GetCombinedSamplerId() != InvalidSamplerId; @@ -368,20 +372,20 @@ public: SHADER_RESOURCE_VARIABLE_TYPE FindVariableType(const D3DShaderResourceAttribs& ResourceAttribs, const PipelineResourceLayoutDesc& ResourceLayout) const; - Int32 FindStaticSampler(const D3DShaderResourceAttribs& ResourceAttribs, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - bool LogStaticSamplerArrayError) const; + Int32 FindImmutableSampler(const D3DShaderResourceAttribs& ResourceAttribs, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + bool LogImmutableSamplerArrayError) const; D3DShaderResourceCounters CountResources(const PipelineResourceLayoutDesc& ResourceLayout, const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, Uint32 NumAllowedTypes, - bool CountStaticSamplers) const noexcept; + bool CountImmutableSamplers) const noexcept; #ifdef DILIGENT_DEVELOPMENT static void DvpVerifyResourceLayout(const PipelineResourceLayoutDesc& ResourceLayout, const ShaderResources* const pShaderResources[], Uint32 NumShaders, bool VerifyVariables, - bool VerifyStaticSamplers); + bool VerifyImmutableSamplers) noexcept; #endif void GetShaderModel(Uint32& Major, Uint32& Minor) const diff --git a/Graphics/GraphicsEngineD3DBase/include/ShaderVariableD3DBase.hpp b/Graphics/GraphicsEngineD3DBase/include/ShaderVariableD3DBase.hpp index 0ea6e397..2497b17d 100644 --- a/Graphics/GraphicsEngineD3DBase/include/ShaderVariableD3DBase.hpp +++ b/Graphics/GraphicsEngineD3DBase/include/ShaderVariableD3DBase.hpp @@ -86,4 +86,53 @@ protected: const SHADER_RESOURCE_VARIABLE_TYPE m_VariableType; }; + +template <typename BufferViewImplType> +bool VerifyBufferViewModeD3D(BufferViewImplType* pViewD3D11, const D3DShaderResourceAttribs& Attribs, const char* ShaderName) +{ + if (pViewD3D11 == nullptr) + return true; + + const auto& ViewDesc = pViewD3D11->GetDesc(); + const auto& BuffDesc = pViewD3D11->GetBuffer()->GetDesc(); + + auto LogBufferBindingError = [&](const char* Msg) // + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, + "' to shader variable '", Attribs.Name, "' in shader '", ShaderName, "': ", Msg); + }; + + switch (Attribs.GetInputType()) + { + case D3D_SIT_TEXTURE: + case D3D_SIT_UAV_RWTYPED: + if (BuffDesc.Mode != BUFFER_MODE_FORMATTED || ViewDesc.Format.ValueType == VT_UNDEFINED) + { + LogBufferBindingError("formatted buffer view is expected."); + return false; + } + break; + + case D3D_SIT_STRUCTURED: + case D3D_SIT_UAV_RWSTRUCTURED: + if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED) + { + LogBufferBindingError("structured buffer view is expected."); + return false; + } + break; + + case D3D_SIT_BYTEADDRESS: + case D3D_SIT_UAV_RWBYTEADDRESS: + if (BuffDesc.Mode != BUFFER_MODE_RAW) + { + LogBufferBindingError("raw buffer view is expected."); + return false; + } + break; + } + + return true; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp b/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp index 75ec17ea..b975b506 100644 --- a/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp +++ b/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp @@ -122,44 +122,44 @@ SHADER_RESOURCE_VARIABLE_TYPE ShaderResources::FindVariableType(const D3DShaderR } } -Int32 ShaderResources::FindStaticSampler(const D3DShaderResourceAttribs& ResourceAttribs, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - bool LogStaticSamplerArrayError) const +Int32 ShaderResources::FindImmutableSampler(const D3DShaderResourceAttribs& ResourceAttribs, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + bool LogImmutableSamplerArrayError) const { VERIFY(ResourceAttribs.GetInputType() == D3D_SIT_SAMPLER, "Sampler is expected"); - auto StaticSamplerInd = - Diligent::FindStaticSampler(ResourceLayoutDesc.StaticSamplers, - ResourceLayoutDesc.NumStaticSamplers, - m_ShaderType, - ResourceAttribs.Name, - m_SamplerSuffix); + auto ImtblSamplerInd = + Diligent::FindImmutableSampler(ResourceLayoutDesc.ImmutableSamplers, + ResourceLayoutDesc.NumImmutableSamplers, + m_ShaderType, + ResourceAttribs.Name, + m_SamplerSuffix); - if (StaticSamplerInd >= 0 && ResourceAttribs.BindCount > 1) + if (ImtblSamplerInd >= 0 && ResourceAttribs.BindCount > 1) { Uint32 ShaderMajorVersion = 0; Uint32 ShaderMinorVersion = 0; GetShaderModel(ShaderMajorVersion, ShaderMinorVersion); if (ShaderMajorVersion >= 6 || ShaderMajorVersion >= 5 && ShaderMinorVersion >= 1) { - if (LogStaticSamplerArrayError) + if (LogImmutableSamplerArrayError) { - LOG_ERROR_MESSAGE("Static sampler '", ResourceAttribs.Name, '[', ResourceAttribs.BindCount, + LOG_ERROR_MESSAGE("Immutable sampler '", ResourceAttribs.Name, '[', ResourceAttribs.BindCount, "]' will be ignored because static sampler arrays are not allowed in shader model 5.1 and above. " "Compile the shader using shader model 5.0 or use non-array sampler variable."); } - StaticSamplerInd = -1; + ImtblSamplerInd = -1; } } - return StaticSamplerInd; + return ImtblSamplerInd; } D3DShaderResourceCounters ShaderResources::CountResources(const PipelineResourceLayoutDesc& ResourceLayout, const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, Uint32 NumAllowedTypes, - bool CountStaticSamplers) const noexcept + bool CountImmutableSamplers) const noexcept { auto AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); @@ -176,11 +176,11 @@ D3DShaderResourceCounters ShaderResources::CountResources(const PipelineResource auto VarType = FindVariableType(Sam, ResourceLayout); if (IsAllowedType(VarType, AllowedTypeBits)) { - if (!CountStaticSamplers) + if (!CountImmutableSamplers) { - constexpr bool LogStaticSamplerArrayError = false; - if (FindStaticSampler(Sam, ResourceLayout, LogStaticSamplerArrayError) >= 0) - return; // Skip static sampler if requested + constexpr bool LogImtblSamplerArrayError = false; + if (FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError) >= 0) + return; // Skip immutable sampler if requested } ++Counters.NumSamplers; } @@ -219,7 +219,7 @@ void ShaderResources::DvpVerifyResourceLayout(const PipelineResourceLayoutDesc& const ShaderResources* const pShaderResources[], Uint32 NumShaders, bool VerifyVariables, - bool VerifyStaticSamplers) + bool VerifyImmutableSamplers) noexcept { auto GetAllowedShadersString = [&](SHADER_TYPE ShaderStages) // { @@ -300,40 +300,40 @@ void ShaderResources::DvpVerifyResourceLayout(const PipelineResourceLayoutDesc& } } - if (VerifyStaticSamplers) + if (VerifyImmutableSamplers) { - for (Uint32 sam = 0; sam < ResourceLayout.NumStaticSamplers; ++sam) + for (Uint32 sam = 0; sam < ResourceLayout.NumImmutableSamplers; ++sam) { - const auto& StSamDesc = ResourceLayout.StaticSamplers[sam]; + const auto& StSamDesc = ResourceLayout.ImmutableSamplers[sam]; if (StSamDesc.ShaderStages == SHADER_TYPE_UNKNOWN) { - LOG_WARNING_MESSAGE("No allowed shader stages are specified for static sampler '", StSamDesc.SamplerOrTextureName, "'."); + LOG_WARNING_MESSAGE("No allowed shader stages are specified for immutable sampler '", StSamDesc.SamplerOrTextureName, "'."); continue; } const auto* TexOrSamName = StSamDesc.SamplerOrTextureName; - bool StaticSamplerFound = false; - for (Uint32 s = 0; s < NumShaders && !StaticSamplerFound; ++s) + bool ImtblSamplerFound = false; + for (Uint32 s = 0; s < NumShaders && !ImtblSamplerFound; ++s) { const auto& Resources = *pShaderResources[s]; if ((StSamDesc.ShaderStages & Resources.GetShaderType()) == 0) continue; - // Look for static sampler. + // Look for immutable sampler. // In case HLSL-style combined image samplers are used, the condition is Sampler.Name == "g_Texture" + "_sampler". // Otherwise the condition is Sampler.Name == "g_Texture_sampler" + "". const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix(); - for (Uint32 n = 0; n < Resources.GetNumSamplers() && !StaticSamplerFound; ++n) + for (Uint32 n = 0; n < Resources.GetNumSamplers() && !ImtblSamplerFound; ++n) { const auto& Sampler = Resources.GetSampler(n); - StaticSamplerFound = StreqSuff(Sampler.Name, TexOrSamName, CombinedSamplerSuffix); + ImtblSamplerFound = StreqSuff(Sampler.Name, TexOrSamName, CombinedSamplerSuffix); } } - if (!StaticSamplerFound) + if (!ImtblSamplerFound) { - LOG_WARNING_MESSAGE("Static sampler '", TexOrSamName, "' is not found in any of the designated shader stages: ", + LOG_WARNING_MESSAGE("Immutable sampler '", TexOrSamName, "' is not found in any of the designated shader stages: ", GetAllowedShadersString(StSamDesc.ShaderStages)); } } @@ -454,6 +454,39 @@ HLSLShaderResourceDesc D3DShaderResourceAttribs::GetHLSLResourceDesc() const return ResourceDesc; } +RESOURCE_DIMENSION D3DShaderResourceAttribs::GetResourceDimension() const +{ + switch (GetSRVDimension()) + { + // clang-format off + case D3D_SRV_DIMENSION_BUFFER: return RESOURCE_DIM_BUFFER; + case D3D_SRV_DIMENSION_TEXTURE1D: return RESOURCE_DIM_TEX_1D; + case D3D_SRV_DIMENSION_TEXTURE1DARRAY: return RESOURCE_DIM_TEX_1D_ARRAY; + case D3D_SRV_DIMENSION_TEXTURE2D: return RESOURCE_DIM_TEX_2D; + case D3D_SRV_DIMENSION_TEXTURE2DARRAY: return RESOURCE_DIM_TEX_2D_ARRAY; + case D3D_SRV_DIMENSION_TEXTURE2DMS: return RESOURCE_DIM_TEX_2D; + case D3D_SRV_DIMENSION_TEXTURE2DMSARRAY: return RESOURCE_DIM_TEX_2D_ARRAY; + case D3D_SRV_DIMENSION_TEXTURE3D: return RESOURCE_DIM_TEX_3D; + case D3D_SRV_DIMENSION_TEXTURECUBE: return RESOURCE_DIM_TEX_CUBE; + case D3D_SRV_DIMENSION_TEXTURECUBEARRAY: return RESOURCE_DIM_TEX_CUBE_ARRAY; + // clang-format on + default: + return RESOURCE_DIM_BUFFER; + } +} + +bool D3DShaderResourceAttribs::IsMultisample() const +{ + switch (GetSRVDimension()) + { + case D3D_SRV_DIMENSION_TEXTURE2DMS: + case D3D_SRV_DIMENSION_TEXTURE2DMSARRAY: + return true; + default: + return false; + } +} + HLSLShaderResourceDesc ShaderResources::GetHLSLShaderResourceDesc(Uint32 Index) const { DEV_CHECK_ERR(Index < m_TotalResources, "Resource index (", Index, ") is out of range"); diff --git a/Graphics/GraphicsEngineMetal/interface/BufferViewMtl.h b/Graphics/GraphicsEngineMetal/interface/BufferViewMtl.h index 97b36dbc..d5561b58 100644 --- a/Graphics/GraphicsEngineMetal/interface/BufferViewMtl.h +++ b/Graphics/GraphicsEngineMetal/interface/BufferViewMtl.h @@ -41,6 +41,7 @@ static const INTERFACE_ID IID_BufferViewMtl = class IBufferViewMtl : public IBufferView { public: + virtual id<MTLTexture> GetMtlTextureView() const = 0; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineMetal/interface/SamplerMtl.h b/Graphics/GraphicsEngineMetal/interface/SamplerMtl.h index 51057dad..a8290e07 100644 --- a/Graphics/GraphicsEngineMetal/interface/SamplerMtl.h +++ b/Graphics/GraphicsEngineMetal/interface/SamplerMtl.h @@ -41,6 +41,7 @@ static const INTERFACE_ID IID_SamplerMtl = class ISamplerMtl : public ISampler { public: + virtual id<MTLSamplerState> GetMtlSampler() = 0; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.hpp b/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.hpp index 80f622c9..24e88004 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.hpp @@ -118,15 +118,15 @@ public: GLVariableBase(const GLProgramResources::GLResourceAttribs& ResourceAttribs, GLPipelineResourceLayout& ParentLayout, SHADER_RESOURCE_VARIABLE_TYPE VariableType, - Int32 StaticSamplerIdx) : + Int32 ImtblSamplerIdx) : // clang-format off TBase {ParentLayout}, m_Attribs {ResourceAttribs }, m_VariableType {VariableType }, - m_StaticSamplerIdx{StaticSamplerIdx} + m_ImtblSamplerIdx {ImtblSamplerIdx} // clang-format on { - VERIFY_EXPR(StaticSamplerIdx < 0 || ResourceAttribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV); + VERIFY_EXPR(ImtblSamplerIdx < 0 || ResourceAttribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV); } virtual SHADER_RESOURCE_VARIABLE_TYPE DILIGENT_CALL_TYPE GetType() const override final @@ -146,7 +146,7 @@ public: const GLProgramResources::GLResourceAttribs& m_Attribs; const SHADER_RESOURCE_VARIABLE_TYPE m_VariableType; - const Int32 m_StaticSamplerIdx; + const Int32 m_ImtblSamplerIdx; }; @@ -188,8 +188,8 @@ public: SamplerBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs, GLPipelineResourceLayout& ParentResLayout, SHADER_RESOURCE_VARIABLE_TYPE VariableType, - Int32 StaticSamplerIdx) : - GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, StaticSamplerIdx} + Int32 ImtblSamplerIdx) : + GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, ImtblSamplerIdx} {} // Non-virtual function diff --git a/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.hpp b/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.hpp index 3fbc550e..07c8f39e 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.hpp @@ -45,7 +45,7 @@ namespace Diligent class GLProgramResourceCache { public: - GLProgramResourceCache() + GLProgramResourceCache() noexcept {} ~GLProgramResourceCache(); @@ -128,9 +128,9 @@ public: GetSampler(Binding).Set(std::move(pTexView), SetSampler); } - void SetStaticSampler(Uint32 Binding, ISampler* pStaticSampler) + void SetImmutableSampler(Uint32 Binding, ISampler* pImtblSampler) { - GetSampler(Binding).pSampler = ValidatedCast<SamplerGLImpl>(pStaticSampler); + GetSampler(Binding).pSampler = ValidatedCast<SamplerGLImpl>(pImtblSampler); } void CopySampler(Uint32 Binding, const CachedResourceView& SrcSam) diff --git a/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.hpp b/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.hpp index a3b13b6d..091d0e31 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.hpp @@ -147,6 +147,16 @@ public: ResourceDesc.Type = ResourceType; return ResourceDesc; } + + RESOURCE_DIMENSION GetResourceDimension() const + { + return RESOURCE_DIM_UNDEFINED; + } + + bool IsMultisample() const + { + return false; + } }; struct UniformBufferInfo final : GLResourceAttribs diff --git a/Graphics/GraphicsEngineOpenGL/include/GLTypeConversions.hpp b/Graphics/GraphicsEngineOpenGL/include/GLTypeConversions.hpp index a93528ec..4c57652f 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLTypeConversions.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/GLTypeConversions.hpp @@ -82,7 +82,7 @@ inline GLenum UsageToGLUsage(const BufferDesc& Desc) // DYNAMIC: The data store contents will be modified repeatedly and used many times. // clang-format off - case USAGE_STATIC: return GL_STATIC_DRAW; + case USAGE_IMMUTABLE: return GL_STATIC_DRAW; case USAGE_DEFAULT: return GL_STATIC_DRAW; case USAGE_UNIFIED: return GL_STATIC_DRAW; case USAGE_DYNAMIC: return GL_DYNAMIC_DRAW; diff --git a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp index dea1d6c8..93180774 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<IPipelineStateGL, Ren public: using TPipelineStateBase = PipelineStateBase<IPipelineStateGL, RenderDeviceGLImpl>; - 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 @@ -90,12 +95,32 @@ public: private: GLObjectWrappers::GLPipelineObj& GetGLProgramPipeline(GLContext::NativeGLContextType Context); - void InitStaticSamplersInResourceCache(const GLPipelineResourceLayout& ResourceLayout, GLProgramResourceCache& Cache) const; + void InitImmutableSamplersInResourceCache(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} + {} + }; + + template <typename PSOCreateInfoType> + void Initialize(const PSOCreateInfoType& CreateInfo, const std::vector<GLPipelineShaderStageInfo>& ShaderStages); + + void InitResourceLayouts(const std::vector<GLPipelineShaderStageInfo>& ShaderStages, + LinearAllocator& MemPool); + + void Destruct(); // 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<GLObjectWrappers::GLProgramObj> m_GLPrograms; + using GLProgramObj = GLObjectWrappers::GLProgramObj; + GLProgramObj* m_GLPrograms = nullptr; // [m_NumShaderStages] ThreadingTools::LockFlag m_ProgPipelineLockFlag; @@ -113,14 +138,15 @@ private: GLProgramResourceCache m_StaticResourceCache; // Program resources for all shader stages in the pipeline - std::vector<GLProgramResources> 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<RefCntAutoPtr<ISampler>> m_StaticSamplers; + using SamplerPtr = RefCntAutoPtr<ISampler>; + SamplerPtr* m_ImmutableSamplers = nullptr; // [m_Desc.ResourceLayout.NumImmutableSamplers] }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp index be2b4ddc..3c34b483 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 DILIGENT_CALL_TYPE CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, + IPipelineState** ppPipelineState) override final; + + /// Implementation of IRenderDevice::CreateComputePipelineState() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE 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; @@ -179,6 +187,9 @@ protected: std::unique_ptr<TexRegionRender> m_pTexRegionRender; private: + template <typename PSOCreateInfoType> + void CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState, bool bIsDeviceInternal); + virtual void TestTextureFormat(TEXTURE_FORMAT TexFormat) override final; bool CheckExtension(const Char* ExtensionString); void FlagSupportedTexFormats(); diff --git a/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.hpp index bc0f32e6..d4c4b87e 100644 --- a/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.hpp @@ -92,7 +92,7 @@ public: /// Implementation of IShader::GetResource() in OpenGL backend. virtual void DILIGENT_CALL_TYPE GetResourceDesc(Uint32 Index, ShaderResourceDesc& ResourceDesc) const override final; - static GLObjectWrappers::GLProgramObj LinkProgram(IShader** ppShaders, Uint32 NumShaders, bool IsSeparableProgram); + static GLObjectWrappers::GLProgramObj LinkProgram(ShaderGLImpl** ppShaders, Uint32 NumShaders, bool IsSeparableProgram); private: GLObjectWrappers::GLShaderObj m_GLShaderObj; diff --git a/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp index 4bba7d46..ac99cfa0 100644 --- a/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp @@ -96,8 +96,8 @@ BufferGLImpl::BufferGLImpl(IReferenceCounters* pRefCounters, LOG_ERROR_AND_THROW("Unified resources are not supported in OpenGL/GLES"); } - if (m_Desc.Usage == USAGE_STATIC) - VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for static buffers"); + if (m_Desc.Usage == USAGE_IMMUTABLE) + VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for immutable buffers"); // TODO: find out if it affects performance if the buffer is originally bound to one target // and then bound to another (such as first to GL_ARRAY_BUFFER and then to GL_UNIFORM_BUFFER) diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index deea5ade..7b09f9ce 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/GLPipelineResourceLayout.cpp b/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp index 0955a54f..d2f9cddc 100644 --- a/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp @@ -147,11 +147,11 @@ void GLPipelineResourceLayout::Initialize(GLProgramResources* P { auto VarType = GetShaderVariableType(ShaderStages, Sam.Name, ResourceLayout); VERIFY_EXPR(IsAllowedType(VarType, DbgAllowedTypeBits)); - Int32 StaticSamplerIdx = -1; + Int32 ImtblSamplerIdx = -1; if (Sam.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV) { - StaticSamplerIdx = FindStaticSampler(ResourceLayout.StaticSamplers, ResourceLayout.NumStaticSamplers, ShaderStages, - Sam.Name, nullptr); + ImtblSamplerIdx = FindImmutableSampler(ResourceLayout.ImmutableSamplers, ResourceLayout.NumImmutableSamplers, ShaderStages, + Sam.Name, nullptr); } auto* pSamVar = new (&GetResource<SamplerBindInfo>(VarCounters.NumSamplers++)) SamplerBindInfo // @@ -159,7 +159,7 @@ void GLPipelineResourceLayout::Initialize(GLProgramResources* P Sam, *this, VarType, - StaticSamplerIdx // + ImtblSamplerIdx // }; SamplerBindingSlots = std::max(SamplerBindingSlots, pSamVar->m_Attribs.Binding + pSamVar->m_Attribs.ArraySize); }, @@ -290,13 +290,13 @@ void GLPipelineResourceLayout::SamplerBindInfo::BindResource(IDeviceObject* pVie { auto& CachedTexSampler = ResourceCache.GetConstSampler(m_Attribs.Binding + ArrayIndex); VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, CachedTexSampler.pView.RawPtr()); - if (m_StaticSamplerIdx >= 0) + if (m_ImtblSamplerIdx >= 0) { - VERIFY(CachedTexSampler.pSampler != nullptr, "Static samplers must be initialized by PipelineStateGLImpl::InitializeSRBResourceCache!"); + VERIFY(CachedTexSampler.pSampler != nullptr, "Immutable samplers must be initialized by PipelineStateGLImpl::InitializeSRBResourceCache!"); } } #endif - ResourceCache.SetTexSampler(m_Attribs.Binding + ArrayIndex, std::move(pViewGL), m_StaticSamplerIdx < 0); + ResourceCache.SetTexSampler(m_Attribs.Binding + ArrayIndex, std::move(pViewGL), m_ImtblSamplerIdx < 0); } else if (m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV) { @@ -307,6 +307,16 @@ void GLPipelineResourceLayout::SamplerBindInfo::BindResource(IDeviceObject* pVie { auto& CachedBuffSampler = ResourceCache.GetConstSampler(m_Attribs.Binding + ArrayIndex); VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {BUFFER_VIEW_SHADER_RESOURCE}, CachedBuffSampler.pView.RawPtr()); + if (pViewGL != nullptr) + { + const auto& ViewDesc = pViewGL->GetDesc(); + const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); + if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW)) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + m_Attribs.Name, ": formatted buffer view is expected."); + } + } } #endif ResourceCache.SetBufSampler(m_Attribs.Binding + ArrayIndex, std::move(pViewGL)); @@ -347,6 +357,16 @@ void GLPipelineResourceLayout::ImageBindInfo::BindResource(IDeviceObject* pView, { auto& CachedUAV = ResourceCache.GetConstImage(m_Attribs.Binding + ArrayIndex); VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {BUFFER_VIEW_UNORDERED_ACCESS}, CachedUAV.pView.RawPtr()); + if (pViewGL != nullptr) + { + const auto& ViewDesc = pViewGL->GetDesc(); + const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); + if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW)) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + m_Attribs.Name, ": formatted buffer view is expected."); + } + } } #endif ResourceCache.SetBufImage(m_Attribs.Binding + ArrayIndex, std::move(pViewGL)); @@ -375,6 +395,16 @@ void GLPipelineResourceLayout::StorageBufferBindInfo::BindResource(IDeviceObject auto& CachedSSBO = ResourceCache.GetConstSSBO(m_Attribs.Binding + ArrayIndex); // HLSL structured buffers are mapped to SSBOs in GLSL VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {BUFFER_VIEW_SHADER_RESOURCE, BUFFER_VIEW_UNORDERED_ACCESS}, CachedSSBO.pBufferView.RawPtr()); + if (pViewGL != nullptr) + { + const auto& ViewDesc = pViewGL->GetDesc(); + const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); + if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + m_Attribs.Name, ": structured buffer view is expected."); + } + } } #endif ResourceCache.SetSSBO(m_Attribs.Binding + ArrayIndex, std::move(pViewGL)); @@ -764,9 +794,9 @@ bool GLPipelineResourceLayout::dvpVerifyBindings(const GLProgramResourceCache& R else { const auto& CachedSampler = ResourceCache.GetConstSampler(BindPoint); - if (sam.m_StaticSamplerIdx >= 0 && CachedSampler.pSampler == nullptr) + if (sam.m_ImtblSamplerIdx >= 0 && CachedSampler.pSampler == nullptr) { - LOG_ERROR_MESSAGE("Static sampler is not initialized for texture '", sam.m_Attribs.Name, "'"); + LOG_ERROR_MESSAGE("Immutable sampler is not initialized for texture '", sam.m_Attribs.Name, "'"); BindingsOK = false; } } diff --git a/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp b/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp index 95557557..84cdc46e 100644 --- a/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp @@ -92,7 +92,9 @@ GLProgramResourceCache::~GLProgramResourceCache() void GLProgramResourceCache::Destroy(IMemoryAllocator& MemAllocator) { - VERIFY(IsInitialized(), "Resource cache is not initialized"); + if (!IsInitialized()) + return; + VERIFY(m_pdbgMemoryAllocator == &MemAllocator, "The allocator does not match the one used to create resources"); for (Uint32 cb = 0; cb < GetUBCount(); ++cb) diff --git a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp index 399983c9..8b429094 100644 --- a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp @@ -36,10 +36,47 @@ namespace Diligent { -PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters, - RenderDeviceGLImpl* pDeviceGL, - const PipelineStateCreateInfo& CreateInfo, - bool bIsDeviceInternal) : + +template <typename PSOCreateInfoType> +void PipelineStateGLImpl::Initialize(const PSOCreateInfoType& CreateInfo, const std::vector<GLPipelineShaderStageInfo>& ShaderStages) +{ + LinearAllocator MemPool{GetRawAllocator()}; + VERIFY_EXPR(m_NumShaderStages > 0 && m_NumShaderStages == ShaderStages.size()); + if (!GetDevice()->GetDeviceCaps().Features.SeparablePrograms) + m_NumShaderStages = 1; + + const auto NumPrograms = GetNumShaderStages(); + + MemPool.AddSpace<GLProgramObj>(NumPrograms); + MemPool.AddSpace<GLProgramResources>(NumPrograms); + MemPool.AddSpace<SamplerPtr>(m_Desc.ResourceLayout.NumImmutableSamplers); + + ReserveSpaceForPipelineDesc(CreateInfo, MemPool); + + MemPool.Reserve(); + + m_GLPrograms = MemPool.ConstructArray<GLProgramObj>(NumPrograms, false); + + // The memory is now owned by PipelineStateVkImpl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_GLPrograms); + (void)Ptr; + + m_ProgramResources = MemPool.ConstructArray<GLProgramResources>(NumPrograms); + + m_ImmutableSamplers = MemPool.ConstructArray<SamplerPtr>(m_Desc.ResourceLayout.NumImmutableSamplers); + + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects + + InitResourceLayouts(ShaderStages, MemPool); + InitializePipelineDesc(CreateInfo, MemPool); +} + +PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDeviceGL, + const GraphicsPipelineStateCreateInfo& CreateInfo, + bool bIsDeviceInternal) : // clang-format off TPipelineStateBase { @@ -52,22 +89,110 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun m_StaticResourceLayout{*this} // clang-format on { - if (m_Desc.IsAnyGraphicsPipeline() && m_pPS == nullptr) + try + { + std::vector<GLPipelineShaderStageInfo> ShaderStages; + ExtractShaders<ShaderGLImpl>(CreateInfo, ShaderStages); + + RefCntAutoPtr<ShaderGLImpl> pTempPS; + if (CreateInfo.pPS == nullptr) + { + // Some OpenGL implementations fail if fragment shader is not present, so + // create a dummy one. + ShaderCreateInfo ShaderCI; + ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_GLSL; + ShaderCI.Source = "void main(){}"; + ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL; + ShaderCI.Desc.Name = "Dummy fragment shader"; + pDeviceGL->CreateShader(ShaderCI, reinterpret_cast<IShader**>(static_cast<ShaderGLImpl**>(&pTempPS))); + + ShaderStages.emplace_back(SHADER_TYPE_PIXEL, pTempPS); + m_ShaderStageTypes[m_NumShaderStages++] = SHADER_TYPE_PIXEL; + } + + Initialize(CreateInfo, ShaderStages); + } + catch (...) { - // Some OpenGL implementations fail if fragment shader is not present, so - // create a dummy one. - ShaderCreateInfo ShaderCI; - ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_GLSL; - ShaderCI.Source = "void main(){}"; - ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL; - ShaderCI.Desc.Name = "Dummy fragment shader"; - pDeviceGL->CreateShader(ShaderCI, &m_pPS); - m_Desc.GraphicsPipeline.pPS = m_pPS; - m_ppShaders[m_NumShaders++] = m_pPS; + Destruct(); } +} + +PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDeviceGL, + const ComputePipelineStateCreateInfo& CreateInfo, + bool bIsDeviceInternal) : + // clang-format off + TPipelineStateBase + { + pRefCounters, + pDeviceGL, + CreateInfo.PSODesc, + bIsDeviceInternal + }, + m_ResourceLayout {*this}, + m_StaticResourceLayout{*this} +// clang-format on +{ + try + { + std::vector<GLPipelineShaderStageInfo> ShaderStages; + ExtractShaders<ShaderGLImpl>(CreateInfo, ShaderStages); - auto& DeviceCaps = pDeviceGL->GetDeviceCaps(); - VERIFY(DeviceCaps.DevType != RENDER_DEVICE_TYPE_UNDEFINED, "Device caps are not initialized"); + Initialize(CreateInfo, ShaderStages); + } + catch (...) + { + Destruct(); + } +} + +PipelineStateGLImpl::~PipelineStateGLImpl() +{ + Destruct(); +} + +void PipelineStateGLImpl::Destruct() +{ + auto& RawAllocator = GetRawAllocator(); + m_StaticResourceCache.Destroy(RawAllocator); + GetDevice()->OnDestroyPSO(this); + + if (m_ImmutableSamplers != nullptr) + { + for (Uint32 i = 0; i < m_Desc.ResourceLayout.NumImmutableSamplers; ++i) + { + m_ImmutableSamplers[i].~SamplerPtr(); + } + } + + for (Uint32 i = 0; i < GetNumShaderStages(); ++i) + { + if (m_GLPrograms != nullptr) + { + m_GLPrograms[i].~GLProgramObj(); + } + if (m_ProgramResources != nullptr) + { + m_ProgramResources[i].~GLProgramResources(); + } + } + + if (void* pRawMem = m_GLPrograms) + { + RawAllocator.Free(pRawMem); + } +} + +IMPLEMENT_QUERY_INTERFACE(PipelineStateGLImpl, IID_PipelineStateGL, TPipelineStateBase) + + +void PipelineStateGLImpl::InitResourceLayouts(const std::vector<GLPipelineShaderStageInfo>& ShaderStages, + LinearAllocator& MemPool) +{ + auto* const pDeviceGL = GetDevice(); + const auto& deviceCaps = pDeviceGL->GetDeviceCaps(); + VERIFY(deviceCaps.DevType != RENDER_DEVICE_TYPE_UNDEFINED, "Device caps are not initialized"); auto pImmediateCtx = m_pDevice->GetImmediateContext(); VERIFY_EXPR(pImmediateCtx); @@ -78,18 +203,16 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun m_TotalSamplerBindings = 0; m_TotalImageBindings = 0; m_TotalStorageBufferBindings = 0; - if (DeviceCaps.Features.SeparablePrograms) + if (deviceCaps.Features.SeparablePrograms) { // Program pipelines are not shared between GL contexts, so we cannot create // it now m_ShaderResourceLayoutHash = 0; - m_ProgramResources.resize(m_NumShaders); - m_GLPrograms.reserve(m_NumShaders); - for (Uint32 i = 0; i < m_NumShaders; ++i) + for (size_t i = 0; i < ShaderStages.size(); ++i) { - auto* pShaderGL = GetShader<ShaderGLImpl>(i); + auto* pShaderGL = ShaderStages[i].pShader; const auto& ShaderDesc = pShaderGL->GetDesc(); - m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(&m_ppShaders[i], 1, true)); + 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, @@ -102,15 +225,19 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun } else { - m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(m_ppShaders.data(), m_NumShaders, false)); - m_ProgramResources.resize(1); - SHADER_TYPE ShaderStages = SHADER_TYPE_UNKNOWN; - for (Uint32 i = 0; i < m_NumShaders; ++i) + std::vector<ShaderGLImpl*> Shaders; + + SHADER_TYPE ActiveStages = SHADER_TYPE_UNKNOWN; + for (const auto& Stage : ShaderStages) { - const auto& ShaderDesc = m_ppShaders[i]->GetDesc(); - ShaderStages |= ShaderDesc.ShaderType; + Shaders.push_back(Stage.pShader); + VERIFY((ActiveStages & Stage.Type) == 0, "Shader stage ", GetShaderTypeLiteralName(Stage.Type), " is already active"); + ActiveStages |= Stage.Type; } - m_ProgramResources[0].LoadUniforms(ShaderStages, m_GLPrograms[0], GLState, + + m_GLPrograms[0] = ShaderGLImpl::LinkProgram(Shaders.data(), static_cast<Uint32>(Shaders.size()), false); + + m_ProgramResources[0].LoadUniforms(ActiveStages, m_GLPrograms[0], GLState, m_TotalUniformBufferBindings, m_TotalSamplerBindings, m_TotalImageBindings, @@ -120,38 +247,27 @@ 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<Uint32>(m_GLPrograms.size()), m_Desc.PipelineType, m_Desc.ResourceLayout, nullptr, 0, nullptr); + m_ResourceLayout.Initialize(m_ProgramResources, GetNumShaderStages(), m_Desc.PipelineType, m_Desc.ResourceLayout, nullptr, 0, nullptr); } - m_StaticSamplers.resize(m_Desc.ResourceLayout.NumStaticSamplers); - for (Uint32 s = 0; s < m_Desc.ResourceLayout.NumStaticSamplers; ++s) + for (Uint32 s = 0; s < m_Desc.ResourceLayout.NumImmutableSamplers; ++s) { - pDeviceGL->CreateSampler(m_Desc.ResourceLayout.StaticSamplers[s].Desc, &m_StaticSamplers[s]); + pDeviceGL->CreateSampler(m_Desc.ResourceLayout.ImmutableSamplers[s].Desc, &m_ImmutableSamplers[s]); } { // 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<Uint32>(m_GLPrograms.size()), m_Desc.PipelineType, m_Desc.ResourceLayout, StaticVars, _countof(StaticVars), &m_StaticResourceCache); - InitStaticSamplersInResourceCache(m_StaticResourceLayout, m_StaticResourceCache); + m_StaticResourceLayout.Initialize(m_ProgramResources, GetNumShaderStages(), m_Desc.PipelineType, m_Desc.ResourceLayout, StaticVars, _countof(StaticVars), &m_StaticResourceCache); + InitImmutableSamplersInResourceCache(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<Uint32>(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<IObject**>(ppShaderResourceBinding)); @@ -168,10 +284,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; @@ -196,7 +312,7 @@ void PipelineStateGLImpl::CommitProgram(GLContextState& State) } else { - VERIFY_EXPR(m_GLPrograms.size() == 1); + VERIFY_EXPR(m_GLPrograms != nullptr); State.SetProgram(m_GLPrograms[0]); } } @@ -214,10 +330,9 @@ GLObjectWrappers::GLPipelineObj& PipelineStateGLImpl::GetGLProgramPipeline(GLCon m_GLProgPipelines.emplace_back(Context, true); auto& ctx_pipeline = m_GLProgPipelines.back(); GLuint Pipeline = ctx_pipeline.second; - for (Uint32 i = 0; i < m_NumShaders; ++i) + for (Uint32 i = 0; i < GetNumShaderStages(); ++i) { - auto* pCurrShader = GetShader<ShaderGLImpl>(i); - auto GLShaderBit = ShaderTypeToGLShaderBit(pCurrShader->GetDesc().ShaderType); + auto GLShaderBit = ShaderTypeToGLShaderBit(GetShaderStageType(i)); // If the program has an active code for each stage mentioned in set flags, // then that code will be used by the pipeline. If program is 0, then the given // stages are cleared from the pipeline. @@ -230,19 +345,19 @@ GLObjectWrappers::GLPipelineObj& PipelineStateGLImpl::GetGLProgramPipeline(GLCon void PipelineStateGLImpl::InitializeSRBResourceCache(GLProgramResourceCache& ResourceCache) const { ResourceCache.Initialize(m_TotalUniformBufferBindings, m_TotalSamplerBindings, m_TotalImageBindings, m_TotalStorageBufferBindings, GetRawAllocator()); - InitStaticSamplersInResourceCache(m_ResourceLayout, ResourceCache); + InitImmutableSamplersInResourceCache(m_ResourceLayout, ResourceCache); } -void PipelineStateGLImpl::InitStaticSamplersInResourceCache(const GLPipelineResourceLayout& ResourceLayout, GLProgramResourceCache& Cache) const +void PipelineStateGLImpl::InitImmutableSamplersInResourceCache(const GLPipelineResourceLayout& ResourceLayout, GLProgramResourceCache& Cache) const { for (Uint32 s = 0; s < ResourceLayout.GetNumResources<GLPipelineResourceLayout::SamplerBindInfo>(); ++s) { const auto& Sam = ResourceLayout.GetConstResource<GLPipelineResourceLayout::SamplerBindInfo>(s); - if (Sam.m_StaticSamplerIdx >= 0) + if (Sam.m_ImtblSamplerIdx >= 0) { - ISampler* pSampler = m_StaticSamplers[Sam.m_StaticSamplerIdx].RawPtr<ISampler>(); + ISampler* pSampler = m_ImmutableSamplers[Sam.m_ImtblSamplerIdx].RawPtr<ISampler>(); for (Uint32 binding = Sam.m_Attribs.Binding; binding < Sam.m_Attribs.Binding + Sam.m_Attribs.ArraySize; ++binding) - Cache.SetStaticSampler(binding, pSampler); + Cache.SetImmutableSampler(binding, pSampler); } } } diff --git a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp index b7bdf993..ca75a9ca 100644 --- a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp @@ -330,6 +330,9 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, SET_FEATURE_STATE(WireframeFill, WireframeFillSupported, "Wireframe fill is"); } + if (InitAttribs.ForceNonSeparablePrograms) + LOG_INFO_MESSAGE("Forcing non-separable shader programs"); + if (m_DeviceCaps.DevType == RENDER_DEVICE_TYPE_GL) { const bool IsGL46OrAbove = (MajorVersion >= 5) || (MajorVersion == 4 && MinorVersion >= 6); @@ -337,7 +340,8 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, const bool IsGL42OrAbove = (MajorVersion >= 5) || (MajorVersion == 4 && MinorVersion >= 2); const bool IsGL41OrAbove = (MajorVersion >= 5) || (MajorVersion == 4 && MinorVersion >= 1); - Features.SeparablePrograms = DEVICE_FEATURE_STATE_ENABLED; + SET_FEATURE_STATE(SeparablePrograms, !InitAttribs.ForceNonSeparablePrograms, "Separable programs are"); + SET_FEATURE_STATE(ShaderResourceQueries, Features.SeparablePrograms != DEVICE_FEATURE_STATE_DISABLED, "Shader resource queries are"); Features.IndirectRendering = DEVICE_FEATURE_STATE_ENABLED; Features.WireframeFill = DEVICE_FEATURE_STATE_ENABLED; // clang-format off @@ -396,7 +400,8 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, bool IsGLES32OrAbove = (MajorVersion >= 4) || (MajorVersion == 3 && MinorVersion >= 2); // clang-format off - SET_FEATURE_STATE(SeparablePrograms, IsGLES31OrAbove || strstr(Extensions, "separate_shader_objects"), "Separable programs are"); + SET_FEATURE_STATE(SeparablePrograms, (IsGLES31OrAbove || strstr(Extensions, "separate_shader_objects")) && !InitAttribs.ForceNonSeparablePrograms, "Separable programs are"); + SET_FEATURE_STATE(ShaderResourceQueries, Features.SeparablePrograms != DEVICE_FEATURE_STATE_DISABLED, "Shader resource queries are"); SET_FEATURE_STATE(IndirectRendering, IsGLES31OrAbove || strstr(Extensions, "draw_indirect"), "Indirect rendering is"); SET_FEATURE_STATE(WireframeFill, false, "Wireframe fill is"); SET_FEATURE_STATE(MultithreadedResourceCreation, false, "Multithreaded resource creation is"); @@ -457,7 +462,7 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, #undef SET_FEATURE_STATE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 31, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif } @@ -697,13 +702,8 @@ void RenderDeviceGLImpl::CreateSampler(const SamplerDesc& SamplerDesc, ISampler* CreateSampler(SamplerDesc, ppSampler, false); } - -void RenderDeviceGLImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) -{ - CreatePipelineState(PSOCreateInfo, ppPipelineState, false); -} - -void RenderDeviceGLImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState, bool bIsDeviceInternal) +template <typename PSOCreateInfoType> +void RenderDeviceGLImpl::CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState, bool bIsDeviceInternal) { CreateDeviceObject( "Pipeline state", PSOCreateInfo.PSODesc, ppPipelineState, @@ -716,6 +716,26 @@ void RenderDeviceGLImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOC ); } +void RenderDeviceGLImpl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState, bool bIsDeviceInternal) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState, bIsDeviceInternal); +} + +void RenderDeviceGLImpl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState, bool bIsDeviceInternal) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState, bIsDeviceInternal); +} + +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/ShaderGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp index c7a493cd..e27a8a4c 100644 --- a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp @@ -158,7 +158,7 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters* pRefCounters, if (deviceCaps.Features.SeparablePrograms) { - IShader* ThisShader[] = {this}; + ShaderGLImpl* ThisShader[] = {this}; GLObjectWrappers::GLProgramObj Program = LinkProgram(ThisShader, 1, true); Uint32 UniformBufferBinding = 0; Uint32 SamplerBinding = 0; @@ -178,7 +178,7 @@ ShaderGLImpl::~ShaderGLImpl() IMPLEMENT_QUERY_INTERFACE(ShaderGLImpl, IID_ShaderGL, TShaderBase) -GLObjectWrappers::GLProgramObj ShaderGLImpl::LinkProgram(IShader** ppShaders, Uint32 NumShaders, bool IsSeparableProgram) +GLObjectWrappers::GLProgramObj ShaderGLImpl::LinkProgram(ShaderGLImpl** ppShaders, Uint32 NumShaders, bool IsSeparableProgram) { VERIFY(!IsSeparableProgram || NumShaders == 1, "Number of shaders must be 1 when separable program is created"); @@ -190,7 +190,7 @@ GLObjectWrappers::GLProgramObj ShaderGLImpl::LinkProgram(IShader** ppShaders, Ui for (Uint32 i = 0; i < NumShaders; ++i) { - auto* pCurrShader = ValidatedCast<ShaderGLImpl>(ppShaders[i]); + auto* pCurrShader = ppShaders[i]; glAttachShader(GLProg, pCurrShader->m_GLShaderObj); CHECK_GL_ERROR("glAttachShader() failed"); } diff --git a/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp b/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp index bd47e4ac..5861005e 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,19 @@ 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; + auto& ResourceLayout = PSOCreateInfo.PSODesc.ResourceLayout; + + 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; + ResourceLayout.NumVariables = _countof(Vars); + 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/TextureBaseGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp index 564d16cb..243ab1c9 100644 --- a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp @@ -63,8 +63,8 @@ TextureBaseGL::TextureBaseGL(IReferenceCounters* pRefCounters, // clang-format on { VERIFY(m_GLTexFormat != 0, "Unsupported texture format"); - if (TexDesc.Usage == USAGE_STATIC && pInitData == nullptr) - LOG_ERROR_AND_THROW("Static Texture must be initialized with data at creation time"); + if (TexDesc.Usage == USAGE_IMMUTABLE && pInitData == nullptr) + LOG_ERROR_AND_THROW("Immutable textures must be initialized with data at creation time"); if (TexDesc.Usage == USAGE_STAGING) { 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<PipelineStateGLImpl>(pPSO); auto* pIndexBufferGL = ValidatedCast<BufferGLImpl>(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 d1732211..d4f2fc36 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp @@ -57,7 +57,8 @@ class PipelineStateVkImpl final : public PipelineStateBase<IPipelineStateVk, Ren public: using TPipelineStateBase = PipelineStateBase<IPipelineStateVk, RenderDeviceVkImpl>; - 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; @@ -104,7 +105,7 @@ public: const ShaderResourceLayoutVk& GetShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < GetNumShaderStages()); return m_ShaderResourceLayouts[ShaderInd]; } @@ -125,33 +126,43 @@ public: void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const; private: + using TShaderStages = ShaderResourceLayoutVk::TShaderStages; + + template <typename PSOCreateInfoType> + void InitInternalObjects(const PSOCreateInfoType& CreateInfo, + std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages, + std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules); + + void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages); + + void Destruct(); + const ShaderResourceLayoutVk& GetStaticShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return m_ShaderResourceLayouts[m_NumShaders + ShaderInd]; + VERIFY_EXPR(ShaderInd < GetNumShaderStages()); + return m_ShaderResourceLayouts[GetNumShaderStages() + ShaderInd]; } const ShaderResourceCacheVk& GetStaticResCache(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < GetNumShaderStages()); return m_StaticResCaches[ShaderInd]; } - ShaderVariableManagerVk& GetStaticVarMgr(Uint32 ShaderInd) const + const ShaderVariableManagerVk& GetStaticVarMgr(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < GetNumShaderStages()); 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; - std::array<VulkanUtilities::ShaderModuleWrapper, MAX_SHADERS_IN_PIPELINE> m_ShaderModules = {}; - VulkanUtilities::PipelineWrapper m_Pipeline; PipelineLayout m_PipelineLayout; diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index 94b91cae..d85e9ff3 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, @@ -192,6 +195,9 @@ public: IDXCompiler* GetDxCompiler() const { return m_pDxCompiler.get(); } private: + template <typename PSOCreateInfoType> + void CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState); + virtual void TestTextureFormat(TEXTURE_FORMAT TexFormat) override final; // Submits command buffer for execution to the command queue diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp index 026bb9da..00f2c33a 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp @@ -76,6 +76,8 @@ public: bool StaticResourcesInitialized() const { return m_bStaticResourcesInitialized; } private: + void Destruct(); + ShaderResourceCacheVk m_ShaderResourceCache; ShaderVariableManagerVk* m_pShaderVarMgrs = nullptr; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp index a5278cb7..7d77ff48 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp @@ -75,7 +75,7 @@ public: }; // clang-format off - ShaderResourceCacheVk(DbgCacheContentType dbgContentType) + ShaderResourceCacheVk(DbgCacheContentType dbgContentType) noexcept #ifdef DILIGENT_DEBUG : m_DbgContentType{dbgContentType} #endif diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp index a6d20641..9452a390 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp @@ -110,12 +110,25 @@ namespace Diligent { +class ShaderVkImpl; + /// Diligent::ShaderResourceLayoutVk class // sizeof(ShaderResourceLayoutVk)==56 (MS compiler, x64) class ShaderResourceLayoutVk { public: - ShaderResourceLayoutVk(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) : + struct ShaderStageInfo + { + ShaderStageInfo(SHADER_TYPE _Type, + const ShaderVkImpl* _pShader); + + const SHADER_TYPE Type; + const ShaderVkImpl* const pShader; + std::vector<uint32_t> SPIRV; + }; + using TShaderStages = std::vector<ShaderStageInfo>; + + ShaderResourceLayoutVk(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) noexcept : m_LogicalDevice{LogicalDevice} { } @@ -131,23 +144,21 @@ public: // This method is called by PipelineStateVkImpl class instance to initialize static // shader resource layout and the cache - void InitializeStaticResourceLayout(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - ShaderResourceCacheVk& StaticResourceCache); + void InitializeStaticResourceLayout(const ShaderVkImpl* pShader, + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderResourceCacheVk& StaticResourceCache); // This method is called by PipelineStateVkImpl class instance to initialize resource // layouts for all shader stages in the pipeline. - static void Initialize(IRenderDevice* pRenderDevice, - Uint32 NumShaders, - ShaderResourceLayoutVk Layouts[], - std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - std::vector<uint32_t> SPIRVs[], - class PipelineLayout& PipelineLayout, - bool VerifyVariables, - bool VerifyStaticSamplers); + static void Initialize(IRenderDevice* pRenderDevice, + TShaderStages& ShaderStages, + ShaderResourceLayoutVk Layouts[], + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + class PipelineLayout& PipelineLayout, + bool VerifyVariables, + bool VerifyImmutableSamplers); // sizeof(VkResource) == 24 (x64) struct VkResource @@ -279,11 +290,10 @@ public: #ifdef DILIGENT_DEVELOPMENT bool dvpVerifyBindings(const ShaderResourceCacheVk& ResourceCache) const; - static void dvpVerifyResourceLayoutDesc(Uint32 NumShaders, - const std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - bool VerifyVariables, - bool VerifyStaticSamplers); + static void dvpVerifyResourceLayoutDesc(const TShaderStages& ShaderStages, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + bool VerifyVariables, + bool VerifyImmutableSamplers); #endif Uint32 GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE VarType) const @@ -308,6 +318,8 @@ public: return m_pResources->GetShaderType(); } + const SPIRVShaderResources& GetResources() const { return *m_pResources; } + const VkResource& GetResource(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const { VERIFY_EXPR(r < m_NumResources[VarType]); @@ -346,16 +358,12 @@ private: return m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES]; } - void AllocateMemory(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers); - - Uint32 FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, - Uint32 CurrResourceCount, - SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) const; + void AllocateMemory(const ShaderVkImpl* pShader, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + bool AllocateImmutableSamplers); using ImmutableSamplerPtrType = RefCntAutoPtr<ISampler>; ImmutableSamplerPtrType& GetImmutableSampler(Uint32 n) noexcept diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp index 9039e04e..27689c1e 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp @@ -73,21 +73,25 @@ class ShaderVariableVkImpl; class ShaderVariableManagerVk { public: - ShaderVariableManagerVk(IObject& Owner, - const ShaderResourceLayoutVk& SrcLayout, - IMemoryAllocator& Allocator, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheVk& ResourceCache); + ShaderVariableManagerVk(IObject& Owner, + ShaderResourceCacheVk& ResourceCache) noexcept : + m_Owner{Owner}, + m_ResourceCache{ResourceCache} + {} + + void Initialize(const ShaderResourceLayoutVk& SrcLayout, + IMemoryAllocator& Allocator, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes); ~ShaderVariableManagerVk(); void DestroyVariables(IMemoryAllocator& Allocator); - ShaderVariableVkImpl* GetVariable(const Char* Name); - ShaderVariableVkImpl* GetVariable(Uint32 Index); + ShaderVariableVkImpl* GetVariable(const Char* Name) const; + ShaderVariableVkImpl* GetVariable(Uint32 Index) const; - void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags); + void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) const; static size_t GetRequiredMemorySize(const ShaderResourceLayoutVk& Layout, const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, @@ -115,7 +119,7 @@ private: Uint32 m_NumVariables = 0; #ifdef DILIGENT_DEBUG - IMemoryAllocator& m_DbgAllocator; + IMemoryAllocator* m_pDbgAllocator = nullptr; #endif }; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp index 51083968..e88c93d2 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp @@ -83,6 +83,9 @@ ATTACHMENT_STORE_OP VkAttachmentStoreOpToAttachmentStoreOp(VkAttachmentStoreOp V VkPipelineStageFlags PipelineStageFlagsToVkPipelineStageFlags(PIPELINE_STAGE_FLAGS PipelineStageFlags); VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags); + +VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType); + VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureFlags(RAYTRACING_BUILD_AS_FLAGS Flags); VkGeometryFlagsKHR GeometryFlagsToVkGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flags); VkGeometryInstanceFlagsKHR InstanceFlagsToVkGeometryInstanceFlags(RAYTRACING_INSTANCE_FLAGS Flags); diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp index 7085765c..6b29af25 100644 --- a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp @@ -59,8 +59,8 @@ BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters, { ValidateBufferInitData(BuffDesc, pBuffData); - if (m_Desc.Usage == USAGE_STATIC) - VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for static buffers"); + if (m_Desc.Usage == USAGE_IMMUTABLE) + VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for immutable buffers"); if (m_Desc.Usage == USAGE_DYNAMIC) VERIFY(pBuffData == nullptr || pBuffData->pData == nullptr, "Initial data must be null for dynamic buffers"); @@ -218,7 +218,7 @@ BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters, VkMemoryPropertyFlags vkMemoryFlags = 0; switch (m_Desc.Usage) { - case USAGE_STATIC: + case USAGE_IMMUTABLE: case USAGE_DEFAULT: case USAGE_DYNAMIC: // Dynamic buffer with SRV or UAV bind flag vkMemoryFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index ba36ff7c..99050318 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -260,39 +260,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(); @@ -384,8 +394,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 (" @@ -414,7 +427,6 @@ void DeviceContextVkImpl::DvpLogRenderPass_PSOMismatch() ss << "<Not set>"; 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; @@ -475,7 +487,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) @@ -1129,7 +1141,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 @@ -1155,14 +1167,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/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp index 7a7d8a07..d37655a5 100644 --- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp @@ -238,7 +238,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E VK_KHR_MAINTENANCE1_EXTENSION_NAME // To allow negative viewport height }; - const auto& DeiceExtFeatures = PhysicalDevice->GetExtFeatures(); + const auto& DeviceExtFeatures = PhysicalDevice->GetExtFeatures(); #define ENABLE_FEATURE(IsFeatureSupported, Feature, FeatureName) \ do \ @@ -248,32 +248,32 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E } while (false) - auto MeshShaderFeats = DeiceExtFeatures.MeshShader; + auto MeshShaderFeats = DeviceExtFeatures.MeshShader; ENABLE_FEATURE(MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE, MeshShaders, "Mesh shaders are"); - auto ShaderFloat16Int8 = DeiceExtFeatures.ShaderFloat16Int8; + auto ShaderFloat16Int8 = DeviceExtFeatures.ShaderFloat16Int8; // clang-format off ENABLE_FEATURE(ShaderFloat16Int8.shaderFloat16 != VK_FALSE, ShaderFloat16, "16-bit float shader operations are"); ENABLE_FEATURE(ShaderFloat16Int8.shaderInt8 != VK_FALSE, ShaderInt8, "8-bit int shader operations are"); // clang-format on - auto Storage16BitFeats = DeiceExtFeatures.Storage16Bit; + auto Storage16BitFeats = DeviceExtFeatures.Storage16Bit; // clang-format off ENABLE_FEATURE(Storage16BitFeats.storageBuffer16BitAccess != VK_FALSE, ResourceBuffer16BitAccess, "16-bit resoure buffer access is"); ENABLE_FEATURE(Storage16BitFeats.uniformAndStorageBuffer16BitAccess != VK_FALSE, UniformBuffer16BitAccess, "16-bit uniform buffer access is"); ENABLE_FEATURE(Storage16BitFeats.storageInputOutput16 != VK_FALSE, ShaderInputOutput16, "16-bit shader inputs/outputs are"); // clang-format on - auto Storage8BitFeats = DeiceExtFeatures.Storage8Bit; + auto Storage8BitFeats = DeviceExtFeatures.Storage8Bit; // clang-format off ENABLE_FEATURE(Storage8BitFeats.storageBuffer8BitAccess != VK_FALSE, ResourceBuffer8BitAccess, "8-bit resoure buffer access is"); ENABLE_FEATURE(Storage8BitFeats.uniformAndStorageBuffer8BitAccess != VK_FALSE, UniformBuffer8BitAccess, "8-bit uniform buffer access is"); // clang-format on - auto RayTracingFeats = DeiceExtFeatures.RayTracing; - auto BufferDeviceAddressFeats = DeiceExtFeatures.BufferDeviceAddress; - auto DescriptorIndexingFeats = DeiceExtFeatures.DescriptorIndexing; - ENABLE_FEATURE(RayTracingFeats.rayTracing != VK_FALSE || DeiceExtFeatures.RayTracingNV, RayTracing, "Ray tracing is"); + auto RayTracingFeats = DeviceExtFeatures.RayTracing; + auto BufferDeviceAddressFeats = DeviceExtFeatures.BufferDeviceAddress; + auto DescriptorIndexingFeats = DeviceExtFeatures.DescriptorIndexing; + ENABLE_FEATURE(RayTracingFeats.rayTracing != VK_FALSE || DeviceExtFeatures.RayTracingNV, RayTracing, "Ray tracing is"); #undef FeatureSupport @@ -396,7 +396,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E // Ray tracing if (EngineCI.Features.RayTracing != DEVICE_FEATURE_STATE_DISABLED) { - if (DeiceExtFeatures.RayTracingNV) + if (DeviceExtFeatures.RayTracingNV) { DeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); DeviceExtensions.push_back(VK_NV_RAY_TRACING_EXTENSION_NAME); @@ -429,7 +429,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E } #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 31, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif DeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data(); diff --git a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp index 5110c873..e7ab95b1 100644 --- a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp +++ b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp @@ -154,23 +154,23 @@ std::array<RefCntAutoPtr<IPipelineState>, 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}; PSODesc.ResourceLayout.Variables = &VarDesc; PSODesc.ResourceLayout.NumVariables = 1; - const StaticSamplerDesc StaticSampler(SHADER_TYPE_COMPUTE, "SrcMip", Sam_LinearClamp); - PSODesc.ResourceLayout.StaticSamplers = &StaticSampler; - PSODesc.ResourceLayout.NumStaticSamplers = 1; + const ImmutableSamplerDesc ImtblSampler{SHADER_TYPE_COMPUTE, "SrcMip", Sam_LinearClamp}; + PSODesc.ResourceLayout.ImmutableSamplers = &ImtblSampler; + PSODesc.ResourceLayout.NumImmutableSamplers = 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/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp index b7d2b1f4..b221659a 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -40,34 +40,6 @@ namespace Diligent { - -static VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType) -{ - static_assert(SHADER_TYPE_LAST == SHADER_TYPE_CALLABLE, "Please update the switch below to handle the new shader type"); - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; - case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; - case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; - case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; - case SHADER_TYPE_AMPLIFICATION: return VK_SHADER_STAGE_TASK_BIT_NV; - case SHADER_TYPE_MESH: return VK_SHADER_STAGE_MESH_BIT_NV; - case SHADER_TYPE_RAY_GEN: return VK_SHADER_STAGE_RAYGEN_BIT_KHR; - case SHADER_TYPE_RAY_MISS: return VK_SHADER_STAGE_MISS_BIT_KHR; - case SHADER_TYPE_RAY_CLOSEST_HIT: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - case SHADER_TYPE_RAY_ANY_HIT: return VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - case SHADER_TYPE_RAY_INTERSECTION: return VK_SHADER_STAGE_INTERSECTION_BIT_KHR; - case SHADER_TYPE_CALLABLE: return VK_SHADER_STAGE_CALLABLE_BIT_KHR; - // clang-format on - default: - UNEXPECTED("Unknown shader type"); - return VK_SHADER_STAGE_VERTEX_BIT; - } -} - class ResourceTypeToVkDescriptorType { public: @@ -241,7 +213,7 @@ bool PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::operator== if ((B0.pImmutableSamplers != nullptr && B1.pImmutableSamplers == nullptr) || (B0.pImmutableSamplers == nullptr && B1.pImmutableSamplers != nullptr)) return false; - // Static samplers themselves should not affect compatibility + // Immutable samplers themselves should not affect compatibility // clang-format on } return true; diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 5c165e32..83512870 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -129,346 +129,324 @@ RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc( return RPDesc; } -static std::vector<uint32_t> StripReflection(const std::vector<uint32_t>& OriginalSPIRV) +static bool StripReflection(std::vector<uint32_t>& SPIRV) { #if DILIGENT_NO_HLSL - return OriginalSPIRV; + return false; #else std::vector<uint32_t> StrippedSPIRV; spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); // Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions // removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation. SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); - auto res = SpirvOptimizer.Run(OriginalSPIRV.data(), OriginalSPIRV.size(), &StrippedSPIRV); - if (!res) + if (SpirvOptimizer.Run(SPIRV.data(), SPIRV.size(), &StrippedSPIRV)) { - // Optimized SPIRV may be invalid - StrippedSPIRV.clear(); + SPIRV = std::move(StrippedSPIRV); + return true; } - return StrippedSPIRV; + else + return false; #endif } -PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pDeviceVk, - const PipelineStateCreateInfo& CreateInfo) : - TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, - m_SRBMemAllocator{GetRawAllocator()} +static void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, + ShaderResourceLayoutVk::TShaderStages& ShaderStages, + std::vector<VulkanUtilities::ShaderModuleWrapper>& vkShaderModules, + std::vector<VkPipelineShaderStageCreateInfo>& vkPipelineShaderStages) { - m_ResourceLayoutIndex.fill(-1); - - const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); - - // Initialize shader resource layouts - auto& ShaderResLayoutAllocator = GetRawAllocator(); - - std::array<std::shared_ptr<const SPIRVShaderResources>, MAX_SHADERS_IN_PIPELINE> ShaderResources; - std::array<std::vector<uint32_t>, MAX_SHADERS_IN_PIPELINE> ShaderSPIRVs; - - m_ShaderResourceLayouts = ALLOCATE(ShaderResLayoutAllocator, "Raw memory for ShaderResourceLayoutVk", ShaderResourceLayoutVk, m_NumShaders * 2); - m_StaticResCaches = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceCacheVk", ShaderResourceCacheVk, m_NumShaders); - m_StaticVarsMgrs = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerVk", ShaderVariableManagerVk, m_NumShaders); - - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk{LogicalDevice}; - auto* pShaderVk = GetShader<const ShaderVkImpl>(s); - ShaderResources[s] = pShaderVk->GetShaderResources(); - ShaderSPIRVs[s] = pShaderVk->GetSPIRV(); - - const auto ShaderType = pShaderVk->GetDesc().ShaderType; - const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); - m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s); - - auto* pStaticResLayout = new (m_ShaderResourceLayouts + m_NumShaders + s) ShaderResourceLayoutVk{LogicalDevice}; - auto* pStaticResCache = new (m_StaticResCaches + s) ShaderResourceCacheVk{ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources}; - pStaticResLayout->InitializeStaticResourceLayout(ShaderResources[s], ShaderResLayoutAllocator, m_Desc.ResourceLayout, m_StaticResCaches[s]); - - new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, *pStaticResLayout, GetRawAllocator(), nullptr, 0, *pStaticResCache}; - } - ShaderResourceLayoutVk::Initialize(pDeviceVk, m_NumShaders, m_ShaderResourceLayouts, ShaderResources.data(), GetRawAllocator(), - m_Desc.ResourceLayout, ShaderSPIRVs.data(), m_PipelineLayout, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); - m_PipelineLayout.Finalize(LogicalDevice); - - if (m_Desc.SRBAllocationGranularity > 1) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + auto& StageInfo = ShaderStages[s]; - Uint32 UnusedNumVars = 0; - ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(m_ShaderResourceLayouts[s], AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars); - } - - Uint32 NumSets = 0; - auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets); - auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data()); + VkPipelineShaderStageCreateInfo StageCI = {}; - m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, m_NumShaders, ShaderVariableDataSizes.data(), 1, &CacheMemorySize); - } - - // Create shader modules and initialize shader stages - std::array<VkPipelineShaderStageCreateInfo, MAX_SHADERS_IN_PIPELINE> ShaderStages = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - auto* pShaderVk = GetShader<const ShaderVkImpl>(s); - auto ShaderType = pShaderVk->GetDesc().ShaderType; - - auto& StageCI = ShaderStages[s]; StageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; StageCI.pNext = nullptr; StageCI.flags = 0; // reserved for future use - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: StageCI.stage = VK_SHADER_STAGE_VERTEX_BIT; break; - case SHADER_TYPE_HULL: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; break; - case SHADER_TYPE_DOMAIN: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; break; - case SHADER_TYPE_GEOMETRY: StageCI.stage = VK_SHADER_STAGE_GEOMETRY_BIT; break; - case SHADER_TYPE_PIXEL: StageCI.stage = VK_SHADER_STAGE_FRAGMENT_BIT; break; - case SHADER_TYPE_COMPUTE: StageCI.stage = VK_SHADER_STAGE_COMPUTE_BIT; break; - case SHADER_TYPE_AMPLIFICATION: StageCI.stage = VK_SHADER_STAGE_TASK_BIT_NV; break; - case SHADER_TYPE_MESH: StageCI.stage = VK_SHADER_STAGE_MESH_BIT_NV; break; - default: UNEXPECTED("Unknown shader type"); - // clang-format on - } + StageCI.stage = ShaderTypeToVkShaderStageFlagBit(StageInfo.Type); VkShaderModuleCreateInfo ShaderModuleCI = {}; ShaderModuleCI.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; ShaderModuleCI.pNext = nullptr; ShaderModuleCI.flags = 0; - const auto& SPIRV = ShaderSPIRVs[s]; // We have to strip reflection instructions to fix the follownig validation error: // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string // Optimizer also performs validation and may catch problems with the byte code. - auto StrippedSPIRV = StripReflection(SPIRV); - if (!StrippedSPIRV.empty()) - { - ShaderModuleCI.codeSize = StrippedSPIRV.size() * sizeof(uint32_t); - ShaderModuleCI.pCode = StrippedSPIRV.data(); - } - else - { - LOG_ERROR("Failed to strip reflection information from shader '", pShaderVk->GetDesc().Name, "'. This may indicate a problem with the byte code."); - ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); - ShaderModuleCI.pCode = SPIRV.data(); - } + if (!StripReflection(StageInfo.SPIRV)) + LOG_ERROR("Failed to strip reflection information from shader '", StageInfo.pShader->GetDesc().Name, "'. This may indicate a problem with the byte code."); + + ShaderModuleCI.codeSize = StageInfo.SPIRV.size() * sizeof(uint32_t); + ShaderModuleCI.pCode = StageInfo.SPIRV.data(); - m_ShaderModules[s] = LogicalDevice.CreateShaderModule(ShaderModuleCI, pShaderVk->GetDesc().Name); + vkShaderModules.push_back(LogicalDevice.CreateShaderModule(ShaderModuleCI, StageInfo.pShader->GetDesc().Name)); - StageCI.module = m_ShaderModules[s]; - StageCI.pName = pShaderVk->GetEntryPoint(); + StageCI.module = vkShaderModules.back(); + StageCI.pName = StageInfo.pShader->GetEntryPoint(); StageCI.pSpecializationInfo = nullptr; + + vkPipelineShaderStages.push_back(StageCI); } - // Create pipeline - if (m_Desc.IsComputePipeline()) - { - auto& ComputePipeline = m_Desc.ComputePipeline; + VERIFY_EXPR(vkShaderModules.size() == vkPipelineShaderStages.size()); +} - if (ComputePipeline.pCS == nullptr) - LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc"); - VkComputePipelineCreateInfo PipelineCI = {}; +static void CreateComputePipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector<VkPipelineShaderStageCreateInfo>& Stages, + const PipelineLayout& Layout, + const PipelineStateDesc& PSODesc, + VulkanUtilities::PipelineWrapper& Pipeline) +{ + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + + VkComputePipelineCreateInfo PipelineCI = {}; - PipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - PipelineCI.pNext = nullptr; + PipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + PipelineCI.pNext = nullptr; #ifdef DILIGENT_DEBUG - PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; + PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; #endif - PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from - PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from + PipelineCI.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 - PipelineCI.stage = ShaderStages[0]; - PipelineCI.layout = m_PipelineLayout.GetVkPipelineLayout(); + PipelineCI.stage = Stages[0]; + PipelineCI.layout = Layout.GetVkPipelineLayout(); - m_Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); - } - else - { - const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); - auto& GraphicsPipeline = m_Desc.GraphicsPipeline; - auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); + Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, PSODesc.Name); +} - if (m_pRenderPass == nullptr) - { - RenderPassCache::RenderPassCacheKey Key{ - GraphicsPipeline.NumRenderTargets, - GraphicsPipeline.SmplDesc.Count, - GraphicsPipeline.RTVFormats, - GraphicsPipeline.DSVFormat}; - m_pRenderPass = RPCache.GetRenderPass(Key); - } - VkGraphicsPipelineCreateInfo PipelineCI = {}; +static void CreateGraphicsPipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector<VkPipelineShaderStageCreateInfo>& Stages, + const PipelineLayout& Layout, + const PipelineStateDesc& PSODesc, + const GraphicsPipelineDesc& GraphicsPipeline, + VulkanUtilities::PipelineWrapper& Pipeline, + RefCntAutoPtr<IRenderPass>& pRenderPass) +{ + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); + auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); + + if (pRenderPass == nullptr) + { + RenderPassCache::RenderPassCacheKey Key{ + GraphicsPipeline.NumRenderTargets, + GraphicsPipeline.SmplDesc.Count, + GraphicsPipeline.RTVFormats, + GraphicsPipeline.DSVFormat}; + pRenderPass = RPCache.GetRenderPass(Key); + } + + VkGraphicsPipelineCreateInfo PipelineCI = {}; - PipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - PipelineCI.pNext = nullptr; + PipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + PipelineCI.pNext = nullptr; #ifdef DILIGENT_DEBUG - PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; + PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; #endif - PipelineCI.stageCount = m_NumShaders; - PipelineCI.pStages = ShaderStages.data(); - PipelineCI.layout = m_PipelineLayout.GetVkPipelineLayout(); + PipelineCI.stageCount = static_cast<Uint32>(Stages.size()); + PipelineCI.pStages = Stages.data(); + PipelineCI.layout = Layout.GetVkPipelineLayout(); - VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {}; + VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {}; - std::array<VkVertexInputBindingDescription, MAX_LAYOUT_ELEMENTS> BindingDescriptions; - std::array<VkVertexInputAttributeDescription, MAX_LAYOUT_ELEMENTS> AttributeDescription; - InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, VertexInputStateCI, BindingDescriptions, AttributeDescription); - PipelineCI.pVertexInputState = &VertexInputStateCI; + std::array<VkVertexInputBindingDescription, MAX_LAYOUT_ELEMENTS> BindingDescriptions; + std::array<VkVertexInputAttributeDescription, MAX_LAYOUT_ELEMENTS> AttributeDescription; + InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, VertexInputStateCI, BindingDescriptions, AttributeDescription); + PipelineCI.pVertexInputState = &VertexInputStateCI; - VkPipelineInputAssemblyStateCreateInfo InputAssemblyCI = {}; + VkPipelineInputAssemblyStateCreateInfo InputAssemblyCI = {}; - InputAssemblyCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - InputAssemblyCI.pNext = nullptr; - InputAssemblyCI.flags = 0; // reserved for future use - InputAssemblyCI.primitiveRestartEnable = VK_FALSE; - PipelineCI.pInputAssemblyState = &InputAssemblyCI; + InputAssemblyCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + InputAssemblyCI.pNext = nullptr; + InputAssemblyCI.flags = 0; // reserved for future use + InputAssemblyCI.primitiveRestartEnable = VK_FALSE; + PipelineCI.pInputAssemblyState = &InputAssemblyCI; - VkPipelineTessellationStateCreateInfo TessStateCI = {}; + VkPipelineTessellationStateCreateInfo TessStateCI = {}; - TessStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - TessStateCI.pNext = nullptr; - TessStateCI.flags = 0; // reserved for future use - PipelineCI.pTessellationState = &TessStateCI; + TessStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + TessStateCI.pNext = nullptr; + TessStateCI.flags = 0; // reserved for future use + PipelineCI.pTessellationState = &TessStateCI; - if (m_Desc.PipelineType == PIPELINE_TYPE_MESH) - { - // Input assembly is not used in the mesh pipeline, so topology may contain any value. - // Validation layers may generate a warning if point_list topology is used, so use MAX_ENUM value. - InputAssemblyCI.topology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + 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. + InputAssemblyCI.topology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; - // Vertex input state and tessellation state are ignored in a mesh pipeline and should be null. - PipelineCI.pVertexInputState = nullptr; - PipelineCI.pTessellationState = nullptr; - } - else - { - PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(GraphicsPipeline.PrimitiveTopology, InputAssemblyCI.topology, TessStateCI.patchControlPoints); - } + // Vertex input state and tessellation state are ignored in a mesh pipeline and should be null. + PipelineCI.pVertexInputState = nullptr; + PipelineCI.pTessellationState = nullptr; + } + else + { + PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(GraphicsPipeline.PrimitiveTopology, InputAssemblyCI.topology, TessStateCI.patchControlPoints); + } - VkPipelineViewportStateCreateInfo ViewPortStateCI = {}; - - ViewPortStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - ViewPortStateCI.pNext = nullptr; - ViewPortStateCI.flags = 0; // reserved for future use - ViewPortStateCI.viewportCount = - GraphicsPipeline.NumViewports; // Even though we use dynamic viewports, the number of viewports used - // by the pipeline is still specified by the viewportCount member (23.5) - ViewPortStateCI.pViewports = nullptr; // We will be using dynamic viewport & scissor states - ViewPortStateCI.scissorCount = ViewPortStateCI.viewportCount; // the number of scissors must match the number of viewports (23.5) - // (why the hell it is in the struct then?) - VkRect2D ScissorRect = {}; - if (GraphicsPipeline.RasterizerDesc.ScissorEnable) - { - ViewPortStateCI.pScissors = nullptr; // Ignored if the scissor state is dynamic - } - else + VkPipelineViewportStateCreateInfo ViewPortStateCI = {}; + + ViewPortStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + ViewPortStateCI.pNext = nullptr; + ViewPortStateCI.flags = 0; // reserved for future use + ViewPortStateCI.viewportCount = + GraphicsPipeline.NumViewports; // Even though we use dynamic viewports, the number of viewports used + // by the pipeline is still specified by the viewportCount member (23.5) + ViewPortStateCI.pViewports = nullptr; // We will be using dynamic viewport & scissor states + ViewPortStateCI.scissorCount = ViewPortStateCI.viewportCount; // the number of scissors must match the number of viewports (23.5) + // (why the hell it is in the struct then?) + VkRect2D ScissorRect = {}; + if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + { + ViewPortStateCI.pScissors = nullptr; // Ignored if the scissor state is dynamic + } + else + { + const auto& Props = PhysicalDevice.GetProperties(); + // There are limitiations on the viewport width and height (23.5), but + // it is not clear if there are limitations on the scissor rect width and + // height + ScissorRect.extent.width = Props.limits.maxViewportDimensions[0]; + ScissorRect.extent.height = Props.limits.maxViewportDimensions[1]; + ViewPortStateCI.pScissors = &ScissorRect; + } + PipelineCI.pViewportState = &ViewPortStateCI; + + VkPipelineRasterizationStateCreateInfo RasterizerStateCI = + RasterizerStateDesc_To_VkRasterizationStateCI(GraphicsPipeline.RasterizerDesc); + PipelineCI.pRasterizationState = &RasterizerStateCI; + + // Multisample state (24) + VkPipelineMultisampleStateCreateInfo MSStateCI = {}; + + MSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + MSStateCI.pNext = nullptr; + MSStateCI.flags = 0; // reserved for future use + // If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of + // pMultisampleState must be the same as the sample count for those subpass attachments + MSStateCI.rasterizationSamples = static_cast<VkSampleCountFlagBits>(GraphicsPipeline.SmplDesc.Count); + MSStateCI.sampleShadingEnable = VK_FALSE; + MSStateCI.minSampleShading = 0; // a minimum fraction of sample shading if sampleShadingEnable is set to VK_TRUE. + uint32_t SampleMask[] = {GraphicsPipeline.SampleMask, 0}; // Vulkan spec allows up to 64 samples + MSStateCI.pSampleMask = SampleMask; // an array of static coverage information that is ANDed with + // the coverage information generated during rasterization (25.3) + MSStateCI.alphaToCoverageEnable = VK_FALSE; // whether a temporary coverage value is generated based on + // the alpha component of the fragment's first color output + MSStateCI.alphaToOneEnable = VK_FALSE; // whether the alpha component of the fragment's first color output is replaced with one + PipelineCI.pMultisampleState = &MSStateCI; + + VkPipelineDepthStencilStateCreateInfo DepthStencilStateCI = + DepthStencilStateDesc_To_VkDepthStencilStateCI(GraphicsPipeline.DepthStencilDesc); + PipelineCI.pDepthStencilState = &DepthStencilStateCI; + + const auto& RPDesc = pRenderPass->GetDesc(); + const auto NumRTAttachments = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex].RenderTargetAttachmentCount; + VERIFY_EXPR(GraphicsPipeline.pRenderPass != nullptr || GraphicsPipeline.NumRenderTargets == NumRTAttachments); + std::vector<VkPipelineColorBlendAttachmentState> ColorBlendAttachmentStates(NumRTAttachments); + + VkPipelineColorBlendStateCreateInfo BlendStateCI = {}; + + BlendStateCI.pAttachments = !ColorBlendAttachmentStates.empty() ? ColorBlendAttachmentStates.data() : nullptr; + BlendStateCI.attachmentCount = NumRTAttachments; // must equal the colorAttachmentCount for the subpass + // in which this pipeline is used. + BlendStateDesc_To_VkBlendStateCI(GraphicsPipeline.BlendDesc, BlendStateCI, ColorBlendAttachmentStates); + PipelineCI.pColorBlendState = &BlendStateCI; + + + VkPipelineDynamicStateCreateInfo DynamicStateCI = {}; + + DynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + DynamicStateCI.pNext = nullptr; + DynamicStateCI.flags = 0; // reserved for future use + std::vector<VkDynamicState> DynamicStates = { - const auto& Props = PhysicalDevice.GetProperties(); - // There are limitiations on the viewport width and height (23.5), but - // it is not clear if there are limitations on the scissor rect width and - // height - ScissorRect.extent.width = Props.limits.maxViewportDimensions[0]; - ScissorRect.extent.height = Props.limits.maxViewportDimensions[1]; - ViewPortStateCI.pScissors = &ScissorRect; - } - PipelineCI.pViewportState = &ViewPortStateCI; - - VkPipelineRasterizationStateCreateInfo RasterizerStateCI = - RasterizerStateDesc_To_VkRasterizationStateCI(GraphicsPipeline.RasterizerDesc); - PipelineCI.pRasterizationState = &RasterizerStateCI; - - // Multisample state (24) - VkPipelineMultisampleStateCreateInfo MSStateCI = {}; - - MSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - MSStateCI.pNext = nullptr; - MSStateCI.flags = 0; // reserved for future use - // If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of - // pMultisampleState must be the same as the sample count for those subpass attachments - MSStateCI.rasterizationSamples = static_cast<VkSampleCountFlagBits>(GraphicsPipeline.SmplDesc.Count); - MSStateCI.sampleShadingEnable = VK_FALSE; - MSStateCI.minSampleShading = 0; // a minimum fraction of sample shading if sampleShadingEnable is set to VK_TRUE. - uint32_t SampleMask[] = {GraphicsPipeline.SampleMask, 0}; // Vulkan spec allows up to 64 samples - MSStateCI.pSampleMask = SampleMask; // an array of static coverage information that is ANDed with - // the coverage information generated during rasterization (25.3) - MSStateCI.alphaToCoverageEnable = VK_FALSE; // whether a temporary coverage value is generated based on - // the alpha component of the fragment's first color output - MSStateCI.alphaToOneEnable = VK_FALSE; // whether the alpha component of the fragment's first color output is replaced with one - PipelineCI.pMultisampleState = &MSStateCI; - - VkPipelineDepthStencilStateCreateInfo DepthStencilStateCI = - DepthStencilStateDesc_To_VkDepthStencilStateCI(GraphicsPipeline.DepthStencilDesc); - PipelineCI.pDepthStencilState = &DepthStencilStateCI; - - const auto& RPDesc = m_pRenderPass->GetDesc(); - const auto NumRTAttachments = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex].RenderTargetAttachmentCount; - VERIFY_EXPR(GraphicsPipeline.pRenderPass != nullptr || GraphicsPipeline.NumRenderTargets == NumRTAttachments); - std::vector<VkPipelineColorBlendAttachmentState> ColorBlendAttachmentStates(NumRTAttachments); - - VkPipelineColorBlendStateCreateInfo BlendStateCI = {}; - - BlendStateCI.pAttachments = !ColorBlendAttachmentStates.empty() ? ColorBlendAttachmentStates.data() : nullptr; - BlendStateCI.attachmentCount = NumRTAttachments; // must equal the colorAttachmentCount for the subpass - // in which this pipeline is used. - BlendStateDesc_To_VkBlendStateCI(GraphicsPipeline.BlendDesc, BlendStateCI, ColorBlendAttachmentStates); - PipelineCI.pColorBlendState = &BlendStateCI; - - - VkPipelineDynamicStateCreateInfo DynamicStateCI = {}; - - DynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - DynamicStateCI.pNext = nullptr; - DynamicStateCI.flags = 0; // reserved for future use - std::vector<VkDynamicState> DynamicStates = - { - VK_DYNAMIC_STATE_VIEWPORT, // pViewports state in VkPipelineViewportStateCreateInfo will be ignored and must be - // set dynamically with vkCmdSetViewport before any draw commands. The number of viewports - // used by a pipeline is still specified by the viewportCount member of - // VkPipelineViewportStateCreateInfo. + VK_DYNAMIC_STATE_VIEWPORT, // pViewports state in VkPipelineViewportStateCreateInfo will be ignored and must be + // set dynamically with vkCmdSetViewport before any draw commands. The number of viewports + // used by a pipeline is still specified by the viewportCount member of + // VkPipelineViewportStateCreateInfo. + + VK_DYNAMIC_STATE_BLEND_CONSTANTS, // blendConstants state in VkPipelineColorBlendStateCreateInfo will be ignored + // and must be set dynamically with vkCmdSetBlendConstants + + VK_DYNAMIC_STATE_STENCIL_REFERENCE // pecifies that the reference state in VkPipelineDepthStencilStateCreateInfo + // for both front and back will be ignored and must be set dynamically + // with vkCmdSetStencilReference + }; + + if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + { + // pScissors state in VkPipelineViewportStateCreateInfo will be ignored and must be set + // dynamically with vkCmdSetScissor before any draw commands. The number of scissor rectangles + // used by a pipeline is still specified by the scissorCount member of + // VkPipelineViewportStateCreateInfo. + DynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR); + } + DynamicStateCI.dynamicStateCount = static_cast<uint32_t>(DynamicStates.size()); + DynamicStateCI.pDynamicStates = DynamicStates.data(); + PipelineCI.pDynamicState = &DynamicStateCI; - VK_DYNAMIC_STATE_BLEND_CONSTANTS, // blendConstants state in VkPipelineColorBlendStateCreateInfo will be ignored - // and must be set dynamically with vkCmdSetBlendConstants - VK_DYNAMIC_STATE_STENCIL_REFERENCE // pecifies that the reference state in VkPipelineDepthStencilStateCreateInfo - // for both front and back will be ignored and must be set dynamically - // with vkCmdSetStencilReference - }; + PipelineCI.renderPass = pRenderPass.RawPtr<IRenderPassVk>()->GetVkRenderPass(); + 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 - if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, PSODesc.Name); +} + +void PipelineStateVkImpl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages) +{ + auto* const pDeviceVk = GetDevice(); + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + + for (size_t s = 0; s < ShaderStages.size(); ++s) + { + auto& StageInfo = ShaderStages[s]; + const auto ShaderType = StageInfo.Type; + const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); + + m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s); + + auto& StaticResLayout = m_ShaderResourceLayouts[GetNumShaderStages() + s]; + StaticResLayout.InitializeStaticResourceLayout(StageInfo.pShader, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]); + + m_StaticVarsMgrs[s].Initialize(StaticResLayout, GetRawAllocator(), nullptr, 0); + } + ShaderResourceLayoutVk::Initialize(pDeviceVk, ShaderStages, m_ShaderResourceLayouts, GetRawAllocator(), + m_Desc.ResourceLayout, m_PipelineLayout, + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS) == 0); + m_PipelineLayout.Finalize(LogicalDevice); + + if (m_Desc.SRBAllocationGranularity > 1) + { + std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {}; + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { - // pScissors state in VkPipelineViewportStateCreateInfo will be ignored and must be set - // dynamically with vkCmdSetScissor before any draw commands. The number of scissor rectangles - // used by a pipeline is still specified by the scissorCount member of - // VkPipelineViewportStateCreateInfo. - DynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR); - } - DynamicStateCI.dynamicStateCount = static_cast<uint32_t>(DynamicStates.size()); - DynamicStateCI.pDynamicStates = DynamicStates.data(); - PipelineCI.pDynamicState = &DynamicStateCI; + const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + Uint32 UnusedNumVars = 0; + ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(m_ShaderResourceLayouts[s], AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars); + } - PipelineCI.renderPass = GetRenderPass()->GetVkRenderPass(); - PipelineCI.subpass = m_Desc.GraphicsPipeline.SubpassIndex; - PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from - PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from + Uint32 NumSets = 0; + auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets); + auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data()); - m_Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); + m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderVariableDataSizes.data(), 1, &CacheMemorySize); } m_HasStaticResources = false; m_HasNonStaticResources = false; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) != 0) @@ -482,34 +460,137 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun m_ShaderResourceLayoutHash = m_PipelineLayout.GetHash(); } +template <typename PSOCreateInfoType> +void PipelineStateVkImpl::InitInternalObjects(const PSOCreateInfoType& CreateInfo, + std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages, + std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules) +{ + m_ResourceLayoutIndex.fill(-1); + + TShaderStages ShaderStages; + ExtractShaders<ShaderVkImpl>(CreateInfo, ShaderStages); + + LinearAllocator MemPool{GetRawAllocator()}; + + const auto NumShaderStages = GetNumShaderStages(); + VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size()); + + MemPool.AddSpace<ShaderResourceCacheVk>(NumShaderStages); + MemPool.AddSpace<ShaderResourceLayoutVk>(NumShaderStages * 2); + MemPool.AddSpace<ShaderVariableManagerVk>(NumShaderStages); + + ReserveSpaceForPipelineDesc(CreateInfo, MemPool); + + MemPool.Reserve(); + + const auto& LogicalDevice = GetDevice()->GetLogicalDevice(); + + m_StaticResCaches = MemPool.ConstructArray<ShaderResourceCacheVk>(NumShaderStages, ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources); + + // The memory is now owned by PipelineStateVkImpl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_StaticResCaches); + (void)Ptr; + + m_ShaderResourceLayouts = MemPool.ConstructArray<ShaderResourceLayoutVk>(NumShaderStages * 2, LogicalDevice); + + m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerVk>(NumShaderStages); + for (Uint32 s = 0; s < NumShaderStages; ++s) + new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, m_StaticResCaches[s]}; + + InitializePipelineDesc(CreateInfo, MemPool); + + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects + + InitResourceLayouts(CreateInfo, ShaderStages); + + // Create shader modules and initialize shader stages + InitPipelineShaderStages(GetDevice()->GetLogicalDevice(), ShaderStages, ShaderModules, vkShaderStages); +} + +PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVk, + const GraphicsPipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + try + { + std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages; + std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules; + + InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules); + + CreateGraphicsPipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass); + } + catch (...) + { + Destruct(); + throw; + } +} + + +PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVk, + const ComputePipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + try + { + std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages; + std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules; + + InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules); + + CreateComputePipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline); + } + catch (...) + { + Destruct(); + throw; + } +} + + PipelineStateVkImpl::~PipelineStateVkImpl() { + Destruct(); +} + +void PipelineStateVkImpl::Destruct() +{ m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask); m_PipelineLayout.Release(m_pDevice, m_Desc.CommandQueueMask); - for (auto& ShaderModule : m_ShaderModules) + auto& RawAllocator = GetRawAllocator(); + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { - if (ShaderModule != VK_NULL_HANDLE) + if (m_StaticVarsMgrs != nullptr) { - m_pDevice->SafeReleaseDeviceObject(std::move(ShaderModule), m_Desc.CommandQueueMask); + m_StaticVarsMgrs[s].DestroyVariables(GetRawAllocator()); + m_StaticVarsMgrs[s].~ShaderVariableManagerVk(); } - } - auto& RawAllocator = GetRawAllocator(); - for (Uint32 s = 0; s < m_NumShaders * 2; ++s) - { - m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk(); + if (m_ShaderResourceLayouts != nullptr) + { + m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk(); + m_ShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutVk(); + } + + if (m_StaticResCaches != nullptr) + { + m_StaticResCaches[s].~ShaderResourceCacheVk(); + } } - for (Uint32 s = 0; s < m_NumShaders; ++s) + // All internal objects are allocted in contiguous chunks of memory. + if (void* pRawMem = m_StaticResCaches) { - m_StaticResCaches[s].~ShaderResourceCacheVk(); - m_StaticVarsMgrs[s].DestroyVariables(GetRawAllocator()); - m_StaticVarsMgrs[s].~ShaderVariableManagerVk(); + RawAllocator.Free(pRawMem); } - RawAllocator.Free(m_ShaderResourceLayouts); - RawAllocator.Free(m_StaticResCaches); - RawAllocator.Free(m_StaticVarsMgrs); } IMPLEMENT_QUERY_INTERFACE(PipelineStateVkImpl, IID_PipelineStateVk, TPipelineStateBase) @@ -540,23 +621,22 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const #ifdef DILIGENT_DEBUG { bool IsCompatibleShaders = true; - if (m_NumShaders != pPSOVk->m_NumShaders) + if (GetNumShaderStages() != pPSOVk->GetNumShaderStages()) IsCompatibleShaders = false; if (IsCompatibleShaders) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { - auto* pShader0 = GetShader<const ShaderVkImpl>(s); - auto* pShader1 = pPSOVk->GetShader<const ShaderVkImpl>(s); - if (pShader0->GetDesc().ShaderType != pShader1->GetDesc().ShaderType) + if (GetShaderStageType(s) != pPSOVk->GetShaderStageType(s)) { IsCompatibleShaders = false; break; } - const auto* pRes0 = pShader0->GetShaderResources().get(); - const auto* pRes1 = pShader1->GetShaderResources().get(); - if (!pRes0->IsCompatibleWith(*pRes1)) + + const auto& Res0 = GetShaderResLayout(s).GetResources(); + const auto& Res1 = pPSOVk->GetShaderResLayout(s).GetResources(); + if (!Res0.IsCompatibleWith(Res1)) { IsCompatibleShaders = false; break; @@ -614,7 +694,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind auto& ResourceCache = pResBindingVkImpl->GetResourceCache(); #ifdef DILIGENT_DEVELOPMENT - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { m_ShaderResourceLayouts[s].dvpVerifyBindings(ResourceCache); } @@ -649,7 +729,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind // Allocate vulkan descriptor set for dynamic resources DynamicDescrSet = pCtxVkImpl->AllocateDynamicDescriptorSet(DynamicDescriptorSetVkLayout, DynamicDescrSetName); // Commit all dynamic resource descriptors - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) != 0) @@ -666,7 +746,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind void PipelineStateVkImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { auto ShaderType = GetStaticShaderResLayout(s).GetShaderType(); if ((ShaderType & ShaderFlags) != 0) @@ -703,24 +783,24 @@ IShaderResourceVariable* PipelineStateVkImpl::GetStaticVariableByIndex(SHADER_TY if (LayoutInd < 0) return nullptr; - auto& StaticVarMgr = GetStaticVarMgr(LayoutInd); + const auto& StaticVarMgr = GetStaticVarMgr(LayoutInd); return StaticVarMgr.GetVariable(Index); } void PipelineStateVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { const auto& StaticResLayout = GetStaticShaderResLayout(s); const auto& StaticResCache = GetStaticResCache(s); + #ifdef DILIGENT_DEVELOPMENT if (!StaticResLayout.dvpVerifyBindings(StaticResCache)) { - const auto* pShaderVk = GetShader<const ShaderVkImpl>(s); LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", GetDesc().Name, "' will not be successfully initialized because not all static resource bindings in shader '", - pShaderVk->GetDesc().Name, + GetShaderTypeLiteralName(GetShaderStageType(s)), "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method."); } diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 6e5ec710..cdcac036 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -106,6 +106,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors}, {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors}, {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors}, }, EngineCI.MainDescriptorPoolSize.MaxDescriptorSets, true @@ -126,6 +127,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors}, }, EngineCI.DynamicDescriptorPoolSize.MaxDescriptorSets, false // Pools can only be reset @@ -217,6 +219,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* // The following features are always enabled Features.SeparablePrograms = DEVICE_FEATURE_STATE_ENABLED; + Features.ShaderResourceQueries = DEVICE_FEATURE_STATE_ENABLED; Features.IndirectRendering = DEVICE_FEATURE_STATE_ENABLED; Features.MultithreadedResourceCreation = DEVICE_FEATURE_STATE_ENABLED; Features.ComputeShaders = DEVICE_FEATURE_STATE_ENABLED; @@ -226,7 +229,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* Features.DurationQueries = DEVICE_FEATURE_STATE_ENABLED; #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 31, "Did you add a new feature to DeviceFeatures? Please handle its satus here (if necessary)."); + static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here (if necessary)."); #endif const auto& vkDeviceLimits = m_PhysicalDevice->GetProperties().limits; @@ -545,7 +548,8 @@ void RenderDeviceVkImpl::TestTextureFormat(TEXTURE_FORMAT TexFormat) IMPLEMENT_QUERY_INTERFACE(RenderDeviceVkImpl, IID_RenderDeviceVk, TRenderDeviceBase) -void RenderDeviceVkImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +template <typename PSOCreateInfoType> +void RenderDeviceVkImpl::CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState) { CreateDeviceObject( "Pipeline State", PSOCreateInfo.PSODesc, ppPipelineState, @@ -558,6 +562,17 @@ void RenderDeviceVkImpl::CreatePipelineState(const PipelineStateCreateInfo& PSOC ); } +void RenderDeviceVkImpl::CreateGraphicsPipelineState(const GraphicsPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState); +} + + +void RenderDeviceVkImpl::CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState); +} + void RenderDeviceVkImpl::CreateBufferFromVulkanResource(VkBuffer vkBuffer, const BufferDesc& BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) { diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp index 6e6c142f..3e4a65cf 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp @@ -30,6 +30,7 @@ #include "PipelineStateVkImpl.hpp" #include "ShaderVkImpl.hpp" #include "RenderDeviceVkImpl.hpp" +#include "LinearAllocator.hpp" namespace Diligent { @@ -47,55 +48,79 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pR m_ShaderResourceCache{ShaderResourceCacheVk::DbgCacheContentType::SRBResources} // clang-format on { - m_ResourceLayoutIndex.fill(-1); + try + { + m_ResourceLayoutIndex.fill(-1); - auto* ppShaders = pPSO->GetShaders(); - m_NumShaders = static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaders()); + m_NumShaders = static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaderStages()); - auto* pRenderDeviceVkImpl = pPSO->GetDevice(); - // This will only allocate memory and initialize descriptor sets in the resource cache - // Resources will be initialized by InitializeResourceMemoryInCache() - auto& ResourceCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0); - pPSO->GetPipelineLayout().InitResourceCache(pRenderDeviceVkImpl, m_ShaderResourceCache, ResourceCacheDataAllocator, pPSO->GetDesc().Name); + LinearAllocator MemPool{GetRawAllocator()}; + MemPool.AddSpace<ShaderVariableManagerVk>(m_NumShaders); + MemPool.Reserve(); + m_pShaderVarMgrs = MemPool.ConstructArray<ShaderVariableManagerVk>(m_NumShaders, std::ref(*this), std::ref(m_ShaderResourceCache)); - m_pShaderVarMgrs = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerVk", ShaderVariableManagerVk, m_NumShaders); + // The memory is now owned by ShaderResourceBindingVkImpl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_pShaderVarMgrs); + (void)Ptr; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - auto* pShader = ppShaders[s]; - auto ShaderType = pShader->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPSO->GetDesc().PipelineType); + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects - m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); + auto* pRenderDeviceVkImpl = pPSO->GetDevice(); + // This will only allocate memory and initialize descriptor sets in the resource cache + // Resources will be initialized by InitializeResourceMemoryInCache() + auto& ResourceCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0); + pPSO->GetPipelineLayout().InitResourceCache(pRenderDeviceVkImpl, m_ShaderResourceCache, ResourceCacheDataAllocator, pPSO->GetDesc().Name); - auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); + for (Uint32 s = 0; s < m_NumShaders; ++s) + { + auto ShaderInd = GetShaderTypePipelineIndex(pPSO->GetShaderStageType(s), pPSO->GetDesc().PipelineType); - const auto& SrcLayout = pPSO->GetShaderResLayout(s); - // Use source layout to initialize resource memory in the cache - SrcLayout.InitializeResourceMemoryInCache(m_ShaderResourceCache); + m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); - // Create shader variable manager in place - // Initialize vars manager to reference mutable and dynamic variables - // Note that the cache has space for all variable types - const SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; - new (m_pShaderVarMgrs + s) ShaderVariableManagerVk{*this, SrcLayout, VarDataAllocator, VarTypes, _countof(VarTypes), m_ShaderResourceCache}; - } + auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); + + const auto& SrcLayout = pPSO->GetShaderResLayout(s); + // Use source layout to initialize resource memory in the cache + SrcLayout.InitializeResourceMemoryInCache(m_ShaderResourceCache); + + // Create shader variable manager in place + // Initialize vars manager to reference mutable and dynamic variables + // Note that the cache has space for all variable types + const SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + m_pShaderVarMgrs[s].Initialize(SrcLayout, VarDataAllocator, VarTypes, _countof(VarTypes)); + } #ifdef DILIGENT_DEBUG - m_ShaderResourceCache.DbgVerifyResourceInitialization(); + m_ShaderResourceCache.DbgVerifyResourceInitialization(); #endif + } + catch (...) + { + Destruct(); + throw; + } } ShaderResourceBindingVkImpl::~ShaderResourceBindingVkImpl() { - PipelineStateVkImpl* pPSO = ValidatedCast<PipelineStateVkImpl>(m_pPSO); - for (Uint32 s = 0; s < m_NumShaders; ++s) + Destruct(); +} + +void ShaderResourceBindingVkImpl::Destruct() +{ + if (m_pShaderVarMgrs != nullptr) { - auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); - m_pShaderVarMgrs[s].DestroyVariables(VarDataAllocator); - m_pShaderVarMgrs[s].~ShaderVariableManagerVk(); - } + auto& SRBMemAllocator = m_pPSO->GetSRBMemoryAllocator(); + for (Uint32 s = 0; s < m_NumShaders; ++s) + { + auto& VarDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s); + m_pShaderVarMgrs[s].DestroyVariables(VarDataAllocator); + m_pShaderVarMgrs[s].~ShaderVariableManagerVk(); + } - GetRawAllocator().Free(m_pShaderVarMgrs); + GetRawAllocator().Free(m_pShaderVarMgrs); + } } IMPLEMENT_QUERY_INTERFACE(ShaderResourceBindingVkImpl, IID_ShaderResourceBindingVk, TBase) diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index 4f28af80..e73ee9aa 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -63,10 +63,10 @@ static Int32 FindImmutableSampler(SHADER_TYPE ShaderType, return -1; } - for (Uint32 s = 0; s < ResourceLayoutDesc.NumStaticSamplers; ++s) + for (Uint32 s = 0; s < ResourceLayoutDesc.NumImmutableSamplers; ++s) { - const auto& StSam = ResourceLayoutDesc.StaticSamplers[s]; - if (((StSam.ShaderStages & ShaderType) != 0) && StreqSuff(Attribs.Name, StSam.SamplerOrTextureName, SamplerSuffix)) + const auto& ImtblSam = ResourceLayoutDesc.ImmutableSamplers[s]; + if (((ImtblSam.ShaderStages & ShaderType) != 0) && StreqSuff(Attribs.Name, ImtblSam.SamplerOrTextureName, SamplerSuffix)) return s; } @@ -93,6 +93,14 @@ static SHADER_RESOURCE_VARIABLE_TYPE FindShaderVariableType(SHADER_TYPE } } +ShaderResourceLayoutVk::ShaderStageInfo::ShaderStageInfo(SHADER_TYPE _Type, + const ShaderVkImpl* _pShader) : + Type{_Type}, + pShader{_pShader}, + SPIRV{pShader->GetSPIRV()} +{ +} + ShaderResourceLayoutVk::~ShaderResourceLayoutVk() { @@ -103,36 +111,37 @@ ShaderResourceLayoutVk::~ShaderResourceLayoutVk() GetImmutableSampler(s).~ImmutableSamplerPtrType(); } -void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers) +void ShaderResourceLayoutVk::AllocateMemory(const ShaderVkImpl* pShader, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + bool AllocateImmutableSamplers) { VERIFY(!m_ResourceBuffer, "Memory has already been initialized"); VERIFY_EXPR(!m_pResources); - VERIFY_EXPR(pSrcResources); + m_pResources = pShader->GetShaderResources(); - m_pResources = std::move(pSrcResources); - - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - const auto ShaderType = m_pResources->GetShaderType(); - const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); + const auto ShaderType = pShader->GetDesc().ShaderType; + VERIFY_EXPR(m_pResources->GetShaderType() == ShaderType); // Count the number of resources to allocate all needed memory - m_pResources->ProcessResources( - [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) // - { - auto VarType = FindShaderVariableType(ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); - if (IsAllowedType(VarType, AllowedTypeBits)) + { + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); + m_pResources->ProcessResources( + [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) // { - // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app + auto VarType = FindShaderVariableType(ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); + if (IsAllowedType(VarType, AllowedTypeBits)) + { + // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app - VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits<Uint16>::max()}, "Number of resources exceeds Uint16 maximum representable value"); - ++m_NumResources[VarType]; - } - } // - ); + VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits<Uint16>::max()}, "Number of resources exceeds Uint16 maximum representable value"); + ++m_NumResources[VarType]; + } + } // + ); + } Uint32 TotalResources = 0; for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) @@ -145,10 +154,10 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderRes m_NumImmutableSamplers = 0; if (AllocateImmutableSamplers) { - for (Uint32 s = 0; s < ResourceLayoutDesc.NumStaticSamplers; ++s) + for (Uint32 s = 0; s < ResourceLayoutDesc.NumImmutableSamplers; ++s) { - const auto& StSamDesc = ResourceLayoutDesc.StaticSamplers[s]; - if ((StSamDesc.ShaderStages & ShaderType) != 0) + const auto& ImtblSamDesc = ResourceLayoutDesc.ImmutableSamplers[s]; + if ((ImtblSamDesc.ShaderStages & ShaderType) != 0) ++m_NumImmutableSamplers; } } @@ -169,24 +178,63 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderRes } -void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - ShaderResourceCacheVk& StaticResourceCache) +static Uint32 FindAssignedSampler(const ShaderResourceLayoutVk& Layout, + const SPIRVShaderResources& Resources, + const SPIRVShaderResourceAttribs& SepImg, + Uint32 CurrResourceCount, + SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) +{ + using VkResource = ShaderResourceLayoutVk::VkResource; + VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + + Uint32 SamplerInd = VkResource::InvalidSamplerInd; + if (Resources.IsUsingCombinedSamplers() && SepImg.IsValidSepSamplerAssigned()) + { + const auto& SepSampler = Resources.GetAssignedSepSampler(SepImg); + for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) + { + const auto& Res = Layout.GetResource(ImgVarType, SamplerInd); + if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) + { + VERIFY(ImgVarType == Res.GetVariableType(), + "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name, + "' is not consistent with the type (", GetShaderVariableTypeLiteralName(Res.GetVariableType()), + ") of the separate sampler '", SepSampler.Name, + "' that is assigned to it. " + "This should never happen as when HLSL-style combined texture samplers are used, the type of the sampler " + "is derived from the type of the corresponding separate image."); + break; + } + } + if (SamplerInd == CurrResourceCount) + { + LOG_ERROR("Unable to find separate sampler '", SepSampler.Name, "' assigned to separate image '", SepImg.Name, "' in the list of already created resources. This seems to be a bug."); + SamplerInd = VkResource::InvalidSamplerInd; + } + } + return SamplerInd; +} + + +void ShaderResourceLayoutVk::InitializeStaticResourceLayout(const ShaderVkImpl* pShader, + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderResourceCacheVk& StaticResourceCache) { const auto AllowedVarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; // We do not need immutable samplers in static shader resource layout as they // are relevant only when the main layout is initialized constexpr bool AllocateImmutableSamplers = false; - AllocateMemory(std::move(pSrcResources), LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, AllocateImmutableSamplers); + AllocateMemory(pShader, LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, AllocateImmutableSamplers); std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrResInd = {}; Uint32 StaticResCacheSize = 0; const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1); - const auto ShaderType = m_pResources->GetShaderType(); const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); + const auto ShaderType = pShader->GetDesc().ShaderType; m_pResources->ProcessResources( [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) // @@ -214,7 +262,7 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr<cons { // Separate samplers are enumerated before separate images, so the sampler // assigned to this separate image must have already been created. - SamplerInd = FindAssignedSampler(Attribs, CurrResInd[VarType], VarType); + SamplerInd = FindAssignedSampler(*this, *m_pResources, Attribs, CurrResInd[VarType], VarType); } ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource(*this, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, SrcImmutableSamplerInd >= 0); } // @@ -235,25 +283,24 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr<cons } #ifdef DILIGENT_DEVELOPMENT -void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 NumShaders, - const std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - bool VerifyVariables, - bool VerifyStaticSamplers) +void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages& ShaderStages, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + bool VerifyVariables, + bool VerifyImmutableSamplers) { - auto GetAllowedShadersString = [&](SHADER_TYPE ShaderStages) // + auto GetAllowedShadersString = [&](SHADER_TYPE Stages) // { std::string ShadersStr; - while (ShaderStages != SHADER_TYPE_UNKNOWN) + while (Stages != SHADER_TYPE_UNKNOWN) { - const auto ShaderType = ShaderStages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(ShaderStages) - 1)); + const auto ShaderType = Stages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(Stages) - 1)); const char* ShaderName = nullptr; - for (Uint32 s = 0; s < NumShaders; ++s) + + for (const auto& StageInfo : ShaderStages) { - const auto& Resources = *pShaderResources[s]; - if ((ShaderStages & Resources.GetShaderType()) != 0) + if ((Stages & StageInfo.Type) != 0) { - ShaderName = Resources.GetShaderName(); + ShaderName = StageInfo.pShader->GetDesc().Name; break; } } @@ -274,7 +321,7 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } ShadersStr.append(")"); - ShaderStages &= ~ShaderType; + Stages &= ~ShaderType; } return ShadersStr; }; @@ -291,9 +338,9 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } bool VariableFound = false; - for (Uint32 s = 0; s < NumShaders && !VariableFound; ++s) + for (size_t s = 0; s < ShaderStages.size() && !VariableFound; ++s) { - const auto& Resources = *pShaderResources[s]; + const auto& Resources = *ShaderStages[s].pShader->GetShaderResources(); if ((VarDesc.ShaderStages & Resources.GetShaderType()) != 0) { for (Uint32 res = 0; res < Resources.GetTotalResources() && !VariableFound; ++res) @@ -312,83 +359,82 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } } - if (VerifyStaticSamplers) + if (VerifyImmutableSamplers) { - for (Uint32 sam = 0; sam < ResourceLayoutDesc.NumStaticSamplers; ++sam) + for (Uint32 sam = 0; sam < ResourceLayoutDesc.NumImmutableSamplers; ++sam) { - const auto& StSamDesc = ResourceLayoutDesc.StaticSamplers[sam]; - if (StSamDesc.ShaderStages == SHADER_TYPE_UNKNOWN) + const auto& ImtblSamDesc = ResourceLayoutDesc.ImmutableSamplers[sam]; + if (ImtblSamDesc.ShaderStages == SHADER_TYPE_UNKNOWN) { - LOG_WARNING_MESSAGE("No allowed shader stages are specified for static sampler '", StSamDesc.SamplerOrTextureName, "'."); + LOG_WARNING_MESSAGE("No allowed shader stages are specified for immutable sampler '", ImtblSamDesc.SamplerOrTextureName, "'."); continue; } bool SamplerFound = false; - for (Uint32 s = 0; s < NumShaders && !SamplerFound; ++s) + for (size_t s = 0; s < ShaderStages.size() && !SamplerFound; ++s) { - const auto& Resources = *pShaderResources[s]; - if ((StSamDesc.ShaderStages & Resources.GetShaderType()) == 0) + const auto& Resources = *ShaderStages[s].pShader->GetShaderResources(); + if ((ImtblSamDesc.ShaderStages & Resources.GetShaderType()) == 0) continue; // Irrespective of whether HLSL-style combined image samplers are used, - // a static sampler can be assigned to GLSL sampled image (i.e. sampler2D g_tex) + // an immutable sampler can be assigned to a GLSL sampled image (i.e. sampler2D g_tex) for (Uint32 i = 0; i < Resources.GetNumSmpldImgs() && !SamplerFound; ++i) { const auto& SmplImg = Resources.GetSmpldImg(i); - SamplerFound = (strcmp(SmplImg.Name, StSamDesc.SamplerOrTextureName) == 0); + SamplerFound = (strcmp(SmplImg.Name, ImtblSamDesc.SamplerOrTextureName) == 0); } if (!SamplerFound) { - // Check if static sampler is assigned to a separate sampler. + // Check if an immutable sampler is assigned to a separate sampler. // In case HLSL-style combined image samplers are used, the condition is SepSmpl.Name == "g_Texture" + "_sampler". // Otherwise the condition is SepSmpl.Name == "g_Texture_sampler" + "". const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix(); for (Uint32 i = 0; i < Resources.GetNumSepSmplrs() && !SamplerFound; ++i) { const auto& SepSmpl = Resources.GetSepSmplr(i); - SamplerFound = StreqSuff(SepSmpl.Name, StSamDesc.SamplerOrTextureName, CombinedSamplerSuffix); + SamplerFound = StreqSuff(SepSmpl.Name, ImtblSamDesc.SamplerOrTextureName, CombinedSamplerSuffix); } } } if (!SamplerFound) { - LOG_WARNING_MESSAGE("Static sampler '", StSamDesc.SamplerOrTextureName, + LOG_WARNING_MESSAGE("Immutable sampler '", ImtblSamDesc.SamplerOrTextureName, "' is not found in any of the designated shader stages: ", - GetAllowedShadersString(StSamDesc.ShaderStages)); + GetAllowedShadersString(ImtblSamDesc.ShaderStages)); } } } } #endif -void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice, - Uint32 NumShaders, - ShaderResourceLayoutVk Layouts[], - std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - std::vector<uint32_t> SPIRVs[], - class PipelineLayout& PipelineLayout, - bool VerifyVariables, - bool VerifyStaticSamplers) +void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice, + TShaderStages& ShaderStages, + ShaderResourceLayoutVk Layouts[], + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + class PipelineLayout& PipelineLayout, + bool VerifyVariables, + bool VerifyImmutableSamplers) { #ifdef DILIGENT_DEVELOPMENT - dvpVerifyResourceLayoutDesc(NumShaders, pShaderResources, ResourceLayoutDesc, VerifyVariables, VerifyStaticSamplers); + dvpVerifyResourceLayoutDesc(ShaderStages, ResourceLayoutDesc, VerifyVariables, VerifyImmutableSamplers); #endif - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr; - const Uint32 NumAllowedTypes = 0; - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr; + const Uint32 NumAllowedTypes = 0; + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + constexpr bool AllocateImmutableSamplers = true; - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - constexpr bool AllocateImmutableSamplers = true; - Layouts[s].AllocateMemory(std::move(pShaderResources[s]), LayoutDataAllocator, ResourceLayoutDesc, AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers); + Layouts[s].AllocateMemory(ShaderStages[s].pShader, LayoutDataAllocator, ResourceLayoutDesc, + AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers); } - VERIFY_EXPR(NumShaders <= MAX_SHADERS_IN_PIPELINE); + //VERIFY_EXPR(NumShaders <= MAX_SHADERS_IN_PIPELINE); std::array<std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>, MAX_SHADERS_IN_PIPELINE> CurrResInd = {}; std::array<Uint32, MAX_SHADERS_IN_PIPELINE> CurrImmutableSamplerInd = {}; #ifdef DILIGENT_DEBUG @@ -414,7 +460,7 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* { // Separate samplers are enumerated before separate images, so the sampler // assigned to this separate image must have already been created. - SamplerInd = ResLayout.FindAssignedSampler(Attribs, CurrResInd[ShaderInd][VarType], VarType); + SamplerInd = FindAssignedSampler(ResLayout, Resources, Attribs, CurrResInd[ShaderInd][VarType], VarType); } VkSampler vkImmutableSampler = VK_NULL_HANDLE; @@ -427,13 +473,13 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* { auto& ImmutableSampler = ResLayout.GetImmutableSampler(CurrImmutableSamplerInd[ShaderInd]++); VERIFY(!ImmutableSampler, "Immutable sampler has already been initialized!"); - const auto& ImmutableSamplerDesc = ResourceLayoutDesc.StaticSamplers[SrcImmutableSamplerInd].Desc; + const auto& ImmutableSamplerDesc = ResourceLayoutDesc.ImmutableSamplers[SrcImmutableSamplerInd].Desc; pRenderDevice->CreateSampler(ImmutableSamplerDesc, &ImmutableSampler); vkImmutableSampler = ImmutableSampler.RawPtr<SamplerVkImpl>()->GetVkSampler(); } } - auto& ShaderSPIRV = SPIRVs[ShaderInd]; + auto& ShaderSPIRV = ShaderStages[ShaderInd].SPIRV; PipelineLayout.AllocateResourceSlot(Attribs, VarType, vkImmutableSampler, Resources.GetShaderType(), DescriptorSet, Binding, CacheOffset, ShaderSPIRV); VERIFY(DescriptorSet <= std::numeric_limits<decltype(VkResource::DescriptorSet)>::max(), "Descriptor set (", DescriptorSet, ") excceeds maximum representable value"); VERIFY(Binding <= std::numeric_limits<decltype(VkResource::Binding)>::max(), "Binding (", Binding, ") excceeds maximum representable value"); @@ -454,42 +500,43 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* }; // First process uniform buffers for all shader stages to make sure all UBs go first in every descriptor set - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& Layout = Layouts[s]; + auto* pShaderVk = ShaderStages[s].pShader; + auto& Resources = *pShaderVk->GetShaderResources(); for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n) { const auto& UB = Resources.GetUB(n); auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc); if (IsAllowedType(VarType, AllowedTypeBits)) { - AddResource(s, Layout, Resources, UB); + AddResource(static_cast<Uint32>(s), Layout, Resources, UB); } } } // Second, process all storage buffers - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& Layout = Layouts[s]; + auto& Resources = *ShaderStages[s].pShader->GetShaderResources(); for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n) { const auto& SB = Resources.GetSB(n); auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc); if (IsAllowedType(VarType, AllowedTypeBits)) { - AddResource(s, Layout, Resources, SB); + AddResource(static_cast<Uint32>(s), Layout, Resources, SB); } } } // Finally, process all other resource types - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& Layout = Layouts[s]; + auto& Resources = *ShaderStages[s].pShader->GetShaderResources(); // clang-format off Resources.ProcessResources( [&](const SPIRVShaderResourceAttribs& UB, Uint32) @@ -505,39 +552,39 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* [&](const SPIRVShaderResourceAttribs& Img, Uint32) { VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer); - AddResource(s, Layout, Resources, Img); + AddResource(static_cast<Uint32>(s), Layout, Resources, Img); }, [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32) { VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); - AddResource(s, Layout, Resources, SmplImg); + AddResource(static_cast<Uint32>(s), Layout, Resources, SmplImg); }, [&](const SPIRVShaderResourceAttribs& AC, Uint32) { VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter); - AddResource(s, Layout, Resources, AC); + AddResource(static_cast<Uint32>(s), Layout, Resources, AC); }, [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32) { VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); - AddResource(s, Layout, Resources, SepSmpl); + AddResource(static_cast<Uint32>(s), Layout, Resources, SepSmpl); }, [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) { VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); - AddResource(s, Layout, Resources, SepImg); + AddResource(static_cast<Uint32>(s), Layout, Resources, SepImg); }, [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32) { VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment); - AddResource(s, Layout, Resources, InputAtt); + AddResource(static_cast<Uint32>(s), Layout, Resources, InputAtt); } ); // clang-format on } #ifdef DILIGENT_DEBUG - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { auto& Layout = Layouts[s]; for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) @@ -550,43 +597,6 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* #endif } - -Uint32 ShaderResourceLayoutVk::FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, - Uint32 CurrResourceCount, - SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) const -{ - VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); - - Uint32 SamplerInd = VkResource::InvalidSamplerInd; - if (m_pResources->IsUsingCombinedSamplers() && SepImg.IsValidSepSamplerAssigned()) - { - const auto& SepSampler = m_pResources->GetAssignedSepSampler(SepImg); - for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) - { - const auto& Res = GetResource(ImgVarType, SamplerInd); - if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && - strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) - { - VERIFY(ImgVarType == Res.GetVariableType(), - "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name, - "' is not consistent with the type (", GetShaderVariableTypeLiteralName(Res.GetVariableType()), - ") of the separate sampler '", SepSampler.Name, - "' that is assigned to it. " - "This should never happen as when HLSL-style combined texture samplers are used, the type of the sampler " - "is derived from the type of the corresponding separate image."); - break; - } - } - if (SamplerInd == CurrResourceCount) - { - LOG_ERROR("Unable to find separate sampler '", SepSampler.Name, "' assigned to separate image '", SepImg.Name, "' in the list of already created resources. This seems to be a bug."); - SamplerInd = VkResource::InvalidSamplerInd; - } - } - return SamplerInd; -} - - void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, uint32_t ArrayElement, const VkDescriptorImageInfo* pImageInfo, @@ -692,6 +702,16 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* // HLSL buffer SRVs are mapped to storge buffers in GLSL auto RequiredViewType = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ? BUFFER_VIEW_SHADER_RESOURCE : BUFFER_VIEW_UNORDERED_ACCESS; VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); + if (pBufferViewVk != nullptr) + { + const auto& ViewDesc = pBufferViewVk->GetDesc(); + const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc(); + if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "': structured buffer view is expected."); + } + } } #endif @@ -738,6 +758,16 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* // HLSL buffer SRVs are mapped to storge buffers in GLSL auto RequiredViewType = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer ? BUFFER_VIEW_UNORDERED_ACCESS : BUFFER_VIEW_SHADER_RESOURCE; VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); + if (pBufferViewVk != nullptr) + { + const auto& ViewDesc = pBufferViewVk->GetDesc(); + const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc(); + if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW)) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "': formatted buffer view is expected."); + } + } } #endif @@ -1017,7 +1047,7 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou { auto NumStaticResources = m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC]; VERIFY(NumStaticResources == SrcLayout.m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC], "Inconsistent number of static resources"); - VERIFY(SrcLayout.m_pResources->GetShaderType() == m_pResources->GetShaderType(), "Incosistent shader types"); + VERIFY(SrcLayout.GetShaderType() == GetShaderType(), "Incosistent shader types"); // Static shader resources are stored in one large continuous descriptor set for (Uint32 r = 0; r < NumStaticResources; ++r) diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp index 82d26b44..7e06bd69 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp @@ -65,20 +65,15 @@ size_t ShaderVariableManagerVk::GetRequiredMemorySize(const ShaderResourceLayout } // Creates shader variable for every resource from SrcLayout whose type is one AllowedVarTypes -ShaderVariableManagerVk::ShaderVariableManagerVk(IObject& Owner, - const ShaderResourceLayoutVk& SrcLayout, - IMemoryAllocator& Allocator, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheVk& ResourceCache) : - // clang-format off - m_Owner {Owner }, - m_ResourceCache{ResourceCache} +void ShaderVariableManagerVk::Initialize(const ShaderResourceLayoutVk& SrcLayout, + IMemoryAllocator& Allocator, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes) +{ #ifdef DILIGENT_DEBUG - , m_DbgAllocator {Allocator} + m_pDbgAllocator = &Allocator; #endif -// clang-format on -{ + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); VERIFY_EXPR(m_NumVariables == 0); auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, m_NumVariables); @@ -119,10 +114,10 @@ ShaderVariableManagerVk::~ShaderVariableManagerVk() void ShaderVariableManagerVk::DestroyVariables(IMemoryAllocator& Allocator) { - VERIFY(&m_DbgAllocator == &Allocator, "Incosistent alloctor"); - if (m_pVariables != nullptr) { + VERIFY(m_pDbgAllocator == &Allocator, "Incosistent alloctor"); + for (Uint32 v = 0; v < m_NumVariables; ++v) m_pVariables[v].~ShaderVariableVkImpl(); Allocator.Free(m_pVariables); @@ -130,7 +125,7 @@ void ShaderVariableManagerVk::DestroyVariables(IMemoryAllocator& Allocator) } } -ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) +ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) const { ShaderVariableVkImpl* pVar = nullptr; for (Uint32 v = 0; v < m_NumVariables; ++v) @@ -147,7 +142,7 @@ ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) } -ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(Uint32 Index) +ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(Uint32 Index) const { if (Index >= m_NumVariables) { @@ -178,7 +173,7 @@ Uint32 ShaderVariableManagerVk::GetVariableIndex(const ShaderVariableVkImpl& Var } } -void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) +void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) const { if (!pResourceMapping) { diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index 313de089..488e4bf6 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -54,13 +54,13 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, } // clang-format on { - if (m_Desc.Usage == USAGE_STATIC && (pInitData == nullptr || pInitData->pSubResources == nullptr)) - LOG_ERROR_AND_THROW("Static textures must be initialized with data at creation time: pInitData can't be null"); + if (m_Desc.Usage == USAGE_IMMUTABLE && (pInitData == nullptr || pInitData->pSubResources == nullptr)) + LOG_ERROR_AND_THROW("Immutable textures must be initialized with data at creation time: pInitData can't be null"); const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format); const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); - if (m_Desc.Usage == USAGE_STATIC || m_Desc.Usage == USAGE_DEFAULT || m_Desc.Usage == USAGE_DYNAMIC) + if (m_Desc.Usage == USAGE_IMMUTABLE || m_Desc.Usage == USAGE_DEFAULT || m_Desc.Usage == USAGE_DYNAMIC) { VkImageCreateInfo ImageCI = {}; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index fa03bca6..6358174c 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -1528,6 +1528,35 @@ VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags) } #undef ASSERT_SAME + +VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType) +{ + static_assert(SHADER_TYPE_LAST == SHADER_TYPE_CALLABLE, "Please update the switch below to handle the new shader type"); + VERIFY(IsPowerOfTwo(Uint32{ShaderType}), "More than one shader type is specified"); + switch (ShaderType) + { + // clang-format off + case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; + case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; + case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; + case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; + case SHADER_TYPE_AMPLIFICATION: return VK_SHADER_STAGE_TASK_BIT_NV; + case SHADER_TYPE_MESH: return VK_SHADER_STAGE_MESH_BIT_NV; + case SHADER_TYPE_RAY_GEN: return VK_SHADER_STAGE_RAYGEN_BIT_KHR; + case SHADER_TYPE_RAY_MISS: return VK_SHADER_STAGE_MISS_BIT_KHR; + case SHADER_TYPE_RAY_CLOSEST_HIT: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + case SHADER_TYPE_RAY_ANY_HIT: return VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + case SHADER_TYPE_RAY_INTERSECTION: return VK_SHADER_STAGE_INTERSECTION_BIT_KHR; + case SHADER_TYPE_CALLABLE: return VK_SHADER_STAGE_CALLABLE_BIT_KHR; + // clang-format on + default: + UNEXPECTED("Unknown shader type"); + return VK_SHADER_STAGE_VERTEX_BIT; + } +} + VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureFlags(RAYTRACING_BUILD_AS_FLAGS Flags) { static_assert(RAYTRACING_BUILD_AS_FLAGS_LAST == RAYTRACING_BUILD_AS_LOW_MEMORY, diff --git a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp index 5c35de33..091e2343 100644 --- a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp +++ b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp @@ -78,10 +78,11 @@ struct SPIRVShaderResourceAttribs static constexpr const Uint32 InvalidSepSmplrOrImgInd = static_cast<Uint32>(-1); -/* 0 */const char* const Name; -/* 8 */const Uint16 ArraySize; -/* 10 */const ResourceType Type; -/* 11 */ // unused +/* 0 */const char* const Name; +/* 8 */const Uint16 ArraySize; +/* 10 */const ResourceType Type; +/* 11.0*/const Uint8 ResourceDim : 7; +/* 11.7*/const Uint8 IsMS : 1; private: // Defines the mapping between separate samplers and seperate images when HLSL-style // combined texture samplers are in use (i.e. texture2D g_Tex + sampler g_Tex_sampler). @@ -159,6 +160,16 @@ public: } ShaderResourceDesc GetResourceDesc() const; + + RESOURCE_DIMENSION GetResourceDimension() const + { + return static_cast<RESOURCE_DIMENSION>(ResourceDim); + } + + bool IsMultisample() const + { + return IsMS != 0; + } }; static_assert(sizeof(SPIRVShaderResourceAttribs) % sizeof(void*) == 0, "Size of SPIRVShaderResourceAttribs struct must be multiple of sizeof(void*)"); diff --git a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp index dbdc81bc..cda18772 100644 --- a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp +++ b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp @@ -53,6 +53,46 @@ Type GetResourceArraySize(const diligent_spirv_cross::Compiler& Compiler, return static_cast<Type>(arrSize); } +static RESOURCE_DIMENSION GetResourceDimension(const diligent_spirv_cross::Compiler& Compiler, + const diligent_spirv_cross::Resource& Res) +{ + const auto& type = Compiler.get_type(Res.type_id); + if (type.basetype == diligent_spirv_cross::SPIRType::BaseType::Image || + type.basetype == diligent_spirv_cross::SPIRType::BaseType::SampledImage) + { + switch (type.image.dim) + { + // clang-format off + case spv::Dim1D: return type.image.arrayed ? RESOURCE_DIM_TEX_1D_ARRAY : RESOURCE_DIM_TEX_1D; + case spv::Dim2D: return type.image.arrayed ? RESOURCE_DIM_TEX_2D_ARRAY : RESOURCE_DIM_TEX_2D; + case spv::Dim3D: return RESOURCE_DIM_TEX_3D; + case spv::DimCube: return type.image.arrayed ? RESOURCE_DIM_TEX_CUBE_ARRAY : RESOURCE_DIM_TEX_CUBE; + case spv::DimBuffer: return RESOURCE_DIM_BUFFER; + // clang-format on + default: return RESOURCE_DIM_UNDEFINED; + } + } + else + { + return RESOURCE_DIM_UNDEFINED; + } +} + +static bool IsMultisample(const diligent_spirv_cross::Compiler& Compiler, + const diligent_spirv_cross::Resource& Res) +{ + const auto& type = Compiler.get_type(Res.type_id); + if (type.basetype == diligent_spirv_cross::SPIRType::BaseType::Image || + type.basetype == diligent_spirv_cross::SPIRType::BaseType::SampledImage) + { + return type.image.ms; + } + else + { + return RESOURCE_DIM_UNDEFINED; + } +} + static uint32_t GetDecorationOffset(const diligent_spirv_cross::Compiler& Compiler, const diligent_spirv_cross::Resource& Res, spv::Decoration Decoration) @@ -74,6 +114,8 @@ SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const diligent_spirv_cros Name {_Name}, ArraySize {GetResourceArraySize<decltype(ArraySize)>(Compiler, Res)}, Type {_Type}, + ResourceDim {Diligent::GetResourceDimension(Compiler, Res)}, + IsMS {Diligent::IsMultisample(Compiler, Res) ? Uint8{1} : Uint8{0}}, SepSmplrOrImgInd {_SepSmplrOrImgInd}, BindingDecorationOffset {GetDecorationOffset(Compiler, Res, spv::Decoration::DecorationBinding)}, DescriptorSetDecorationOffset {GetDecorationOffset(Compiler, Res, spv::Decoration::DecorationDescriptorSet)} @@ -588,6 +630,7 @@ void SPIRVShaderResources::Initialize(IMemoryAllocator& Allocator, VERIFY_EXPR(GetNumACs() == Counters.NumACs); VERIFY_EXPR(GetNumSepSmplrs() == Counters.NumSepSmplrs); VERIFY_EXPR(GetNumSepImgs() == Counters.NumSepImgs); + VERIFY_EXPR(GetNumInptAtts() == Counters.NumInptAtts); // clang-format on if (MemorySize) @@ -624,6 +667,9 @@ SPIRVShaderResources::~SPIRVShaderResources() for (Uint32 n = 0; n < GetNumSepImgs(); ++n) GetSepImg(n).~SPIRVShaderResourceAttribs(); + for (Uint32 n = 0; n < GetNumInptAtts(); ++n) + GetInptAtt(n).~SPIRVShaderResourceAttribs(); + for (Uint32 n = 0; n < GetNumShaderStageInputs(); ++n) GetShaderStageInputAttribs(n).~SPIRVShaderStageInputAttribs(); } @@ -754,7 +800,8 @@ bool SPIRVShaderResources::IsCompatibleWith(const SPIRVShaderResources& Resource GetNumSmpldImgs() != Resources.GetNumSmpldImgs() || GetNumACs() != Resources.GetNumACs() || GetNumSepImgs() != Resources.GetNumSepImgs() || - GetNumSepSmplrs() != Resources.GetNumSepSmplrs()) + GetNumSepSmplrs() != Resources.GetNumSepSmplrs() || + GetNumInptAtts() != Resources.GetNumInptAtts()) return false; // clang-format on VERIFY_EXPR(GetTotalResources() == Resources.GetTotalResources()); |
