diff options
| author | azhirnov <zh1dron@gmail.com> | 2020-10-08 18:45:01 +0000 |
|---|---|---|
| committer | azhirnov <zh1dron@gmail.com> | 2020-10-08 18:46:35 +0000 |
| commit | 2b396d236ab33dfe9c0defbe401d354ed3fb34f9 (patch) | |
| tree | 575243bb9aa6215725a8b16a7747c103c1eda852 /Graphics/GraphicsEngineVulkan | |
| parent | Updated PipelineState[D3D11,D3D12,Vk]Impl to allocate single chunk of memory ... (diff) | |
| download | DiligentCore-2b396d236ab33dfe9c0defbe401d354ed3fb34f9.tar.gz DiligentCore-2b396d236ab33dfe9c0defbe401d354ed3fb34f9.zip | |
removed strong references to shaders in PSO
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
9 files changed, 595 insertions, 544 deletions
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp index d1732211..303496bb 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp @@ -56,6 +56,7 @@ class PipelineStateVkImpl final : public PipelineStateBase<IPipelineStateVk, Ren { public: using TPipelineStateBase = PipelineStateBase<IPipelineStateVk, RenderDeviceVkImpl>; + using ShaderSPIRVs_t = std::vector<std::vector<uint32_t>>; PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const PipelineStateCreateInfo& CreateInfo); ~PipelineStateVkImpl(); @@ -104,7 +105,7 @@ public: const ShaderResourceLayoutVk& GetShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < m_NumShaderTypes); return m_ShaderResourceLayouts[ShaderInd]; } @@ -127,19 +128,19 @@ public: private: const ShaderResourceLayoutVk& GetStaticShaderResLayout(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); - return m_ShaderResourceLayouts[m_NumShaders + ShaderInd]; + VERIFY_EXPR(ShaderInd < m_NumShaderTypes); + return m_ShaderResourceLayouts[m_NumShaderTypes + ShaderInd]; } const ShaderResourceCacheVk& GetStaticResCache(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < m_NumShaderTypes); return m_StaticResCaches[ShaderInd]; } ShaderVariableManagerVk& GetStaticVarMgr(Uint32 ShaderInd) const { - VERIFY_EXPR(ShaderInd < m_NumShaders); + VERIFY_EXPR(ShaderInd < m_NumShaderTypes); return m_StaticVarsMgrs[ShaderInd]; } @@ -150,14 +151,12 @@ private: // SRB memory allocator must be declared before m_pDefaultShaderResBinding SRBMemoryAllocator m_SRBMemAllocator; - std::array<VulkanUtilities::ShaderModuleWrapper, MAX_SHADERS_IN_PIPELINE> m_ShaderModules = {}; - VulkanUtilities::PipelineWrapper m_Pipeline; PipelineLayout m_PipelineLayout; // Resource layout index in m_ShaderResourceLayouts array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; + std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex; bool m_HasStaticResources = false; bool m_HasNonStaticResources = false; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp index 026bb9da..85230b02 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp @@ -81,7 +81,7 @@ private: // Resource layout index in m_ShaderResourceCache array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; + std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex; bool m_bStaticResourcesInitialized = false; Uint8 m_NumShaders = 0; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp index a6d20641..28defd0f 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp @@ -115,6 +115,9 @@ namespace Diligent class ShaderResourceLayoutVk { public: + using ShaderStages_t = std::vector<std::pair<SHADER_TYPE, IShader*>>; + using ShaderSPIRVs_t = std::vector<std::vector<uint32_t>>; + ShaderResourceLayoutVk(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) : m_LogicalDevice{LogicalDevice} { @@ -131,23 +134,22 @@ public: // This method is called by PipelineStateVkImpl class instance to initialize static // shader resource layout and the cache - void InitializeStaticResourceLayout(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - ShaderResourceCacheVk& StaticResourceCache); + void InitializeStaticResourceLayout(IShader* pShader, + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderResourceCacheVk& StaticResourceCache); // This method is called by PipelineStateVkImpl class instance to initialize resource // layouts for all shader stages in the pipeline. - static void Initialize(IRenderDevice* pRenderDevice, - Uint32 NumShaders, - ShaderResourceLayoutVk Layouts[], - std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - std::vector<uint32_t> SPIRVs[], - class PipelineLayout& PipelineLayout, - bool VerifyVariables, - bool VerifyStaticSamplers); + static void Initialize(IRenderDevice* pRenderDevice, + const ShaderStages_t& ShaderStages, + ShaderResourceLayoutVk Layouts[], + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderSPIRVs_t& SPIRVs, + class PipelineLayout& PipelineLayout, + bool VerifyVariables, + bool VerifyStaticSamplers); // sizeof(VkResource) == 24 (x64) struct VkResource @@ -175,33 +177,21 @@ public: /* 7.5 */ const Uint32 VariableType : VariableTypeBits; /* 7.7 */ const Uint32 ImmutableSamplerAssigned : ImmutableSamplerFlagBits; -/* 8 */ const SPIRVShaderResourceAttribs& SpirvAttribs; -/* 16 */ const ShaderResourceLayoutVk& ParentResLayout; - - VkResource(const ShaderResourceLayoutVk& _ParentLayout, - const SPIRVShaderResourceAttribs& _SpirvAttribs, - SHADER_RESOURCE_VARIABLE_TYPE _VariableType, - uint32_t _Binding, - uint32_t _DescriptorSet, - Uint32 _CacheOffset, - Uint32 _SamplerInd, - bool _ImmutableSamplerAssigned = false)noexcept : - Binding {static_cast<decltype(Binding)>(_Binding) }, - DescriptorSet {static_cast<decltype(DescriptorSet)>(_DescriptorSet)}, - CacheOffset {_CacheOffset }, - SamplerInd {_SamplerInd }, - VariableType {_VariableType }, - ImmutableSamplerAssigned {_ImmutableSamplerAssigned ? 1U : 0U}, - SpirvAttribs {_SpirvAttribs }, - ParentResLayout {_ParentLayout } - { - VERIFY(_CacheOffset < (1 << CacheOffsetBits), "Cache offset (", _CacheOffset, ") exceeds max representable value ", (1 << CacheOffsetBits) ); - VERIFY(_SamplerInd < (1 << SamplerIndBits), "Sampler index (", _SamplerInd, ") exceeds max representable value ", (1 << SamplerIndBits) ); - VERIFY(_Binding <= std::numeric_limits<decltype(Binding)>::max(), "Binding (", _Binding, ") exceeds max representable value ", std::numeric_limits<decltype(Binding)>::max() ); - VERIFY(_DescriptorSet <= std::numeric_limits<decltype(DescriptorSet)>::max(), "Descriptor set (", _DescriptorSet, ") exceeds max representable value ", std::numeric_limits<decltype(DescriptorSet)>::max()); - } +/* 8 */ const SPIRVShaderResourceAttribs SpirvAttribs; +/* 16 */ const ShaderResourceLayoutVk& ParentResLayout; // clang-format on + VkResource(const ShaderResourceLayoutVk& _ParentLayout, + const SPIRVShaderResourceAttribs& _SpirvAttribs, + SHADER_RESOURCE_VARIABLE_TYPE _VariableType, + uint32_t _Binding, + uint32_t _DescriptorSet, + Uint32 _CacheOffset, + Uint32 _SamplerInd, + bool _ImmutableSamplerAssigned = false) noexcept; + + ~VkResource(); + // Checks if a resource is bound in ResourceCache at the given ArrayIndex bool IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const; @@ -279,11 +269,10 @@ public: #ifdef DILIGENT_DEVELOPMENT bool dvpVerifyBindings(const ShaderResourceCacheVk& ResourceCache) const; - static void dvpVerifyResourceLayoutDesc(Uint32 NumShaders, - const std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - bool VerifyVariables, - bool VerifyStaticSamplers); + static void dvpVerifyResourceLayoutDesc(const ShaderStages_t& ShaderStages, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + bool VerifyVariables, + bool VerifyStaticSamplers); #endif Uint32 GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE VarType) const @@ -300,13 +289,10 @@ public: const Char* GetShaderName() const { - return m_pResources->GetShaderName(); + return ""; // AZ TODO } - SHADER_TYPE GetShaderType() const - { - return m_pResources->GetShaderType(); - } + SHADER_TYPE GetShaderType() const { return m_ShaderType; } const VkResource& GetResource(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const { @@ -315,7 +301,7 @@ public: return Resources[GetResourceOffset(VarType, r)]; } - bool IsUsingSeparateSamplers() const { return !m_pResources->IsUsingCombinedSamplers(); } + bool IsUsingSeparateSamplers() const { return m_IsUsingSeparateSamplers; } private: Uint32 GetResourceOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const @@ -346,16 +332,12 @@ private: return m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES]; } - void AllocateMemory(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers); - - Uint32 FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, - Uint32 CurrResourceCount, - SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) const; + void AllocateMemory(IShader* pShader, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + bool AllocateImmutableSamplers); using ImmutableSamplerPtrType = RefCntAutoPtr<ISampler>; ImmutableSamplerPtrType& GetImmutableSampler(Uint32 n) noexcept @@ -366,16 +348,16 @@ private: } // clang-format off -/* 0 */ const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice; -/* 8 */ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer; +/* 0 */ const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice; +/* 8 */ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer; + +/*24 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES+1> m_NumResources = {}; - // We must use shared_ptr to reference ShaderResources instance, because - // there may be multiple objects referencing the same set of resources -/*24 */ std::shared_ptr<const SPIRVShaderResources> m_pResources; +/*32 */ Uint32 m_NumImmutableSamplers = 0; +/*36 */ bool m_IsUsingSeparateSamplers = false; +/*37 */ SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN; -/*40 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES+1> m_NumResources = {}; -/*48 */ Uint32 m_NumImmutableSamplers = 0; -/*56*/ // End of class +/*40 */ // End of class // clang-format on }; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp index dbba5b7e..1e6749f1 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp @@ -82,4 +82,7 @@ ATTACHMENT_STORE_OP VkAttachmentStoreOpToAttachmentStoreOp(VkAttachmentStoreOp V VkPipelineStageFlags PipelineStageFlagsToVkPipelineStageFlags(PIPELINE_STAGE_FLAGS PipelineStageFlags); VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags); + +VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType); + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp index 2fd063c9..6ed84171 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -40,28 +40,6 @@ namespace Diligent { - -static VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType) -{ - static_assert(SHADER_TYPE_LAST == 0x080, "Please update the switch below to handle the new shader type"); - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; - case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; - case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; - case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; - case SHADER_TYPE_AMPLIFICATION: return VK_SHADER_STAGE_TASK_BIT_NV; - case SHADER_TYPE_MESH: return VK_SHADER_STAGE_MESH_BIT_NV; - // clang-format on - default: - UNEXPECTED("Unknown shader type"); - return VK_SHADER_STAGE_VERTEX_BIT; - } -} - class ResourceTypeToVkDescriptorType { public: diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 75dd3263..29d16239 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -129,352 +129,376 @@ RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc( return RPDesc; } -static std::vector<uint32_t> StripReflection(const std::vector<uint32_t>& OriginalSPIRV) +static bool StripReflection(std::vector<uint32_t>& SPIRV) { #if DILIGENT_NO_HLSL - return OriginalSPIRV; + return false; #else std::vector<uint32_t> StrippedSPIRV; spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); // Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions // removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation. SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); - auto res = SpirvOptimizer.Run(OriginalSPIRV.data(), OriginalSPIRV.size(), &StrippedSPIRV); - if (!res) + if (SpirvOptimizer.Run(SPIRV.data(), SPIRV.size(), &StrippedSPIRV)) { - // Optimized SPIRV may be invalid - StrippedSPIRV.clear(); + SPIRV = std::move(StrippedSPIRV); + return true; } - return StrippedSPIRV; + else + return false; #endif } -PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pDeviceVk, - const PipelineStateCreateInfo& CreateInfo) : - TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, - m_SRBMemAllocator{GetRawAllocator()} +static void InitializeShaderStages(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, + const PipelineStateVkImpl::ShaderStages_t& ShaderStages, + PipelineStateVkImpl::ShaderSPIRVs_t& ShaderSPIRVs, + std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules, + std::vector<VkPipelineShaderStageCreateInfo>& Stages) { - m_ResourceLayoutIndex.fill(-1); - - const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + VERIFY_EXPR(ShaderStages.size() == ShaderSPIRVs.size()); - std::array<std::shared_ptr<const SPIRVShaderResources>, MAX_SHADERS_IN_PIPELINE> ShaderResources; - std::array<std::vector<uint32_t>, MAX_SHADERS_IN_PIPELINE> ShaderSPIRVs; - - // clang-format off - static_assert((sizeof(ShaderResourceLayoutVk) % sizeof(void*)) == 0, "sizeof(ShaderResourceLayoutVk) is expected to be a multiple of sizeof(void*)"); - static_assert((sizeof(ShaderResourceCacheVk) % sizeof(void*)) == 0, "sizeof(ShaderResourceCacheVk) is expected to be a multiple of sizeof(void*)"); - static_assert((sizeof(ShaderVariableManagerVk) % sizeof(void*)) == 0, "sizeof(ShaderVariableManagerVk) is expected to be a multiple of sizeof(void*)"); - // clang-format on - const auto MemSize = (sizeof(ShaderResourceLayoutVk) * 2 + sizeof(ShaderResourceCacheVk) + sizeof(ShaderVariableManagerVk)) * m_NumShaders; - auto* const pRawMem = - ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutVk, ShaderResourceCacheVk, and ShaderVariableManagerVk arrays", MemSize); - - m_ShaderResourceLayouts = reinterpret_cast<ShaderResourceLayoutVk*>(pRawMem); - m_StaticResCaches = reinterpret_cast<ShaderResourceCacheVk*>(m_ShaderResourceLayouts + m_NumShaders * 2); - m_StaticVarsMgrs = reinterpret_cast<ShaderVariableManagerVk*>(m_StaticResCaches + m_NumShaders); - - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk{LogicalDevice}; - auto* pShaderVk = GetShader<const ShaderVkImpl>(s); - ShaderResources[s] = pShaderVk->GetShaderResources(); - ShaderSPIRVs[s] = pShaderVk->GetSPIRV(); - - const auto ShaderType = pShaderVk->GetDesc().ShaderType; - const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); - m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s); - - auto* pStaticResLayout = new (m_ShaderResourceLayouts + m_NumShaders + s) ShaderResourceLayoutVk{LogicalDevice}; - auto* pStaticResCache = new (m_StaticResCaches + s) ShaderResourceCacheVk{ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources}; - pStaticResLayout->InitializeStaticResourceLayout(ShaderResources[s], GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]); - - new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, *pStaticResLayout, GetRawAllocator(), nullptr, 0, *pStaticResCache}; - } - ShaderResourceLayoutVk::Initialize(pDeviceVk, m_NumShaders, m_ShaderResourceLayouts, ShaderResources.data(), GetRawAllocator(), - m_Desc.ResourceLayout, ShaderSPIRVs.data(), m_PipelineLayout, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); - m_PipelineLayout.Finalize(LogicalDevice); + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(ShaderStages[s].second); + auto& SPIRV = ShaderSPIRVs[s]; + const auto ShaderType = ShaderStages[s].first; - if (m_Desc.SRBAllocationGranularity > 1) - { - std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + VkPipelineShaderStageCreateInfo StageCI = {}; - Uint32 UnusedNumVars = 0; - ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(m_ShaderResourceLayouts[s], AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars); - } - - Uint32 NumSets = 0; - auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets); - auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data()); - - m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, m_NumShaders, ShaderVariableDataSizes.data(), 1, &CacheMemorySize); - } - - // Create shader modules and initialize shader stages - std::array<VkPipelineShaderStageCreateInfo, MAX_SHADERS_IN_PIPELINE> ShaderStages = {}; - for (Uint32 s = 0; s < m_NumShaders; ++s) - { - auto* pShaderVk = GetShader<const ShaderVkImpl>(s); - auto ShaderType = pShaderVk->GetDesc().ShaderType; - - auto& StageCI = ShaderStages[s]; StageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; StageCI.pNext = nullptr; StageCI.flags = 0; // reserved for future use - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: StageCI.stage = VK_SHADER_STAGE_VERTEX_BIT; break; - case SHADER_TYPE_HULL: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; break; - case SHADER_TYPE_DOMAIN: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; break; - case SHADER_TYPE_GEOMETRY: StageCI.stage = VK_SHADER_STAGE_GEOMETRY_BIT; break; - case SHADER_TYPE_PIXEL: StageCI.stage = VK_SHADER_STAGE_FRAGMENT_BIT; break; - case SHADER_TYPE_COMPUTE: StageCI.stage = VK_SHADER_STAGE_COMPUTE_BIT; break; - case SHADER_TYPE_AMPLIFICATION: StageCI.stage = VK_SHADER_STAGE_TASK_BIT_NV; break; - case SHADER_TYPE_MESH: StageCI.stage = VK_SHADER_STAGE_MESH_BIT_NV; break; - default: UNEXPECTED("Unknown shader type"); - // clang-format on - } + StageCI.stage = ShaderTypeToVkShaderStageFlagBit(ShaderType); VkShaderModuleCreateInfo ShaderModuleCI = {}; ShaderModuleCI.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; ShaderModuleCI.pNext = nullptr; ShaderModuleCI.flags = 0; - const auto& SPIRV = ShaderSPIRVs[s]; // We have to strip reflection instructions to fix the follownig validation error: // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string // Optimizer also performs validation and may catch problems with the byte code. - auto StrippedSPIRV = StripReflection(SPIRV); - if (!StrippedSPIRV.empty()) - { - ShaderModuleCI.codeSize = StrippedSPIRV.size() * sizeof(uint32_t); - ShaderModuleCI.pCode = StrippedSPIRV.data(); - } - else - { + if (!StripReflection(SPIRV)) LOG_ERROR("Failed to strip reflection information from shader '", pShaderVk->GetDesc().Name, "'. This may indicate a problem with the byte code."); - ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); - ShaderModuleCI.pCode = SPIRV.data(); - } - m_ShaderModules[s] = LogicalDevice.CreateShaderModule(ShaderModuleCI, pShaderVk->GetDesc().Name); + ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); + ShaderModuleCI.pCode = SPIRV.data(); + + ShaderModules.push_back(LogicalDevice.CreateShaderModule(ShaderModuleCI, pShaderVk->GetDesc().Name)); - StageCI.module = m_ShaderModules[s]; + StageCI.module = ShaderModules.back(); StageCI.pName = pShaderVk->GetEntryPoint(); StageCI.pSpecializationInfo = nullptr; + + Stages.push_back(StageCI); } - // Create pipeline - if (m_Desc.IsComputePipeline()) - { - auto& ComputePipeline = m_Desc.ComputePipeline; + VERIFY_EXPR(ShaderModules.size() == Stages.size()); +} + + +static void CreateComputePipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector<VkPipelineShaderStageCreateInfo>& Stages, + const PipelineLayout& Layout, + const PipelineStateDesc& Desc, + VulkanUtilities::PipelineWrapper& Pipeline) +{ + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + + VkComputePipelineCreateInfo PipelineCI = {}; + + PipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + PipelineCI.pNext = nullptr; +#ifdef DILIGENT_DEBUG + PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; +#endif + PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from + PipelineCI.basePipelineIndex = -1; // an index into the pCreateInfos parameter to use as a pipeline to derive from - if (ComputePipeline.pCS == nullptr) - LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc"); + PipelineCI.stage = Stages[0]; + PipelineCI.layout = Layout.GetVkPipelineLayout(); - VkComputePipelineCreateInfo PipelineCI = {}; + Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, Desc.Name); +} + + +static void CreateGraphicsPipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector<VkPipelineShaderStageCreateInfo>& Stages, + const PipelineLayout& Layout, + const PipelineStateDesc& Desc, + VulkanUtilities::PipelineWrapper& Pipeline, + RefCntAutoPtr<IRenderPass>& pRenderPass) +{ + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); + auto& GraphicsPipeline = Desc.GraphicsPipeline; + auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); + + if (pRenderPass == nullptr) + { + RenderPassCache::RenderPassCacheKey Key{ + GraphicsPipeline.NumRenderTargets, + GraphicsPipeline.SmplDesc.Count, + GraphicsPipeline.RTVFormats, + GraphicsPipeline.DSVFormat}; + pRenderPass = RPCache.GetRenderPass(Key); + } + + VkGraphicsPipelineCreateInfo PipelineCI = {}; - PipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - PipelineCI.pNext = nullptr; + PipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + PipelineCI.pNext = nullptr; #ifdef DILIGENT_DEBUG - PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; + PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; #endif - PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from - PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from - PipelineCI.stage = ShaderStages[0]; - PipelineCI.layout = m_PipelineLayout.GetVkPipelineLayout(); + PipelineCI.stageCount = static_cast<Uint32>(Stages.size()); + PipelineCI.pStages = Stages.data(); + PipelineCI.layout = Layout.GetVkPipelineLayout(); + + VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {}; + + std::array<VkVertexInputBindingDescription, MAX_LAYOUT_ELEMENTS> BindingDescriptions; + std::array<VkVertexInputAttributeDescription, MAX_LAYOUT_ELEMENTS> AttributeDescription; + InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, VertexInputStateCI, BindingDescriptions, AttributeDescription); + PipelineCI.pVertexInputState = &VertexInputStateCI; - m_Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); + + VkPipelineInputAssemblyStateCreateInfo InputAssemblyCI = {}; + + InputAssemblyCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + InputAssemblyCI.pNext = nullptr; + InputAssemblyCI.flags = 0; // reserved for future use + InputAssemblyCI.primitiveRestartEnable = VK_FALSE; + PipelineCI.pInputAssemblyState = &InputAssemblyCI; + + + VkPipelineTessellationStateCreateInfo TessStateCI = {}; + + TessStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + TessStateCI.pNext = nullptr; + TessStateCI.flags = 0; // reserved for future use + PipelineCI.pTessellationState = &TessStateCI; + + if (Desc.PipelineType == PIPELINE_TYPE_MESH) + { + // Input assembly is not used in the mesh pipeline, so topology may contain any value. + // Validation layers may generate a warning if point_list topology is used, so use MAX_ENUM value. + InputAssemblyCI.topology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + + // Vertex input state and tessellation state are ignored in a mesh pipeline and should be null. + PipelineCI.pVertexInputState = nullptr; + PipelineCI.pTessellationState = nullptr; } else { - const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); - auto& GraphicsPipeline = m_Desc.GraphicsPipeline; - auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); + PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(GraphicsPipeline.PrimitiveTopology, InputAssemblyCI.topology, TessStateCI.patchControlPoints); + } - if (m_pRenderPass == nullptr) + VkPipelineViewportStateCreateInfo ViewPortStateCI = {}; + + ViewPortStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + ViewPortStateCI.pNext = nullptr; + ViewPortStateCI.flags = 0; // reserved for future use + ViewPortStateCI.viewportCount = + GraphicsPipeline.NumViewports; // Even though we use dynamic viewports, the number of viewports used + // by the pipeline is still specified by the viewportCount member (23.5) + ViewPortStateCI.pViewports = nullptr; // We will be using dynamic viewport & scissor states + ViewPortStateCI.scissorCount = ViewPortStateCI.viewportCount; // the number of scissors must match the number of viewports (23.5) + // (why the hell it is in the struct then?) + VkRect2D ScissorRect = {}; + if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + { + ViewPortStateCI.pScissors = nullptr; // Ignored if the scissor state is dynamic + } + else + { + const auto& Props = PhysicalDevice.GetProperties(); + // There are limitiations on the viewport width and height (23.5), but + // it is not clear if there are limitations on the scissor rect width and + // height + ScissorRect.extent.width = Props.limits.maxViewportDimensions[0]; + ScissorRect.extent.height = Props.limits.maxViewportDimensions[1]; + ViewPortStateCI.pScissors = &ScissorRect; + } + PipelineCI.pViewportState = &ViewPortStateCI; + + VkPipelineRasterizationStateCreateInfo RasterizerStateCI = + RasterizerStateDesc_To_VkRasterizationStateCI(GraphicsPipeline.RasterizerDesc); + PipelineCI.pRasterizationState = &RasterizerStateCI; + + // Multisample state (24) + VkPipelineMultisampleStateCreateInfo MSStateCI = {}; + + MSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + MSStateCI.pNext = nullptr; + MSStateCI.flags = 0; // reserved for future use + // If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of + // pMultisampleState must be the same as the sample count for those subpass attachments + MSStateCI.rasterizationSamples = static_cast<VkSampleCountFlagBits>(GraphicsPipeline.SmplDesc.Count); + MSStateCI.sampleShadingEnable = VK_FALSE; + MSStateCI.minSampleShading = 0; // a minimum fraction of sample shading if sampleShadingEnable is set to VK_TRUE. + uint32_t SampleMask[] = {GraphicsPipeline.SampleMask, 0}; // Vulkan spec allows up to 64 samples + MSStateCI.pSampleMask = SampleMask; // an array of static coverage information that is ANDed with + // the coverage information generated during rasterization (25.3) + MSStateCI.alphaToCoverageEnable = VK_FALSE; // whether a temporary coverage value is generated based on + // the alpha component of the fragment's first color output + MSStateCI.alphaToOneEnable = VK_FALSE; // whether the alpha component of the fragment's first color output is replaced with one + PipelineCI.pMultisampleState = &MSStateCI; + + VkPipelineDepthStencilStateCreateInfo DepthStencilStateCI = + DepthStencilStateDesc_To_VkDepthStencilStateCI(GraphicsPipeline.DepthStencilDesc); + PipelineCI.pDepthStencilState = &DepthStencilStateCI; + + const auto& RPDesc = pRenderPass->GetDesc(); + const auto NumRTAttachments = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex].RenderTargetAttachmentCount; + VERIFY_EXPR(GraphicsPipeline.pRenderPass != nullptr || GraphicsPipeline.NumRenderTargets == NumRTAttachments); + std::vector<VkPipelineColorBlendAttachmentState> ColorBlendAttachmentStates(NumRTAttachments); + + VkPipelineColorBlendStateCreateInfo BlendStateCI = {}; + + BlendStateCI.pAttachments = !ColorBlendAttachmentStates.empty() ? ColorBlendAttachmentStates.data() : nullptr; + BlendStateCI.attachmentCount = NumRTAttachments; // must equal the colorAttachmentCount for the subpass + // in which this pipeline is used. + BlendStateDesc_To_VkBlendStateCI(GraphicsPipeline.BlendDesc, BlendStateCI, ColorBlendAttachmentStates); + PipelineCI.pColorBlendState = &BlendStateCI; + + + VkPipelineDynamicStateCreateInfo DynamicStateCI = {}; + + DynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + DynamicStateCI.pNext = nullptr; + DynamicStateCI.flags = 0; // reserved for future use + std::vector<VkDynamicState> DynamicStates = { - RenderPassCache::RenderPassCacheKey Key{ - GraphicsPipeline.NumRenderTargets, - GraphicsPipeline.SmplDesc.Count, - GraphicsPipeline.RTVFormats, - GraphicsPipeline.DSVFormat}; - m_pRenderPass = RPCache.GetRenderPass(Key); - } + VK_DYNAMIC_STATE_VIEWPORT, // pViewports state in VkPipelineViewportStateCreateInfo will be ignored and must be + // set dynamically with vkCmdSetViewport before any draw commands. The number of viewports + // used by a pipeline is still specified by the viewportCount member of + // VkPipelineViewportStateCreateInfo. - VkGraphicsPipelineCreateInfo PipelineCI = {}; + VK_DYNAMIC_STATE_BLEND_CONSTANTS, // blendConstants state in VkPipelineColorBlendStateCreateInfo will be ignored + // and must be set dynamically with vkCmdSetBlendConstants - PipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - PipelineCI.pNext = nullptr; -#ifdef DILIGENT_DEBUG - PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; -#endif + VK_DYNAMIC_STATE_STENCIL_REFERENCE // pecifies that the reference state in VkPipelineDepthStencilStateCreateInfo + // for both front and back will be ignored and must be set dynamically + // with vkCmdSetStencilReference + }; - PipelineCI.stageCount = m_NumShaders; - PipelineCI.pStages = ShaderStages.data(); - PipelineCI.layout = m_PipelineLayout.GetVkPipelineLayout(); + if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + { + // pScissors state in VkPipelineViewportStateCreateInfo will be ignored and must be set + // dynamically with vkCmdSetScissor before any draw commands. The number of scissor rectangles + // used by a pipeline is still specified by the scissorCount member of + // VkPipelineViewportStateCreateInfo. + DynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR); + } + DynamicStateCI.dynamicStateCount = static_cast<uint32_t>(DynamicStates.size()); + DynamicStateCI.pDynamicStates = DynamicStates.data(); + PipelineCI.pDynamicState = &DynamicStateCI; - VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {}; - std::array<VkVertexInputBindingDescription, MAX_LAYOUT_ELEMENTS> BindingDescriptions; - std::array<VkVertexInputAttributeDescription, MAX_LAYOUT_ELEMENTS> AttributeDescription; - InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, VertexInputStateCI, BindingDescriptions, AttributeDescription); - PipelineCI.pVertexInputState = &VertexInputStateCI; + PipelineCI.renderPass = pRenderPass.RawPtr<IRenderPassVk>()->GetVkRenderPass(); + PipelineCI.subpass = Desc.GraphicsPipeline.SubpassIndex; + PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from + PipelineCI.basePipelineIndex = -1; // an index into the pCreateInfos parameter to use as a pipeline to derive from + Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, Desc.Name); +} - VkPipelineInputAssemblyStateCreateInfo InputAssemblyCI = {}; - InputAssemblyCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - InputAssemblyCI.pNext = nullptr; - InputAssemblyCI.flags = 0; // reserved for future use - InputAssemblyCI.primitiveRestartEnable = VK_FALSE; - PipelineCI.pInputAssemblyState = &InputAssemblyCI; +PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVk, + const PipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + m_ResourceLayoutIndex.fill(-1); + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); - VkPipelineTessellationStateCreateInfo TessStateCI = {}; + ShaderStages_t ShaderStages; + ShaderSPIRVs_t ShaderSPIRVs; + ExtractShaders(ShaderStages); - TessStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - TessStateCI.pNext = nullptr; - TessStateCI.flags = 0; // reserved for future use - PipelineCI.pTessellationState = &TessStateCI; + ShaderSPIRVs.resize(ShaderStages.size()); + for (size_t s = 0; s < ShaderSPIRVs.size(); ++s) + { + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(ShaderStages[s].second); + ShaderSPIRVs[s] = pShaderVk->GetSPIRV(); + } - if (m_Desc.PipelineType == PIPELINE_TYPE_MESH) - { - // Input assembly is not used in the mesh pipeline, so topology may contain any value. - // Validation layers may generate a warning if point_list topology is used, so use MAX_ENUM value. - InputAssemblyCI.topology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + // clang-format off + static_assert((sizeof(ShaderResourceLayoutVk) % sizeof(void*)) == 0, "sizeof(ShaderResourceLayoutVk) is expected to be a multiple of sizeof(void*)"); + static_assert((sizeof(ShaderResourceCacheVk) % sizeof(void*)) == 0, "sizeof(ShaderResourceCacheVk) is expected to be a multiple of sizeof(void*)"); + static_assert((sizeof(ShaderVariableManagerVk) % sizeof(void*)) == 0, "sizeof(ShaderVariableManagerVk) is expected to be a multiple of sizeof(void*)"); + // clang-format on + const auto MemSize = (sizeof(ShaderResourceLayoutVk) * 2 + sizeof(ShaderResourceCacheVk) + sizeof(ShaderVariableManagerVk)) * GetNumShaderTypes(); + auto* const pRawMem = + ALLOCATE_RAW(GetRawAllocator(), "Raw memory for ShaderResourceLayoutVk, ShaderResourceCacheVk, and ShaderVariableManagerVk arrays", MemSize); - // Vertex input state and tessellation state are ignored in a mesh pipeline and should be null. - PipelineCI.pVertexInputState = nullptr; - PipelineCI.pTessellationState = nullptr; - } - else - { - PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(GraphicsPipeline.PrimitiveTopology, InputAssemblyCI.topology, TessStateCI.patchControlPoints); - } + m_ShaderResourceLayouts = reinterpret_cast<ShaderResourceLayoutVk*>(pRawMem); + m_StaticResCaches = reinterpret_cast<ShaderResourceCacheVk*>(m_ShaderResourceLayouts + GetNumShaderTypes() * 2); + m_StaticVarsMgrs = reinterpret_cast<ShaderVariableManagerVk*>(m_StaticResCaches + GetNumShaderTypes()); - VkPipelineViewportStateCreateInfo ViewPortStateCI = {}; - - ViewPortStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - ViewPortStateCI.pNext = nullptr; - ViewPortStateCI.flags = 0; // reserved for future use - ViewPortStateCI.viewportCount = - GraphicsPipeline.NumViewports; // Even though we use dynamic viewports, the number of viewports used - // by the pipeline is still specified by the viewportCount member (23.5) - ViewPortStateCI.pViewports = nullptr; // We will be using dynamic viewport & scissor states - ViewPortStateCI.scissorCount = ViewPortStateCI.viewportCount; // the number of scissors must match the number of viewports (23.5) - // (why the hell it is in the struct then?) - VkRect2D ScissorRect = {}; - if (GraphicsPipeline.RasterizerDesc.ScissorEnable) - { - ViewPortStateCI.pScissors = nullptr; // Ignored if the scissor state is dynamic - } - else - { - const auto& Props = PhysicalDevice.GetProperties(); - // There are limitiations on the viewport width and height (23.5), but - // it is not clear if there are limitations on the scissor rect width and - // height - ScissorRect.extent.width = Props.limits.maxViewportDimensions[0]; - ScissorRect.extent.height = Props.limits.maxViewportDimensions[1]; - ViewPortStateCI.pScissors = &ScissorRect; - } - PipelineCI.pViewportState = &ViewPortStateCI; - - VkPipelineRasterizationStateCreateInfo RasterizerStateCI = - RasterizerStateDesc_To_VkRasterizationStateCI(GraphicsPipeline.RasterizerDesc); - PipelineCI.pRasterizationState = &RasterizerStateCI; - - // Multisample state (24) - VkPipelineMultisampleStateCreateInfo MSStateCI = {}; - - MSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - MSStateCI.pNext = nullptr; - MSStateCI.flags = 0; // reserved for future use - // If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of - // pMultisampleState must be the same as the sample count for those subpass attachments - MSStateCI.rasterizationSamples = static_cast<VkSampleCountFlagBits>(GraphicsPipeline.SmplDesc.Count); - MSStateCI.sampleShadingEnable = VK_FALSE; - MSStateCI.minSampleShading = 0; // a minimum fraction of sample shading if sampleShadingEnable is set to VK_TRUE. - uint32_t SampleMask[] = {GraphicsPipeline.SampleMask, 0}; // Vulkan spec allows up to 64 samples - MSStateCI.pSampleMask = SampleMask; // an array of static coverage information that is ANDed with - // the coverage information generated during rasterization (25.3) - MSStateCI.alphaToCoverageEnable = VK_FALSE; // whether a temporary coverage value is generated based on - // the alpha component of the fragment's first color output - MSStateCI.alphaToOneEnable = VK_FALSE; // whether the alpha component of the fragment's first color output is replaced with one - PipelineCI.pMultisampleState = &MSStateCI; - - VkPipelineDepthStencilStateCreateInfo DepthStencilStateCI = - DepthStencilStateDesc_To_VkDepthStencilStateCI(GraphicsPipeline.DepthStencilDesc); - PipelineCI.pDepthStencilState = &DepthStencilStateCI; - - const auto& RPDesc = m_pRenderPass->GetDesc(); - const auto NumRTAttachments = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex].RenderTargetAttachmentCount; - VERIFY_EXPR(GraphicsPipeline.pRenderPass != nullptr || GraphicsPipeline.NumRenderTargets == NumRTAttachments); - std::vector<VkPipelineColorBlendAttachmentState> ColorBlendAttachmentStates(NumRTAttachments); - - VkPipelineColorBlendStateCreateInfo BlendStateCI = {}; - - BlendStateCI.pAttachments = !ColorBlendAttachmentStates.empty() ? ColorBlendAttachmentStates.data() : nullptr; - BlendStateCI.attachmentCount = NumRTAttachments; // must equal the colorAttachmentCount for the subpass - // in which this pipeline is used. - BlendStateDesc_To_VkBlendStateCI(GraphicsPipeline.BlendDesc, BlendStateCI, ColorBlendAttachmentStates); - PipelineCI.pColorBlendState = &BlendStateCI; - - - VkPipelineDynamicStateCreateInfo DynamicStateCI = {}; - - DynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - DynamicStateCI.pNext = nullptr; - DynamicStateCI.flags = 0; // reserved for future use - std::vector<VkDynamicState> DynamicStates = - { - VK_DYNAMIC_STATE_VIEWPORT, // pViewports state in VkPipelineViewportStateCreateInfo will be ignored and must be - // set dynamically with vkCmdSetViewport before any draw commands. The number of viewports - // used by a pipeline is still specified by the viewportCount member of - // VkPipelineViewportStateCreateInfo. + for (size_t s = 0; s < ShaderStages.size(); ++s) + { + new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk{LogicalDevice}; + + const auto ShaderType = ShaderStages[s].first; + auto& Shaders = ShaderStages[s].second; + const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); + m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s); - VK_DYNAMIC_STATE_BLEND_CONSTANTS, // blendConstants state in VkPipelineColorBlendStateCreateInfo will be ignored - // and must be set dynamically with vkCmdSetBlendConstants + auto* pStaticResLayout = new (m_ShaderResourceLayouts + ShaderStages.size() + s) ShaderResourceLayoutVk{LogicalDevice}; + auto* pStaticResCache = new (m_StaticResCaches + s) ShaderResourceCacheVk{ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources}; + pStaticResLayout->InitializeStaticResourceLayout(Shaders, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]); - VK_DYNAMIC_STATE_STENCIL_REFERENCE // pecifies that the reference state in VkPipelineDepthStencilStateCreateInfo - // for both front and back will be ignored and must be set dynamically - // with vkCmdSetStencilReference - }; + new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, *pStaticResLayout, GetRawAllocator(), nullptr, 0, *pStaticResCache}; + } + ShaderResourceLayoutVk::Initialize(pDeviceVk, ShaderStages, m_ShaderResourceLayouts, GetRawAllocator(), + m_Desc.ResourceLayout, ShaderSPIRVs, m_PipelineLayout, + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, + (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_STATIC_SAMPLERS) == 0); + m_PipelineLayout.Finalize(LogicalDevice); - if (GraphicsPipeline.RasterizerDesc.ScissorEnable) + if (m_Desc.SRBAllocationGranularity > 1) + { + std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {}; + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { - // pScissors state in VkPipelineViewportStateCreateInfo will be ignored and must be set - // dynamically with vkCmdSetScissor before any draw commands. The number of scissor rectangles - // used by a pipeline is still specified by the scissorCount member of - // VkPipelineViewportStateCreateInfo. - DynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR); + const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + + Uint32 UnusedNumVars = 0; + ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(m_ShaderResourceLayouts[s], AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars); } - DynamicStateCI.dynamicStateCount = static_cast<uint32_t>(DynamicStates.size()); - DynamicStateCI.pDynamicStates = DynamicStates.data(); - PipelineCI.pDynamicState = &DynamicStateCI; + Uint32 NumSets = 0; + auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets); + auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data()); + + m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderTypes(), ShaderVariableDataSizes.data(), 1, &CacheMemorySize); + } - PipelineCI.renderPass = GetRenderPass()->GetVkRenderPass(); - PipelineCI.subpass = m_Desc.GraphicsPipeline.SubpassIndex; - PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from - PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from + // Create shader modules and initialize shader stages + std::vector<VkPipelineShaderStageCreateInfo> VkShaderStages; + std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules; + InitializeShaderStages(LogicalDevice, ShaderStages, ShaderSPIRVs, ShaderModules, VkShaderStages); - m_Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); + // Create pipeline + switch (m_Desc.PipelineType) + { + // clang-format off + case PIPELINE_TYPE_GRAPHICS: + case PIPELINE_TYPE_MESH: CreateGraphicsPipeline( pDeviceVk, VkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline, m_pRenderPass); break; + case PIPELINE_TYPE_COMPUTE: CreateComputePipeline( pDeviceVk, VkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline); break; + default: UNEXPECTED("unknown pipeline type"); + // clang-format on } m_HasStaticResources = false; m_HasNonStaticResources = false; - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) != 0) @@ -493,21 +517,13 @@ PipelineStateVkImpl::~PipelineStateVkImpl() m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask); m_PipelineLayout.Release(m_pDevice, m_Desc.CommandQueueMask); - for (auto& ShaderModule : m_ShaderModules) - { - if (ShaderModule != VK_NULL_HANDLE) - { - m_pDevice->SafeReleaseDeviceObject(std::move(ShaderModule), m_Desc.CommandQueueMask); - } - } - auto& RawAllocator = GetRawAllocator(); - for (Uint32 s = 0; s < m_NumShaders * 2; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes() * 2; ++s) { m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk(); } - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { m_StaticResCaches[s].~ShaderResourceCacheVk(); m_StaticVarsMgrs[s].DestroyVariables(GetRawAllocator()); @@ -547,27 +563,27 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const #ifdef DILIGENT_DEBUG { bool IsCompatibleShaders = true; - if (m_NumShaders != pPSOVk->m_NumShaders) + if (GetNumShaderTypes() != pPSOVk->GetNumShaderTypes()) IsCompatibleShaders = false; if (IsCompatibleShaders) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { - auto* pShader0 = GetShader<const ShaderVkImpl>(s); - auto* pShader1 = pPSOVk->GetShader<const ShaderVkImpl>(s); - if (pShader0->GetDesc().ShaderType != pShader1->GetDesc().ShaderType) + if (GetShaderTypes()[s] != pPSOVk->GetShaderTypes()[s]) { IsCompatibleShaders = false; break; } - const auto* pRes0 = pShader0->GetShaderResources().get(); + + // AZ TODO + /*const auto* pRes0 = pShader0->GetShaderResources().get(); const auto* pRes1 = pShader1->GetShaderResources().get(); if (!pRes0->IsCompatibleWith(*pRes1)) { IsCompatibleShaders = false; break; - } + }*/ } } @@ -621,7 +637,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind auto& ResourceCache = pResBindingVkImpl->GetResourceCache(); #ifdef DILIGENT_DEVELOPMENT - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { m_ShaderResourceLayouts[s].dvpVerifyBindings(ResourceCache); } @@ -656,7 +672,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind // Allocate vulkan descriptor set for dynamic resources DynamicDescrSet = pCtxVkImpl->AllocateDynamicDescriptorSet(DynamicDescriptorSetVkLayout, DynamicDescrSetName); // Commit all dynamic resource descriptors - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) != 0) @@ -673,7 +689,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind void PipelineStateVkImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { auto ShaderType = GetStaticShaderResLayout(s).GetShaderType(); if ((ShaderType & ShaderFlags) != 0) @@ -717,17 +733,17 @@ IShaderResourceVariable* PipelineStateVkImpl::GetStaticVariableByIndex(SHADER_TY void PipelineStateVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const { - for (Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < GetNumShaderTypes(); ++s) { const auto& StaticResLayout = GetStaticShaderResLayout(s); const auto& StaticResCache = GetStaticResCache(s); + #ifdef DILIGENT_DEVELOPMENT if (!StaticResLayout.dvpVerifyBindings(StaticResCache)) { - const auto* pShaderVk = GetShader<const ShaderVkImpl>(s); LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", GetDesc().Name, "' will not be successfully initialized because not all static resource bindings in shader '", - pShaderVk->GetDesc().Name, + GetShaderTypeLiteralName(GetShaderTypes()[s]), "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method."); } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp index 53a92a59..75f3bb37 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp @@ -49,8 +49,8 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pR { m_ResourceLayoutIndex.fill(-1); - auto* ppShaders = pPSO->GetShaders(); - m_NumShaders = static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaders()); + auto* pShaderTypes = pPSO->GetShaderTypes(); + m_NumShaders = static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaderTypes()); auto* pRenderDeviceVkImpl = pPSO->GetDevice(); // This will only allocate memory and initialize descriptor sets in the resource cache @@ -62,9 +62,7 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pR for (Uint32 s = 0; s < m_NumShaders; ++s) { - auto* pShader = ppShaders[s]; - auto ShaderType = pShader->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPSO->GetDesc().PipelineType); + auto ShaderInd = GetShaderTypePipelineIndex(pShaderTypes[s], pPSO->GetDesc().PipelineType); m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index 4f28af80..1f798eb9 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -103,36 +103,40 @@ ShaderResourceLayoutVk::~ShaderResourceLayoutVk() GetImmutableSampler(s).~ImmutableSamplerPtrType(); } -void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers) +void ShaderResourceLayoutVk::AllocateMemory(IShader* pShader, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + bool AllocateImmutableSamplers) { VERIFY(!m_ResourceBuffer, "Memory has already been initialized"); - VERIFY_EXPR(!m_pResources); - VERIFY_EXPR(pSrcResources); + VERIFY_EXPR(pShader != nullptr); + VERIFY_EXPR(m_ShaderType == SHADER_TYPE_UNKNOWN); - m_pResources = std::move(pSrcResources); - - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - const auto ShaderType = m_pResources->GetShaderType(); - const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + m_ShaderType = pShader->GetDesc().ShaderType; // Count the number of resources to allocate all needed memory - m_pResources->ProcessResources( - [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) // - { - auto VarType = FindShaderVariableType(ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); - if (IsAllowedType(VarType, AllowedTypeBits)) + { + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto pResources = pShaderVk->GetShaderResources(); + const auto* CombinedSamplerSuffix = pResources->GetCombinedSamplerSuffix(); + VERIFY_EXPR(pResources->GetShaderType() == m_ShaderType); + pResources->ProcessResources( + [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) // { - // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app + auto VarType = FindShaderVariableType(m_ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); + if (IsAllowedType(VarType, AllowedTypeBits)) + { + // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app - VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits<Uint16>::max()}, "Number of resources exceeds Uint16 maximum representable value"); - ++m_NumResources[VarType]; - } - } // - ); + VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits<Uint16>::max()}, "Number of resources exceeds Uint16 maximum representable value"); + ++m_NumResources[VarType]; + } + } // + ); + m_IsUsingSeparateSamplers = !pResources->IsUsingCombinedSamplers(); + } Uint32 TotalResources = 0; for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) @@ -148,7 +152,7 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderRes for (Uint32 s = 0; s < ResourceLayoutDesc.NumStaticSamplers; ++s) { const auto& StSamDesc = ResourceLayoutDesc.StaticSamplers[s]; - if ((StSamDesc.ShaderStages & ShaderType) != 0) + if ((StSamDesc.ShaderStages & m_ShaderType) != 0) ++m_NumImmutableSamplers; } } @@ -169,56 +173,99 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr<const SPIRVShaderRes } -void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr<const SPIRVShaderResources> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - ShaderResourceCacheVk& StaticResourceCache) +Uint32 FindAssignedSampler(const ShaderResourceLayoutVk& Layout, + const SPIRVShaderResources& Resources, + const SPIRVShaderResourceAttribs& SepImg, + Uint32 CurrResourceCount, + SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) +{ + using VkResource = ShaderResourceLayoutVk::VkResource; + VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + + Uint32 SamplerInd = VkResource::InvalidSamplerInd; + if (Resources.IsUsingCombinedSamplers() && SepImg.IsValidSepSamplerAssigned()) + { + const auto& SepSampler = Resources.GetAssignedSepSampler(SepImg); + for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) + { + const auto& Res = Layout.GetResource(ImgVarType, SamplerInd); + if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) + { + VERIFY(ImgVarType == Res.GetVariableType(), + "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name, + "' is not consistent with the type (", GetShaderVariableTypeLiteralName(Res.GetVariableType()), + ") of the separate sampler '", SepSampler.Name, + "' that is assigned to it. " + "This should never happen as when HLSL-style combined texture samplers are used, the type of the sampler " + "is derived from the type of the corresponding separate image."); + break; + } + } + if (SamplerInd == CurrResourceCount) + { + LOG_ERROR("Unable to find separate sampler '", SepSampler.Name, "' assigned to separate image '", SepImg.Name, "' in the list of already created resources. This seems to be a bug."); + SamplerInd = VkResource::InvalidSamplerInd; + } + } + return SamplerInd; +} + + +void ShaderResourceLayoutVk::InitializeStaticResourceLayout(IShader* pShader, + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderResourceCacheVk& StaticResourceCache) { const auto AllowedVarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; // We do not need immutable samplers in static shader resource layout as they // are relevant only when the main layout is initialized constexpr bool AllocateImmutableSamplers = false; - AllocateMemory(std::move(pSrcResources), LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, AllocateImmutableSamplers); + AllocateMemory(pShader, LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, AllocateImmutableSamplers); std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrResInd = {}; Uint32 StaticResCacheSize = 0; - const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1); - const auto ShaderType = m_pResources->GetShaderType(); - const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); + const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1); - m_pResources->ProcessResources( - [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) // - { - auto VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix); - if (!IsAllowedType(VarType, AllowedTypeBits)) - return; + { + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto pResources = pShaderVk->GetShaderResources(); + const auto* CombinedSamplerSuffix = pResources->GetCombinedSamplerSuffix(); - Int32 SrcImmutableSamplerInd = -1; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || - Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) + pResources->ProcessResources( + [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) // { - // Only search for the immutable sampler for combined image samplers and separate samplers - SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, CombinedSamplerSuffix); - // For immutable separate samplers we allocate VkResource instances, but they are never exposed to the app - } + auto VarType = FindShaderVariableType(m_ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix); + if (!IsAllowedType(VarType, AllowedTypeBits)) + return; - Uint32 Binding = Attribs.Type; - Uint32 DescriptorSet = 0; - Uint32 CacheOffset = StaticResCacheSize; - StaticResCacheSize += Attribs.ArraySize; + Int32 SrcImmutableSamplerInd = -1; + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || + Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) + { + // Only search for the immutable sampler for combined image samplers and separate samplers + SrcImmutableSamplerInd = FindImmutableSampler(m_ShaderType, ResourceLayoutDesc, Attribs, CombinedSamplerSuffix); + // For immutable separate samplers we allocate VkResource instances, but they are never exposed to the app + } - Uint32 SamplerInd = VkResource::InvalidSamplerInd; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) - { - // Separate samplers are enumerated before separate images, so the sampler - // assigned to this separate image must have already been created. - SamplerInd = FindAssignedSampler(Attribs, CurrResInd[VarType], VarType); - } - ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource(*this, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, SrcImmutableSamplerInd >= 0); - } // - ); + Uint32 Binding = Attribs.Type; + Uint32 DescriptorSet = 0; + Uint32 CacheOffset = StaticResCacheSize; + StaticResCacheSize += Attribs.ArraySize; + + Uint32 SamplerInd = VkResource::InvalidSamplerInd; + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) + { + // Separate samplers are enumerated before separate images, so the sampler + // assigned to this separate image must have already been created. + SamplerInd = FindAssignedSampler(*this, *pResources, Attribs, CurrResInd[VarType], VarType); + } + ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource(*this, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, SrcImmutableSamplerInd >= 0); + } // + ); + } #ifdef DILIGENT_DEBUG for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) @@ -235,25 +282,24 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr<cons } #ifdef DILIGENT_DEVELOPMENT -void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 NumShaders, - const std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - bool VerifyVariables, - bool VerifyStaticSamplers) +void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const ShaderStages_t& ShaderStages, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + bool VerifyVariables, + bool VerifyStaticSamplers) { - auto GetAllowedShadersString = [&](SHADER_TYPE ShaderStages) // + auto GetAllowedShadersString = [&](SHADER_TYPE Stages) // { std::string ShadersStr; - while (ShaderStages != SHADER_TYPE_UNKNOWN) + while (Stages != SHADER_TYPE_UNKNOWN) { - const auto ShaderType = ShaderStages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(ShaderStages) - 1)); + const auto ShaderType = Stages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(Stages) - 1)); const char* ShaderName = nullptr; - for (Uint32 s = 0; s < NumShaders; ++s) + + for (size_t s = 0; s < ShaderStages.size(); ++s) { - const auto& Resources = *pShaderResources[s]; - if ((ShaderStages & Resources.GetShaderType()) != 0) + if ((Stages & ShaderStages[s].first) != 0) { - ShaderName = Resources.GetShaderName(); + ShaderName = ShaderStages[s].second->GetDesc().Name; break; } } @@ -274,7 +320,7 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } ShadersStr.append(")"); - ShaderStages &= ~ShaderType; + Stages &= ~ShaderType; } return ShadersStr; }; @@ -291,9 +337,10 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } bool VariableFound = false; - for (Uint32 s = 0; s < NumShaders && !VariableFound; ++s) + for (size_t s = 0; s < ShaderStages.size() && !VariableFound; ++s) { - const auto& Resources = *pShaderResources[s]; + const auto* pShaderVk = ValidatedCast<ShaderVkImpl>(ShaderStages[s].second); + const auto& Resources = *pShaderVk->GetShaderResources(); if ((VarDesc.ShaderStages & Resources.GetShaderType()) != 0) { for (Uint32 res = 0; res < Resources.GetTotalResources() && !VariableFound; ++res) @@ -324,9 +371,10 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } bool SamplerFound = false; - for (Uint32 s = 0; s < NumShaders && !SamplerFound; ++s) + for (size_t s = 0; s < ShaderStages.size() && !SamplerFound; ++s) { - const auto& Resources = *pShaderResources[s]; + const auto* pShaderVk = ValidatedCast<ShaderVkImpl>(ShaderStages[s].second); + const auto& Resources = *pShaderVk->GetShaderResources(); if ((StSamDesc.ShaderStages & Resources.GetShaderType()) == 0) continue; @@ -363,32 +411,31 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } #endif -void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice, - Uint32 NumShaders, - ShaderResourceLayoutVk Layouts[], - std::shared_ptr<const SPIRVShaderResources> pShaderResources[], - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - std::vector<uint32_t> SPIRVs[], - class PipelineLayout& PipelineLayout, - bool VerifyVariables, - bool VerifyStaticSamplers) +void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice, + const ShaderStages_t& ShaderStages, + ShaderResourceLayoutVk Layouts[], + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderSPIRVs_t& SPIRVs, + class PipelineLayout& PipelineLayout, + bool VerifyVariables, + bool VerifyStaticSamplers) { #ifdef DILIGENT_DEVELOPMENT - dvpVerifyResourceLayoutDesc(NumShaders, pShaderResources, ResourceLayoutDesc, VerifyVariables, VerifyStaticSamplers); + dvpVerifyResourceLayoutDesc(ShaderStages, ResourceLayoutDesc, VerifyVariables, VerifyStaticSamplers); #endif - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr; - const Uint32 NumAllowedTypes = 0; - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr; + const Uint32 NumAllowedTypes = 0; + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + constexpr bool AllocateImmutableSamplers = true; - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - constexpr bool AllocateImmutableSamplers = true; - Layouts[s].AllocateMemory(std::move(pShaderResources[s]), LayoutDataAllocator, ResourceLayoutDesc, AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers); + Layouts[s].AllocateMemory(ShaderStages[s].second, LayoutDataAllocator, ResourceLayoutDesc, AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers); } - VERIFY_EXPR(NumShaders <= MAX_SHADERS_IN_PIPELINE); + //VERIFY_EXPR(NumShaders <= MAX_SHADERS_IN_PIPELINE); std::array<std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>, MAX_SHADERS_IN_PIPELINE> CurrResInd = {}; std::array<Uint32, MAX_SHADERS_IN_PIPELINE> CurrImmutableSamplerInd = {}; #ifdef DILIGENT_DEBUG @@ -414,7 +461,7 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* { // Separate samplers are enumerated before separate images, so the sampler // assigned to this separate image must have already been created. - SamplerInd = ResLayout.FindAssignedSampler(Attribs, CurrResInd[ShaderInd][VarType], VarType); + SamplerInd = FindAssignedSampler(ResLayout, Resources, Attribs, CurrResInd[ShaderInd][VarType], VarType); } VkSampler vkImmutableSampler = VK_NULL_HANDLE; @@ -454,42 +501,48 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* }; // First process uniform buffers for all shader stages to make sure all UBs go first in every descriptor set - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& pShader = ShaderStages[s].second; + auto& Layout = Layouts[s]; + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto& Resources = *pShaderVk->GetShaderResources(); for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n) { const auto& UB = Resources.GetUB(n); auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc); if (IsAllowedType(VarType, AllowedTypeBits)) { - AddResource(s, Layout, Resources, UB); + AddResource(static_cast<Uint32>(s), Layout, Resources, UB); } } } // Second, process all storage buffers - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& pShader = ShaderStages[s].second; + auto& Layout = Layouts[s]; + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto& Resources = *pShaderVk->GetShaderResources(); for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n) { const auto& SB = Resources.GetSB(n); auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc); if (IsAllowedType(VarType, AllowedTypeBits)) { - AddResource(s, Layout, Resources, SB); + AddResource(static_cast<Uint32>(s), Layout, Resources, SB); } } } // Finally, process all other resource types - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& Layout = Layouts[s]; - const auto& Resources = *Layout.m_pResources; + auto& pShader = ShaderStages[s].second; + auto& Layout = Layouts[s]; + auto* pShaderVk = ValidatedCast<ShaderVkImpl>(pShader); + auto& Resources = *pShaderVk->GetShaderResources(); // clang-format off Resources.ProcessResources( [&](const SPIRVShaderResourceAttribs& UB, Uint32) @@ -505,39 +558,39 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* [&](const SPIRVShaderResourceAttribs& Img, Uint32) { VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer); - AddResource(s, Layout, Resources, Img); + AddResource(static_cast<Uint32>(s), Layout, Resources, Img); }, [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32) { VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); - AddResource(s, Layout, Resources, SmplImg); + AddResource(static_cast<Uint32>(s), Layout, Resources, SmplImg); }, [&](const SPIRVShaderResourceAttribs& AC, Uint32) { VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter); - AddResource(s, Layout, Resources, AC); + AddResource(static_cast<Uint32>(s), Layout, Resources, AC); }, [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32) { VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); - AddResource(s, Layout, Resources, SepSmpl); + AddResource(static_cast<Uint32>(s), Layout, Resources, SepSmpl); }, [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) { VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); - AddResource(s, Layout, Resources, SepImg); + AddResource(static_cast<Uint32>(s), Layout, Resources, SepImg); }, [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32) { VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment); - AddResource(s, Layout, Resources, InputAtt); + AddResource(static_cast<Uint32>(s), Layout, Resources, InputAtt); } ); // clang-format on } #ifdef DILIGENT_DEBUG - for (Uint32 s = 0; s < NumShaders; ++s) + for (size_t s = 0; s < ShaderStages.size(); ++s) { auto& Layout = Layouts[s]; for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) @@ -551,41 +604,40 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* } -Uint32 ShaderResourceLayoutVk::FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, - Uint32 CurrResourceCount, - SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) const +ShaderResourceLayoutVk::VkResource::VkResource(const ShaderResourceLayoutVk& _ParentLayout, + const SPIRVShaderResourceAttribs& _SpirvAttribs, + SHADER_RESOURCE_VARIABLE_TYPE _VariableType, + uint32_t _Binding, + uint32_t _DescriptorSet, + Uint32 _CacheOffset, + Uint32 _SamplerInd, + bool _ImmutableSamplerAssigned) noexcept : + // clang-format off + Binding {static_cast<decltype(Binding)>(_Binding) }, + DescriptorSet {static_cast<decltype(DescriptorSet)>(_DescriptorSet)}, + CacheOffset {_CacheOffset }, + SamplerInd {_SamplerInd }, + VariableType {_VariableType }, + ImmutableSamplerAssigned {_ImmutableSamplerAssigned ? 1U : 0U}, + SpirvAttribs {_SpirvAttribs }, + ParentResLayout {_ParentLayout } +// clang-format on { - VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); - - Uint32 SamplerInd = VkResource::InvalidSamplerInd; - if (m_pResources->IsUsingCombinedSamplers() && SepImg.IsValidSepSamplerAssigned()) - { - const auto& SepSampler = m_pResources->GetAssignedSepSampler(SepImg); - for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) - { - const auto& Res = GetResource(ImgVarType, SamplerInd); - if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && - strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) - { - VERIFY(ImgVarType == Res.GetVariableType(), - "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name, - "' is not consistent with the type (", GetShaderVariableTypeLiteralName(Res.GetVariableType()), - ") of the separate sampler '", SepSampler.Name, - "' that is assigned to it. " - "This should never happen as when HLSL-style combined texture samplers are used, the type of the sampler " - "is derived from the type of the corresponding separate image."); - break; - } - } - if (SamplerInd == CurrResourceCount) - { - LOG_ERROR("Unable to find separate sampler '", SepSampler.Name, "' assigned to separate image '", SepImg.Name, "' in the list of already created resources. This seems to be a bug."); - SamplerInd = VkResource::InvalidSamplerInd; - } - } - return SamplerInd; + VERIFY(_CacheOffset < (1 << CacheOffsetBits), "Cache offset (", _CacheOffset, ") exceeds max representable value ", (1 << CacheOffsetBits)); + VERIFY(_SamplerInd < (1 << SamplerIndBits), "Sampler index (", _SamplerInd, ") exceeds max representable value ", (1 << SamplerIndBits)); + VERIFY(_Binding <= std::numeric_limits<decltype(Binding)>::max(), "Binding (", _Binding, ") exceeds max representable value ", std::numeric_limits<decltype(Binding)>::max()); + VERIFY(_DescriptorSet <= std::numeric_limits<decltype(DescriptorSet)>::max(), "Descriptor set (", _DescriptorSet, ") exceeds max representable value ", std::numeric_limits<decltype(DescriptorSet)>::max()); + + const size_t Size = strlen(SpirvAttribs.Name) + 1; + char* NameCopy = ALLOCATE(GetRawAllocator(), "SPIRV Attribs Name", char, Size); + std::memcpy(NameCopy, SpirvAttribs.Name, Size); + const_cast<SPIRVShaderResourceAttribs&>(SpirvAttribs).Name = NameCopy; } +ShaderResourceLayoutVk::VkResource::~VkResource() +{ + FREE(GetRawAllocator(), const_cast<char*>(SpirvAttribs.Name)); +} void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, uint32_t ArrayElement, @@ -1017,7 +1069,7 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou { auto NumStaticResources = m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC]; VERIFY(NumStaticResources == SrcLayout.m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC], "Inconsistent number of static resources"); - VERIFY(SrcLayout.m_pResources->GetShaderType() == m_pResources->GetShaderType(), "Incosistent shader types"); + VERIFY(SrcLayout.GetShaderType() == GetShaderType(), "Incosistent shader types"); // Static shader resources are stored in one large continuous descriptor set for (Uint32 r = 0; r < NumStaticResources; ++r) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index fb151407..95261295 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -1511,4 +1511,27 @@ VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags) } #undef ASSERT_SAME + +VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType) +{ + static_assert(SHADER_TYPE_LAST == SHADER_TYPE_MESH, "Please update the switch below to handle the new shader type"); + VERIFY((ShaderType & (ShaderType - 1)) == 0, "More than one shader type specified"); + switch (ShaderType) + { + // clang-format off + case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; + case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; + case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; + case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; + case SHADER_TYPE_AMPLIFICATION: return VK_SHADER_STAGE_TASK_BIT_NV; + case SHADER_TYPE_MESH: return VK_SHADER_STAGE_MESH_BIT_NV; + // clang-format on + default: + UNEXPECTED("Unknown shader type"); + return VK_SHADER_STAGE_VERTEX_BIT; + } +} + } // namespace Diligent |
