From 4ebef0135340b21bcdacf9b59a67995ee6a07ec7 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Sat, 26 May 2018 11:28:15 -0700 Subject: Reworked Vulkan shader resource layout: separated variables from layout resources --- Graphics/GraphicsEngineVulkan/CMakeLists.txt | 2 + .../include/PipelineStateVkImpl.h | 24 +- .../include/ShaderResourceBindingVkImpl.h | 24 +- .../include/ShaderResourceCacheVk.h | 21 +- .../include/ShaderResourceLayoutVk.h | 156 ++++--------- .../include/ShaderVariableVk.h | 150 +++++++++++++ .../GraphicsEngineVulkan/include/ShaderVkImpl.h | 9 +- .../src/PipelineStateVkImpl.cpp | 78 ++++--- .../src/ShaderResourceBindingVkImpl.cpp | 77 ++----- .../src/ShaderResourceLayoutVk.cpp | 244 ++++----------------- .../GraphicsEngineVulkan/src/ShaderVariableVk.cpp | 176 +++++++++++++++ Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp | 19 +- 12 files changed, 540 insertions(+), 440 deletions(-) create mode 100644 Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.h create mode 100644 Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index b4a317df..fff5b003 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -23,6 +23,7 @@ set(INCLUDE include/ShaderResourceBindingVkImpl.h include/ShaderResourceCacheVk.h include/ShaderResourceLayoutVk.h + include/ShaderVariableVk.h include/SwapChainVkImpl.h include/TextureVkImpl.h include/TextureViewVkImpl.h @@ -79,6 +80,7 @@ set(SRC src/ShaderResourceBindingVkImpl.cpp src/ShaderResourceCacheVk.cpp src/ShaderResourceLayoutVk.cpp + src/ShaderVariableVk.cpp src/SwapChainVkImpl.cpp src/TextureVkImpl.cpp src/TextureViewVkImpl.cpp diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h index 3b7166e2..b857054c 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h @@ -71,18 +71,17 @@ public: const PipelineLayout& GetPipelineLayout()const{return m_PipelineLayout;} - const ShaderResourceLayoutVk& GetShaderResLayout(SHADER_TYPE ShaderType)const + const ShaderResourceLayoutVk& GetShaderResLayout(Uint32 ShaderInd)const { - auto ShaderInd = GetShaderTypeIndex(ShaderType); - VERIFY_EXPR(m_pShaderResourceLayouts[ShaderInd] != nullptr); - return *m_pShaderResourceLayouts[ShaderInd]; + VERIFY_EXPR(ShaderInd < m_NumShaders); + return m_ShaderResourceLayouts[ShaderInd]; } IMemoryAllocator& GetResourceCacheDataAllocator(){return m_ResourceCacheDataAllocator;} - IMemoryAllocator& GetShaderResourceLayoutDataAllocator(Uint32 ActiveShaderInd) + IMemoryAllocator& GetShaderVariableDataAllocator(Uint32 ActiveShaderInd) { VERIFY_EXPR(ActiveShaderInd < m_NumShaders); - auto *pAllocator = m_ResLayoutDataAllocators.GetAllocator(ActiveShaderInd); + auto *pAllocator = m_VariableDataAllocators.GetAllocator(ActiveShaderInd); return pAllocator != nullptr ? *pAllocator : GetRawAllocator(); } @@ -92,16 +91,16 @@ private: void CreateRenderPass(const VulkanUtilities::VulkanLogicalDevice &LogicalDevice); - void ParseResourceLayoutAndCreateShader(IShader *pShader); + void ParseResourceLayoutAndCreateShader(IShader *pShader, Uint32 LayoutInd); DummyShaderVariable m_DummyVar; // Looks like there may be a bug in msvc: when allocators are declared as // an array and if an exception is thrown from constructor, the app crashes - class ResLayoutDataAllocators + class VariableDataAllocators { public: - ~ResLayoutDataAllocators() + ~VariableDataAllocators() { for(size_t i=0; i < _countof(m_pAllocators); ++i) if(m_pAllocators[i] != nullptr) @@ -111,7 +110,7 @@ private: { VERIFY_EXPR(NumActiveShaders <= _countof(m_pAllocators) ); for(Uint32 i=0; i < NumActiveShaders; ++i) - m_pAllocators[i] = NEW_POOL_OBJECT(AdaptiveFixedBlockAllocator, "Shader resource layout data allocator", GetRawAllocator(), SRBAllocationGranularity); + m_pAllocators[i] = NEW_POOL_OBJECT(AdaptiveFixedBlockAllocator, "Shader variable data allocator", GetRawAllocator(), SRBAllocationGranularity); } AdaptiveFixedBlockAllocator *GetAllocator(Uint32 ActiveShaderInd) { @@ -120,9 +119,10 @@ private: } private: AdaptiveFixedBlockAllocator *m_pAllocators[5] = {}; - }m_ResLayoutDataAllocators; // Allocators must be defined before default SRB + }m_VariableDataAllocators; // Allocators must be defined before default SRB + + ShaderResourceLayoutVk* m_ShaderResourceLayouts = nullptr; - std::array m_pShaderResourceLayouts = {}; AdaptiveFixedBlockAllocator m_ResourceCacheDataAllocator; // Use separate allocator for every shader stage std::array m_ShaderModules; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h index 5dd36dcc..079fdee0 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h @@ -31,7 +31,7 @@ #include "ShaderResourceBindingBase.h" #include "ShaderBase.h" #include "ShaderResourceCacheVk.h" -#include "ShaderResourceLayoutVk.h" +#include "ShaderVariableVk.h" namespace Diligent { @@ -51,32 +51,16 @@ public: virtual IShaderVariable *GetVariable(SHADER_TYPE ShaderType, const char *Name)override; - ShaderResourceLayoutVk& GetResourceLayout(SHADER_TYPE ResType) - { - auto ShaderInd = GetShaderTypeIndex(ResType); - auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd]; - VERIFY(ResLayoutInd >= 0, "Shader resource layout is not initialized"); - VERIFY_EXPR(ResLayoutInd < (Int32)m_NumShaders); - return m_pResourceLayouts[ResLayoutInd]; - } ShaderResourceCacheVk& GetResourceCache(){return m_ShaderResourceCache;} -#ifdef VERIFY_SHADER_BINDINGS - void dbgVerifyResourceBindings(const PipelineStateVkImpl *pPSO); -#endif - bool StaticResourcesInitialized()const{return m_bStaticResourcesInitialized;} - void InitializeStaticResources(const PipelineStateVkImpl *pPSO); - - // Updates dynamic resource descriptors in the descriptor set, for every layout. - // The set is assigned to the resource cache by PipelineLayout::AllocateDynamicDescriptorSet(). - void CommitDynamicResources(); + void SetStaticResourcesInitialized(){m_bStaticResourcesInitialized = true;} private: ShaderResourceCacheVk m_ShaderResourceCache; - ShaderResourceLayoutVk* m_pResourceLayouts = nullptr; - // Resource layout index in m_ResourceLayouts[] array for every shader stage + ShaderVariableManagerVk* m_pShaderVarMgrs = nullptr; + // Shader variable manager index in m_pShaderVarMgrs[] array for every shader stage Int8 m_ResourceLayoutIndex[6] = {-1, -1, -1, -1, -1, -1}; bool m_bStaticResourcesInitialized = false; Uint32 m_NumShaders = 0; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h index b4fe5972..c5f22aee 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h @@ -88,6 +88,11 @@ public: struct Resource { + Resource(const Resource&) = delete; + Resource(Resource&&) = delete; + Resource& operator = (const Resource&) = delete; + Resource& operator = (Resource&&) = delete; + const SPIRVShaderResourceAttribs::ResourceType Type; RefCntAutoPtr pObject; void* vkDescriptor = nullptr; @@ -106,10 +111,15 @@ public: m_pResources(pResources) {} - inline Resource& GetResource(Uint32 OffsetFromTableStart) + inline Resource& GetResource(Uint32 CacheOffset) + { + VERIFY(CacheOffset < m_NumResources, "Offset ", CacheOffset, " is out of range" ); + return m_pResources[CacheOffset]; + } + inline const Resource& GetResource(Uint32 CacheOffset)const { - VERIFY(OffsetFromTableStart < m_NumResources, "Root table at index is not large enough to store descriptor at offset ", OffsetFromTableStart ); - return m_pResources[OffsetFromTableStart]; + VERIFY(CacheOffset < m_NumResources, "Offset ", CacheOffset, " is out of range" ); + return m_pResources[CacheOffset]; } inline Uint32 GetSize()const{return m_NumResources; } @@ -137,6 +147,11 @@ public: VERIFY_EXPR(Index < m_NumSets); return reinterpret_cast(m_pMemory)[Index]; } + inline const DescriptorSet& GetDescriptorSet(Uint32 Index)const + { + VERIFY_EXPR(Index < m_NumSets); + return reinterpret_cast(m_pMemory)[Index]; + } inline Uint32 GetNumDescriptorSets()const{return m_NumSets; } diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h index 5cb2de31..389246af 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h @@ -90,12 +90,6 @@ #include #include -#include - -// Set this define to 1 to use unordered_map to store shader variables. -// Note that sizeof(m_VariableHash)==128 (release mode, MS compiler, x64). -#define USE_VARIABLE_HASH_MAP 0 - #include "ShaderBase.h" #include "HashUtils.h" @@ -111,20 +105,13 @@ namespace Diligent { /// Diligent::ShaderResourceLayoutVk class -// sizeof(ShaderResourceLayoutVk)==72 (MS compiler, x64) +// sizeof(ShaderResourceLayoutVk)==56 (MS compiler, x64) class ShaderResourceLayoutVk { public: - ShaderResourceLayoutVk(IObject &Owner, IMemoryAllocator &ResourceLayoutDataAllocator); - - // This constructor is used by ShaderResourceBindingVkImpl to clone layout from the reference layout in PipelineStateVkImpl. - // Descriptor sets and bindings must be correct. Resource cache is assigned, but not initialized. - ShaderResourceLayoutVk(IObject &Owner, - const ShaderResourceLayoutVk& SrcLayout, - IMemoryAllocator &ResourceLayoutDataAllocator, - const SHADER_VARIABLE_TYPE *AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheVk &ResourceCache); + ShaderResourceLayoutVk(IObject& Owner, + const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, + IMemoryAllocator& ResourceLayoutDataAllocator); ShaderResourceLayoutVk (const ShaderResourceLayoutVk&) = delete; ShaderResourceLayoutVk (ShaderResourceLayoutVk&&) = delete; @@ -139,17 +126,16 @@ public: // - PipelineStateVkImpl class instance to reference all types of resources (static, mutable, dynamic). // Root indices and descriptor table offsets are assigned during the initialization; // no shader resource cache is provided - void Initialize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, - const std::shared_ptr& pSrcResources, + void Initialize(const std::shared_ptr& pSrcResources, IMemoryAllocator& LayoutDataAllocator, const SHADER_VARIABLE_TYPE* AllowedVarTypes, Uint32 NumAllowedTypes, - ShaderResourceCacheVk* pResourceCache, + ShaderResourceCacheVk* pStaticResourceCache, std::vector* pSPIRV, class PipelineLayout* pPipelineLayout); - // sizeof(VkResource) == 32 (x64) - struct VkResource : IShaderVariable + // sizeof(VkResource) == 24 (x64) + struct VkResource { VkResource(const VkResource&) = delete; VkResource(VkResource&&) = delete; @@ -160,9 +146,9 @@ public: const Uint16 DescriptorSet; const Uint32 CacheOffset; // Offset from the beginning of the cached descriptor set const SPIRVShaderResourceAttribs &SpirvAttribs; - ShaderResourceLayoutVk &ParentResLayout; + const ShaderResourceLayoutVk &ParentResLayout; - VkResource(ShaderResourceLayoutVk& _ParentLayout, + VkResource(const ShaderResourceLayoutVk& _ParentLayout, const SPIRVShaderResourceAttribs& _SpirvAttribs, uint32_t _Binding, uint32_t _DescriptorSet, @@ -187,47 +173,13 @@ public: { } - virtual IReferenceCounters* GetReferenceCounters()const override final - { - return ParentResLayout.GetOwner().GetReferenceCounters(); - } - - virtual Atomics::Long AddRef()override final - { - return ParentResLayout.GetOwner().AddRef(); - } - - virtual Atomics::Long Release()override final - { - return ParentResLayout.GetOwner().Release(); - } - - void QueryInterface(const INTERFACE_ID &IID, IObject **ppInterface)override final - { - if (ppInterface == nullptr) - return; - - *ppInterface = nullptr; - if (IID == IID_ShaderVariable || IID == IID_Unknown) - { - *ppInterface = this; - (*ppInterface)->AddRef(); - } - } - - bool IsBound(Uint32 ArrayIndex); - // Non-virtual function - void BindResource(IDeviceObject *pObject, Uint32 ArrayIndex, const ShaderResourceLayoutVk *dbgResLayout); - virtual void Set(IDeviceObject *pObject)override final{ BindResource(pObject, 0, nullptr); } + // Checks if a resource is bound in ResourceCache at the given ArrayIndex + bool IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache)const; + + // Binds a resource pObject in the ResourceCache + void BindResource(IDeviceObject *pObject, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache)const; - virtual void SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements)override final - { - for(Uint32 Elem = 0; Elem < NumElements; ++Elem) - BindResource(ppObjects[Elem], FirstElement+Elem, nullptr); - } - - // Updates dynamic resource descriptors in the descriptor set. The set is assigned - // to the resource cache by PipelineLayout::AllocateDynamicDescriptorSet(). + // Updates resource descriptor in the descriptor set inline void UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, uint32_t ArrayElement, const VkDescriptorImageInfo* pImageInfo, @@ -238,57 +190,62 @@ public: void CacheBuffer(IDeviceObject* pBuffer, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd); + Uint32 ArrayInd)const; void CacheTexelBuffer(IDeviceObject* pBufferView, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd); + Uint32 ArrayInd)const; void CacheImage(IDeviceObject* pTexView, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd); + Uint32 ArrayInd)const; void CacheSeparateSampler(IDeviceObject* pSampler, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd); + Uint32 ArrayInd)const; bool UpdateCachedResource(ShaderResourceCacheVk::Resource& DstRes, Uint32 ArrayInd, IDeviceObject* pObject, INTERFACE_ID InterfaceId, - const char* ResourceName); + const char* ResourceName)const; }; - void InitializeStaticResources(const ShaderResourceLayoutVk &SrcLayout); - - // dbgResourceCache is only used for sanity check and as a remainder that the resource cache must be alive - // while Layout is alive - void BindResources( IResourceMapping* pResourceMapping, Uint32 Flags, const ShaderResourceCacheVk *dbgResourceCache ); - VkResource* GetShaderVariable( const Char* Name ); + // Copies static resources from SrcResourceCache defined by SrcLayout + // to DstResourceCache defined by this layout + void InitializeStaticResources(const ShaderResourceLayoutVk& SrcLayout, + ShaderResourceCacheVk& SrcResourceCache, + ShaderResourceCacheVk& DstResourceCache)const; #ifdef VERIFY_SHADER_BINDINGS - void dbgVerifyBindings()const; + void dbgVerifyBindings(const ShaderResourceCacheVk& ResourceCache)const; #endif - IObject& GetOwner(){return m_Owner;} - Uint32 GetResourceCount(SHADER_VARIABLE_TYPE VarType)const { return m_NumResources[VarType]; } - void InitializeResourcesInCache(); + // Initializes resource slots in the ResourceCache + void InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache)const; - void CommitDynamicResources(); - -private: - void InitVariablesHashMap(); + // Updates dynamic resource descriptors in the ResourceCache. The descriptor set is assigned + // to the resource cache by PipelineLayout::AllocateDynamicDescriptorSet(). + void CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache)const; const Char* GetShaderName()const; + const VkResource& GetResource(SHADER_VARIABLE_TYPE VarType, Uint32 r)const + { + VERIFY_EXPR( r < m_NumResources[VarType] ); + auto* Resources = reinterpret_cast(m_ResourceBuffer.get()); + return Resources[GetResourceOffset(VarType,r)]; + } + +private: Uint32 GetResourceOffset(SHADER_VARIABLE_TYPE VarType, Uint32 r)const { VERIFY_EXPR( r < m_NumResources[VarType] ); @@ -304,16 +261,11 @@ private: auto* Resources = reinterpret_cast(m_ResourceBuffer.get()); return Resources[GetResourceOffset(VarType,r)]; } - const VkResource& GetResource(SHADER_VARIABLE_TYPE VarType, Uint32 r)const + + const VkResource& GetResource(Uint32 r)const { - VERIFY_EXPR( r < m_NumResources[VarType] ); + VERIFY_EXPR(r < GetTotalResourceCount()); auto* Resources = reinterpret_cast(m_ResourceBuffer.get()); - return Resources[GetResourceOffset(VarType,r)]; - } - VkResource& GetResource(Uint32 r) - { - VERIFY_EXPR( r < GetTotalResourceCount() ); - auto* Resources = reinterpret_cast(m_ResourceBuffer.get()); return Resources[r]; } @@ -325,28 +277,16 @@ private: void AllocateMemory(IMemoryAllocator &Allocator); - - // There is no need to use shared ptr as referenced resource cache is either part of the - // parent ShaderVkImpl object or ShaderResourceBindingVkImpl object - ShaderResourceCacheVk *m_pResourceCache = nullptr; - - std::unique_ptr > m_ResourceBuffer; - std::array m_NumResources = {}; - -#if USE_VARIABLE_HASH_MAP - // Hash map to look up shader variables by name. - // Note that sizeof(m_VariableHash)==128 (release mode, MS compiler, x64). - typedef std::pair VariableHashElemType; - std::unordered_map, std::equal_to, STDAllocatorRawMem > m_VariableHash; -#endif - std::shared_ptr m_pLogicalDevice; + IObject& m_Owner; + const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice; + std::unique_ptr > m_ResourceBuffer; - IObject &m_Owner; // We must use shared_ptr to reference ShaderResources instance, because // there may be multiple objects referencing the same set of resources - std::shared_ptr m_pResources; + std::shared_ptr m_pResources; + std::array m_NumResources = {}; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.h new file mode 100644 index 00000000..13fef274 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.h @@ -0,0 +1,150 @@ +/* Copyright 2015-2018 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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. + */ + +#pragma once + +#include +#include + +// Set this define to 1 to use unordered_map to store shader variables. +// Note that sizeof(m_VariableHash)==128 (release mode, MS compiler, x64). +#define USE_VARIABLE_HASH_MAP 0 + +#include "ShaderResourceLayoutVk.h" + +namespace Diligent +{ + +class ShaderVariableVkImpl; + +class ShaderVariableManagerVk +{ +public: + ShaderVariableManagerVk(IObject &Owner) : + m_Owner(Owner) + {} + ~ShaderVariableManagerVk(); + + void Initialize(const ShaderResourceLayoutVk& Layout, + IMemoryAllocator& Allocator, + const SHADER_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + ShaderResourceCacheVk& ResourceCache); + void Destroy(IMemoryAllocator& Allocator); + + ShaderVariableVkImpl* GetVariable(const Char* Name); + + void BindResources( IResourceMapping* pResourceMapping, Uint32 Flags); + +private: + friend ShaderVariableVkImpl; + +#if USE_VARIABLE_HASH_MAP + void InitVariablesHashMap(); + + // Hash map to look up shader variables by name. + // Note that sizeof(m_VariableHash)==128 (release mode, MS compiler, x64). + typedef std::pair VariableHashElemType; + std::unordered_map, std::equal_to, STDAllocatorRawMem > m_VariableHash; +#endif + + IObject& m_Owner; + const ShaderResourceLayoutVk* m_pResourceLayout= nullptr; + ShaderResourceCacheVk* m_pResourceCache = nullptr; + ShaderVariableVkImpl* m_pVariables = nullptr; + Uint32 m_NumVariables = 0; +#ifdef _DEBUG + IMemoryAllocator* m_pDbgAllocator = nullptr; +#endif +}; + +// sizeof(ShaderVariableVkImpl) == 24 (x64) +class ShaderVariableVkImpl : public IShaderVariable +{ +public: + ShaderVariableVkImpl(ShaderVariableManagerVk& ParentManager, + const ShaderResourceLayoutVk::VkResource& Resource) : + m_ParentManager(ParentManager), + m_Resource(Resource) + {} + + ShaderVariableVkImpl(const ShaderVariableVkImpl&) = delete; + ShaderVariableVkImpl(ShaderVariableVkImpl&&) = delete; + ShaderVariableVkImpl& operator= (const ShaderVariableVkImpl&) = delete; + ShaderVariableVkImpl& operator= (ShaderVariableVkImpl&&) = delete; + + + virtual IReferenceCounters* GetReferenceCounters()const override final + { + return m_ParentManager.m_Owner.GetReferenceCounters(); + } + + virtual Atomics::Long AddRef()override final + { + return m_ParentManager.m_Owner.AddRef(); + } + + virtual Atomics::Long Release()override final + { + return m_ParentManager.m_Owner.Release(); + } + + void QueryInterface(const INTERFACE_ID &IID, IObject **ppInterface)override final + { + if (ppInterface == nullptr) + return; + + *ppInterface = nullptr; + if (IID == IID_ShaderVariable || IID == IID_Unknown) + { + *ppInterface = this; + (*ppInterface)->AddRef(); + } + } + + virtual void Set(IDeviceObject *pObject)override final + { + VERIFY_EXPR(m_ParentManager.m_pResourceCache != nullptr); + m_Resource.BindResource(pObject, 0, *m_ParentManager.m_pResourceCache); + } + + virtual void SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements)override final + { + VERIFY_EXPR(m_ParentManager.m_pResourceCache != nullptr); + for (Uint32 Elem = 0; Elem < NumElements; ++Elem) + m_Resource.BindResource(ppObjects[Elem], FirstElement + Elem, *m_ParentManager.m_pResourceCache); + } + + const ShaderResourceLayoutVk::VkResource& GetResource()const + { + return m_Resource; + } + +private: + friend ShaderVariableManagerVk; + + ShaderVariableManagerVk& m_ParentManager; + const ShaderResourceLayoutVk::VkResource& m_Resource; +}; + +} diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h b/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h index d7852c37..e70adf59 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h @@ -31,6 +31,7 @@ #include "ShaderBase.h" #include "ShaderResourceLayoutVk.h" #include "SPIRVShaderResources.h" +#include "ShaderVariableVk.h" #ifdef _DEBUG # define VERIFY_SHADER_BINDINGS @@ -63,8 +64,9 @@ public: } const std::shared_ptr& GetShaderResources()const{return m_pShaderResources;} - const ShaderResourceLayoutVk& GetConstResLayout()const{return m_StaticResLayout;} - + const ShaderResourceLayoutVk& GetStaticResLayout()const{return m_StaticResLayout;} + ShaderResourceCacheVk& GetStaticResCache(){return m_StaticResCache;} + #ifdef VERIFY_SHADER_BINDINGS void DbgVerifyStaticResourceBindings(); #endif @@ -77,7 +79,8 @@ private: // it is referenced by ShaderResourceLayoutVk class instances std::shared_ptr m_pShaderResources; ShaderResourceLayoutVk m_StaticResLayout; - ShaderResourceCacheVk m_ConstResCache; + ShaderResourceCacheVk m_StaticResCache; + ShaderVariableManagerVk m_StaticVarsMgr; std::vector m_SPIRV; }; diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index f9075de9..ad625d0b 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -36,24 +36,17 @@ namespace Diligent { -void PipelineStateVkImpl::ParseResourceLayoutAndCreateShader(IShader *pShader) +void PipelineStateVkImpl::ParseResourceLayoutAndCreateShader(IShader *pShader, Uint32 LayoutInd) { VERIFY_EXPR(pShader); - auto ShaderType = pShader->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypeIndex(ShaderType); auto *pShaderVk = ValidatedCast(pShader); - VERIFY(m_pShaderResourceLayouts[ShaderInd] == nullptr, "Shader resource layout has already been initialized"); - auto pDeviceVkImpl = ValidatedCast(pShaderVk->GetDevice()); const auto &LogicalDevice = pDeviceVkImpl->GetLogicalDevice(); - auto &ShaderResLayoutAllocator = GetRawAllocator(); - - auto *pRawMem = ALLOCATE(ShaderResLayoutAllocator, "Raw memory for ShaderResourceLayoutVk", sizeof(ShaderResourceLayoutVk)); - m_pShaderResourceLayouts[ShaderInd] = new (pRawMem) ShaderResourceLayoutVk(*this, GetRawAllocator()); + std::vector SPIRV = pShaderVk->GetSPIRV(); - m_pShaderResourceLayouts[ShaderInd]->Initialize(LogicalDevice, pShaderVk->GetShaderResources(), GetRawAllocator(), nullptr, 0, nullptr, &SPIRV, &m_PipelineLayout); + m_ShaderResourceLayouts[LayoutInd].Initialize(pShaderVk->GetShaderResources(), GetRawAllocator(), nullptr, 0, nullptr, &SPIRV, &m_PipelineLayout); VkShaderModuleCreateInfo ShaderModuleCI = {}; ShaderModuleCI.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -61,7 +54,7 @@ void PipelineStateVkImpl::ParseResourceLayoutAndCreateShader(IShader *pShader) ShaderModuleCI.flags = 0; ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); ShaderModuleCI.pCode = SPIRV.data(); - m_ShaderModules[ShaderInd] = LogicalDevice.CreateShaderModule(ShaderModuleCI, m_Desc.Name); + m_ShaderModules[LayoutInd] = LogicalDevice.CreateShaderModule(ShaderModuleCI, m_Desc.Name); } @@ -160,6 +153,12 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren m_pDefaultShaderResBinding(nullptr, STDDeleter(pDeviceVk->GetSRBAllocator()) ) { const auto &LogicalDevice = pDeviceVk->GetLogicalDevice(); + auto &ShaderResLayoutAllocator = GetRawAllocator(); + auto *pRawMem = ALLOCATE(ShaderResLayoutAllocator, "Raw memory for ShaderResourceLayoutVk", sizeof(ShaderResourceLayoutVk) * m_NumShaders); + m_ShaderResourceLayouts = reinterpret_cast(pRawMem); + for(Uint32 s=0; s < m_NumShaders; ++s) + new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk(*this, LogicalDevice, GetRawAllocator()); + if (PipelineDesc.IsComputePipeline) { auto &ComputePipeline = PipelineDesc.ComputePipeline; @@ -182,7 +181,7 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren CSStage.flags = 0; // reserved for future use CSStage.stage = VK_SHADER_STAGE_COMPUTE_BIT; - ParseResourceLayoutAndCreateShader(ComputePipeline.pCS); + ParseResourceLayoutAndCreateShader(ComputePipeline.pCS, 0); CSStage.module = m_ShaderModules[CSInd]; m_PipelineLayout.Finalize(LogicalDevice); @@ -233,7 +232,7 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren default: UNEXPECTED("Unknown shader type"); } - ParseResourceLayoutAndCreateShader(pShader); + ParseResourceLayoutAndCreateShader(pShader, s); StageCI.module = m_ShaderModules[GetShaderTypeIndex(ShaderType)]; StageCI.pName = "main"; // entry point @@ -371,18 +370,16 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren } if(PipelineDesc.SRBAllocationGranularity > 1) - m_ResLayoutDataAllocators.Init(m_NumShaders, PipelineDesc.SRBAllocationGranularity); + m_VariableDataAllocators.Init(m_NumShaders, PipelineDesc.SRBAllocationGranularity); bool HasStaticResources = false; bool HasNonStaticResources = false; - for (auto *pLayout : m_pShaderResourceLayouts) + for (Uint32 s=0; s < m_NumShaders; ++s) { - if (pLayout != nullptr) - { - HasStaticResources = pLayout->GetResourceCount(SHADER_VARIABLE_TYPE_STATIC) != 0; - HasNonStaticResources = pLayout->GetResourceCount(SHADER_VARIABLE_TYPE_MUTABLE) != 0 || - pLayout->GetResourceCount(SHADER_VARIABLE_TYPE_DYNAMIC) != 0; - } + const auto &Layout = m_ShaderResourceLayouts[s]; + HasStaticResources = Layout.GetResourceCount(SHADER_VARIABLE_TYPE_STATIC) != 0; + HasNonStaticResources = Layout.GetResourceCount(SHADER_VARIABLE_TYPE_MUTABLE) != 0 || + Layout.GetResourceCount(SHADER_VARIABLE_TYPE_DYNAMIC) != 0; } // If there are only static resources, create default shader resource binding @@ -412,15 +409,12 @@ PipelineStateVkImpl::~PipelineStateVkImpl() } } - auto &ShaderResLayoutAllocator = GetRawAllocator(); - for (auto *pLayout : m_pShaderResourceLayouts) + for (Uint32 s=0; s < m_NumShaders; ++s) { - if (pLayout != nullptr) - { - pLayout->~ShaderResourceLayoutVk(); - ShaderResLayoutAllocator.Free(pLayout); - } + m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk(); } + auto &ShaderResLayoutAllocator = GetRawAllocator(); + ShaderResLayoutAllocator.Free(m_ShaderResourceLayouts); } IMPLEMENT_QUERY_INTERFACE( PipelineStateVkImpl, IID_PipelineStateVk, TPipelineStateBase ) @@ -525,15 +519,30 @@ ShaderResourceCacheVk* PipelineStateVkImpl::CommitAndTransitionShaderResources(I } #endif + auto &ResourceCache = pResBindingVkImpl->GetResourceCache(); + // First time only, copy static shader resources to the cache if(!pResBindingVkImpl->StaticResourcesInitialized()) - pResBindingVkImpl->InitializeStaticResources(this); - + { + for (Uint32 s = 0; s < m_NumShaders; ++s) + { + auto *pShaderVk = ValidatedCast( m_ppShaders[s] ); #ifdef VERIFY_SHADER_BINDINGS - pResBindingVkImpl->dbgVerifyResourceBindings(this); + pShaderVk->DbgVerifyStaticResourceBindings(); #endif + auto &StaticResLayout = pShaderVk->GetStaticResLayout(); + auto &StaticResCache = pShaderVk->GetStaticResCache(); + m_ShaderResourceLayouts[s].InitializeStaticResources(StaticResLayout, StaticResCache, ResourceCache); + } + pResBindingVkImpl->SetStaticResourcesInitialized(); + } - auto &ResourceCache = pResBindingVkImpl->GetResourceCache(); +#ifdef VERIFY_SHADER_BINDINGS + for (Uint32 s = 0; s < m_NumShaders; ++s) + { + m_ShaderResourceLayouts[s].dbgVerifyBindings(ResourceCache); + } +#endif if(CommitResources) { @@ -550,7 +559,10 @@ ShaderResourceCacheVk* PipelineStateVkImpl::CommitAndTransitionShaderResources(I // Allocate vulkan descriptor set for dynamic resources m_PipelineLayout.AllocateDynamicDescriptorSet(pDeviceVkImpl, pCtxVkImpl, ResourceCache); // Commit all dynamic resource descriptors - pResBindingVkImpl->CommitDynamicResources(); + for(Uint32 s=0; s < m_NumShaders; ++s) + { + m_ShaderResourceLayouts[s].CommitDynamicResources(ResourceCache); + } // Bind descriptor sets m_PipelineLayout.BindDescriptorSets(pCtxVkImpl, m_Desc.IsComputePipeline, ResourceCache); } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp index b320d5ba..844c830b 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp @@ -21,6 +21,7 @@ * of the possibility of such damages. */ +#include #include "pch.h" #include "ShaderResourceBindingVkImpl.h" #include "PipelineStateVkImpl.h" @@ -39,11 +40,11 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl( IReferenceCounters *pR auto *pRenderDeviceVkImpl = ValidatedCast(pPSO->GetDevice()); // This only allocate memory and initialize descriptor sets in the resource cache - // Resources will be initialized by InitializeResourcesInCache() + // Resources will be initialized by InitializeResourceMemoryInCache() pPSO->GetPipelineLayout().InitResourceCache(pRenderDeviceVkImpl, m_ShaderResourceCache, pPSO->GetResourceCacheDataAllocator()); - auto *pResLayoutRawMem = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceLayoutVk", m_NumShaders * sizeof(ShaderResourceLayoutVk)); - m_pResourceLayouts = reinterpret_cast(pResLayoutRawMem); + auto *pVarMgrsRawMem = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerVk", m_NumShaders * sizeof(ShaderVariableManagerVk)); + m_pShaderVarMgrs = reinterpret_cast(pVarMgrsRawMem); for (Uint32 s = 0; s < m_NumShaders; ++s) { @@ -51,11 +52,13 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl( IReferenceCounters *pR auto ShaderType = pShader->GetDesc().ShaderType; auto ShaderInd = GetShaderTypeIndex(ShaderType); - auto &ShaderResLayoutDataAllocator = pPSO->GetShaderResourceLayoutDataAllocator(s); + auto &VarDataAllocator = pPSO->GetShaderVariableDataAllocator(s); - const auto &SrcLayout = pPSO->GetShaderResLayout(ShaderType); - new (m_pResourceLayouts + s) ShaderResourceLayoutVk(*this, SrcLayout, ShaderResLayoutDataAllocator, nullptr, 0, m_ShaderResourceCache); - m_pResourceLayouts[s].InitializeResourcesInCache(); + const auto &SrcLayout = pPSO->GetShaderResLayout(s); + new (m_pShaderVarMgrs + s) ShaderVariableManagerVk(*this); + std::array VarTypes = {SHADER_VARIABLE_TYPE_MUTABLE, SHADER_VARIABLE_TYPE_DYNAMIC}; + m_pShaderVarMgrs[s].Initialize(SrcLayout, VarDataAllocator, VarTypes.data(), static_cast(VarTypes.size()), m_ShaderResourceCache); + SrcLayout.InitializeResourceMemoryInCache(m_ShaderResourceCache); m_ResourceLayoutIndex[ShaderInd] = static_cast(s); } @@ -63,10 +66,15 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl( IReferenceCounters *pR ShaderResourceBindingVkImpl::~ShaderResourceBindingVkImpl() { - for(Uint32 l = 0; l < m_NumShaders; ++l) - m_pResourceLayouts[l].~ShaderResourceLayoutVk(); + PipelineStateVkImpl* pPSO = ValidatedCast(m_pPSO); + for(Uint32 s = 0; s < m_NumShaders; ++s) + { + auto &VarDataAllocator = pPSO->GetShaderVariableDataAllocator(s); + m_pShaderVarMgrs[s].Destroy(VarDataAllocator); + m_pShaderVarMgrs[s].~ShaderVariableManagerVk(); + } - GetRawAllocator().Free(m_pResourceLayouts); + GetRawAllocator().Free(m_pShaderVarMgrs); } IMPLEMENT_QUERY_INTERFACE( ShaderResourceBindingVkImpl, IID_ShaderResourceBindingVk, TBase ) @@ -80,7 +88,7 @@ void ShaderResourceBindingVkImpl::BindResources(Uint32 ShaderFlags, IResourceMap auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd]; if(ResLayoutInd >= 0) { - m_pResourceLayouts[ResLayoutInd].BindResources(pResMapping, Flags, &m_ShaderResourceCache); + m_pShaderVarMgrs[ResLayoutInd].BindResources(pResMapping, Flags); } } } @@ -95,8 +103,8 @@ IShaderVariable *ShaderResourceBindingVkImpl::GetVariable(SHADER_TYPE ShaderType LOG_ERROR_MESSAGE("Failed to find shader variable \"", Name,"\" in shader resource binding: shader type ", GetShaderTypeLiteralName(ShaderType), " is not initialized"); return ValidatedCast(GetPipelineState())->GetDummyShaderVar(); } - auto *pVar = m_pResourceLayouts[ResLayoutInd].GetShaderVariable(Name); - if(pVar->SpirvAttribs.VarType == SHADER_VARIABLE_TYPE_STATIC) + auto *pVar = m_pShaderVarMgrs[ResLayoutInd].GetVariable(Name); + if(pVar->GetResource().SpirvAttribs.VarType == SHADER_VARIABLE_TYPE_STATIC) { LOG_ERROR_MESSAGE("Static shader variable \"", Name, "\" must not be accessed through shader resource binding object. Static variable should be set through shader objects."); pVar = nullptr; @@ -108,47 +116,4 @@ IShaderVariable *ShaderResourceBindingVkImpl::GetVariable(SHADER_TYPE ShaderType return pVar; } -#ifdef VERIFY_SHADER_BINDINGS -void ShaderResourceBindingVkImpl::dbgVerifyResourceBindings(const PipelineStateVkImpl *pPSO) -{ - auto *pRefPSO = GetPipelineState(); - if (pPSO->IsIncompatibleWith(pRefPSO)) - { - LOG_ERROR("Shader resource binding is incompatible with the pipeline state \"", pPSO->GetDesc().Name, '\"'); - return; - } - for(Uint32 l = 0; l < m_NumShaders; ++l) - m_pResourceLayouts[l].dbgVerifyBindings(); -} -#endif - -void ShaderResourceBindingVkImpl::InitializeStaticResources(const PipelineStateVkImpl *pPSO) -{ - VERIFY(!StaticResourcesInitialized(), "Static resources have already been initialized"); - VERIFY(pPSO == GetPipelineState(), "Invalid pipeline state provided"); - - auto NumShaders = pPSO->GetNumShaders(); - auto ppShaders = pPSO->GetShaders(); - // Copy static resources - for (Uint32 s = 0; s < NumShaders; ++s) - { - auto *pShader = ValidatedCast( ppShaders[s] ); -#ifdef VERIFY_SHADER_BINDINGS - pShader->DbgVerifyStaticResourceBindings(); -#endif - auto &ConstResLayout = pShader->GetConstResLayout(); - GetResourceLayout(pShader->GetDesc().ShaderType).InitializeStaticResources(ConstResLayout); - } - - m_bStaticResourcesInitialized = true; -} - -void ShaderResourceBindingVkImpl::CommitDynamicResources() -{ - for (Uint32 s=0; s < m_NumShaders; ++s) - { - m_pResourceLayouts[s].CommitDynamicResources(); - } -} - } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index 1b273233..0885f6a8 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -37,9 +37,11 @@ namespace Diligent { -ShaderResourceLayoutVk::ShaderResourceLayoutVk(IObject &Owner, - IMemoryAllocator &ResourceLayoutDataAllocator) : +ShaderResourceLayoutVk::ShaderResourceLayoutVk(IObject& Owner, + const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, + IMemoryAllocator& ResourceLayoutDataAllocator) : m_Owner(Owner), + m_LogicalDevice(LogicalDevice), #if USE_VARIABLE_HASH_MAP m_VariableHash(STD_ALLOCATOR_RAW_MEM(VariableHashElemType, GetRawAllocator(), "Allocator for unordered_map")), #endif @@ -66,67 +68,17 @@ void ShaderResourceLayoutVk::AllocateMemory(IMemoryAllocator &Allocator) m_ResourceBuffer.reset(pRawMem); } -// Clones layout from the reference layout maintained by the pipeline state -// Descriptor sets and bindings must be correct -// Resource cache is not initialized. -ShaderResourceLayoutVk::ShaderResourceLayoutVk(IObject &Owner, - const ShaderResourceLayoutVk& SrcLayout, - IMemoryAllocator &ResourceLayoutDataAllocator, - const SHADER_VARIABLE_TYPE *AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheVk &ResourceCache) : - ShaderResourceLayoutVk(Owner, ResourceLayoutDataAllocator) -{ - m_pLogicalDevice = SrcLayout.m_pLogicalDevice; - m_pResources = SrcLayout.m_pResources; - m_pResourceCache = &ResourceCache; - - Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) - { - m_NumResources[VarType] = IsAllowedType(VarType, AllowedTypeBits) ? SrcLayout.m_NumResources[VarType] : 0; - } - - AllocateMemory(ResourceLayoutDataAllocator); - - Uint32 CurrResInd[SHADER_VARIABLE_TYPE_NUM_TYPES] = {}; - for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) - { - if( !IsAllowedType(VarType, AllowedTypeBits)) - continue; - - Uint32 NumResources = SrcLayout.m_NumResources[VarType]; - VERIFY_EXPR(NumResources == m_NumResources[VarType]); - for( Uint32 r=0; r < NumResources; ++r ) - { - const auto &SrcRes = SrcLayout.GetResource(VarType, r); - ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource( *this, SrcRes ); - } - } - -#ifdef _DEBUG - for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) - { - VERIFY_EXPR(CurrResInd[VarType] == m_NumResources[VarType] ); - } -#endif -} - - -void ShaderResourceLayoutVk::Initialize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, - const std::shared_ptr& pSrcResources, +void ShaderResourceLayoutVk::Initialize(const std::shared_ptr& pSrcResources, IMemoryAllocator& LayoutDataAllocator, const SHADER_VARIABLE_TYPE* AllowedVarTypes, Uint32 NumAllowedTypes, - ShaderResourceCacheVk* pResourceCache, + ShaderResourceCacheVk* pStaticResourceCache, std::vector* pSPIRV, PipelineLayout* pPipelineLayout) { m_pResources = pSrcResources; - m_pResourceCache = pResourceCache; - m_pLogicalDevice = LogicalDevice.GetSharedPtr(); - VERIFY_EXPR( (pResourceCache != nullptr) ^ (pPipelineLayout != nullptr && pSPIRV != nullptr) ); + VERIFY_EXPR( (pStaticResourceCache != nullptr) ^ (pPipelineLayout != nullptr && pSPIRV != nullptr) ); Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); @@ -206,7 +158,7 @@ void ShaderResourceLayoutVk::Initialize(const VulkanUtilities::VulkanLogicalDevi // Atomic counters at index SPIRVShaderResourceAttribs::ResourceType::AtomicCounter (6) // Separate images at index SPIRVShaderResourceAttribs::ResourceType::SeparateImage (7) // Separate samplers at index SPIRVShaderResourceAttribs::ResourceType::SeparateSampler (8) - VERIFY_EXPR(m_pResourceCache != nullptr); + VERIFY_EXPR(pStaticResourceCache != nullptr); DescriptorSet = Attribs.Type; CacheOffset = StaticResCacheSetSizes[DescriptorSet]; @@ -266,37 +218,23 @@ void ShaderResourceLayoutVk::Initialize(const VulkanUtilities::VulkanLogicalDevi } #endif - if(m_pResourceCache) + if(pStaticResourceCache) { // Initialize resource cache to store static resources VERIFY_EXPR(pPipelineLayout == nullptr && pSPIRV == nullptr); - m_pResourceCache->InitializeSets(GetRawAllocator(), static_cast(StaticResCacheSetSizes.size()), StaticResCacheSetSizes.data()); - InitializeResourcesInCache(); + pStaticResourceCache->InitializeSets(GetRawAllocator(), static_cast(StaticResCacheSetSizes.size()), StaticResCacheSetSizes.data()); + InitializeResourceMemoryInCache(*pStaticResourceCache); #ifdef _DEBUG for(SPIRVShaderResourceAttribs::ResourceType ResType = SPIRVShaderResourceAttribs::ResourceType::UniformBuffer; ResType < SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes; ResType = static_cast(ResType +1)) { - VERIFY_EXPR(m_pResourceCache->GetDescriptorSet(ResType).GetSize() == StaticResCacheSetSizes[ResType]); + VERIFY_EXPR(pStaticResourceCache->GetDescriptorSet(ResType).GetSize() == StaticResCacheSetSizes[ResType]); } #endif } - - InitVariablesHashMap(); } -void ShaderResourceLayoutVk::InitVariablesHashMap() -{ -#if USE_VARIABLE_HASH_MAP - Uint32 TotalResources = GetTotalResourceCount(); - for(Uint32 r=0; r < TotalResources; ++r) - { - auto &Res = GetResource(r); - /* HashMapStringKey will make a copy of the string*/ - m_VariableHash.insert( std::make_pair( Diligent::HashMapStringKey(Res.Name), &Res ) ); - } -#endif -} #define LOG_RESOURCE_BINDING_ERROR(ResType, pResource, VarName, ShaderName, ...)\ { \ @@ -325,14 +263,14 @@ void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet WriteDescrSet.pBufferInfo = pBufferInfo; WriteDescrSet.pTexelBufferView = pTexelBufferView; - ParentResLayout.m_pLogicalDevice->UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr); + ParentResLayout.m_LogicalDevice.UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr); } bool ShaderResourceLayoutVk::VkResource::UpdateCachedResource(ShaderResourceCacheVk::Resource& DstRes, Uint32 ArrayInd, IDeviceObject* pObject, INTERFACE_ID InterfaceId, - const char* ResourceName) + const char* ResourceName)const { // We cannot use ValidatedCast<> here as the resource retrieved from the // resource mapping can be of wrong type @@ -365,7 +303,7 @@ bool ShaderResourceLayoutVk::VkResource::UpdateCachedResource(ShaderResourceCach void ShaderResourceLayoutVk::VkResource::CacheBuffer(IDeviceObject* pBuffer, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd) + Uint32 ArrayInd)const { VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageBuffer, @@ -399,7 +337,7 @@ void ShaderResourceLayoutVk::VkResource::CacheBuffer(IDeviceObject* void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* pBufferView, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd) + Uint32 ArrayInd)const { VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer, @@ -438,7 +376,7 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* pTexView, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd) + Uint32 ArrayInd)const { VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || @@ -485,7 +423,7 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* pSampler, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd) + Uint32 ArrayInd)const { VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected"); @@ -502,17 +440,14 @@ void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* } -void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject *pObj, Uint32 ArrayIndex, const ShaderResourceLayoutVk *dbgResLayout) +void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject *pObj, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache)const { - auto *pResourceCache = ParentResLayout.m_pResourceCache; - VERIFY(pResourceCache, "Resource cache is null"); - VERIFY(dbgResLayout == nullptr || pResourceCache == dbgResLayout->m_pResourceCache, "Invalid resource cache"); VERIFY_EXPR(ArrayIndex < SpirvAttribs.ArraySize); - auto &DstDescrSet = pResourceCache->GetDescriptorSet(DescriptorSet); + auto &DstDescrSet = ResourceCache.GetDescriptorSet(DescriptorSet); auto vkDescrSet = DstDescrSet.GetVkDescriptorSet(); #ifdef _DEBUG - if (pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources) + if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources) { if(SpirvAttribs.VarType == SHADER_VARIABLE_TYPE_STATIC || SpirvAttribs.VarType == SHADER_VARIABLE_TYPE_MUTABLE) { @@ -520,7 +455,7 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject *pObj, Uint3 // Dynamic variables do not have vulkan descriptor set only until they are assigned one the first time } } - else if (pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources) + else if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources) { VERIFY(vkDescrSet == VK_NULL_HANDLE, "Static shader resource cache should not have vulkan descriptor set allocation"); } @@ -573,15 +508,13 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject *pObj, Uint3 } } -bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex) +bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache)const { - auto *pResourceCache = ParentResLayout.m_pResourceCache; - VERIFY(pResourceCache, "Resource cache is null"); VERIFY_EXPR(ArrayIndex < SpirvAttribs.ArraySize); - if( DescriptorSet < pResourceCache->GetNumDescriptorSets() ) + if( DescriptorSet < ResourceCache.GetNumDescriptorSets() ) { - auto &Set = pResourceCache->GetDescriptorSet(DescriptorSet); + auto &Set = ResourceCache.GetDescriptorSet(DescriptorSet); if(CacheOffset + ArrayIndex < Set.GetSize()) { auto &CachedRes = Set.GetResource(CacheOffset + ArrayIndex); @@ -593,90 +526,10 @@ bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex) } - -void ShaderResourceLayoutVk::BindResources( IResourceMapping* pResourceMapping, Uint32 Flags, const ShaderResourceCacheVk *dbgResourceCache ) +void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayoutVk& SrcLayout, + ShaderResourceCacheVk& SrcResourceCache, + ShaderResourceCacheVk& DstResourceCache)const { - VERIFY(dbgResourceCache == m_pResourceCache, "Resource cache does not match the cache provided at initialization"); - - if( !pResourceMapping ) - { - LOG_ERROR_MESSAGE( "Failed to bind resources in shader \"", GetShaderName(), "\": resource mapping is null" ); - return; - } - - Uint32 TotalResources = GetTotalResourceCount(); - for(Uint32 r=0; r < TotalResources; ++r) - { - auto &Res = GetResource(r); - for(Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd) - { - if( Flags & BIND_SHADER_RESOURCES_RESET_BINDINGS ) - Res.BindResource(nullptr, ArrInd, this); - - if( (Flags & BIND_SHADER_RESOURCES_UPDATE_UNRESOLVED) && Res.IsBound(ArrInd) ) - return; - - const auto* VarName = Res.SpirvAttribs.Name; - RefCntAutoPtr pObj; - VERIFY_EXPR(pResourceMapping != nullptr); - pResourceMapping->GetResource( VarName, &pObj, ArrInd ); - if( pObj ) - { - // Call non-virtual function - Res.BindResource(pObj, ArrInd, this); - } - else - { - if( (Flags & BIND_SHADER_RESOURCES_ALL_RESOLVED) && !Res.IsBound(ArrInd) ) - LOG_ERROR_MESSAGE( "Cannot bind resource to shader variable \"", Res.SpirvAttribs.GetPrintName(ArrInd), "\": resource view not found in the resource mapping" ); - } - } - } -} - -ShaderResourceLayoutVk::VkResource* ShaderResourceLayoutVk::GetShaderVariable(const Char* Name) -{ - ShaderResourceLayoutVk::VkResource* pVar = nullptr; -#if USE_VARIABLE_HASH_MAP - // Name will be implicitly converted to HashMapStringKey without making a copy - auto it = m_VariableHash.find( Name ); - if( it != m_VariableHash.end() ) - pVar = it->second; -#else - Uint32 TotalResources = GetTotalResourceCount(); - for(Uint32 r=0; r < TotalResources; ++r) - { - auto &Res = GetResource(r); - if(strcmp(Res.SpirvAttribs.Name, Name) == 0) - { - pVar = &Res; - break; - } - } -#endif - - if(pVar == nullptr) - { - LOG_ERROR_MESSAGE( "Shader variable \"", Name, "\" is not found in shader \"", GetShaderName(), "\" (", GetShaderTypeLiteralName(m_pResources->GetShaderType()), "). Attempts to set the variable will be silently ignored." ); - } - return pVar; -} - - -void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayoutVk &SrcLayout) -{ - if (!m_pResourceCache) - { - LOG_ERROR("Resource layout has no resource cache"); - return; - } - - if (!SrcLayout.m_pResourceCache) - { - LOG_ERROR("Src layout has no resource cache"); - return; - } - auto NumStaticResources = m_NumResources[SHADER_VARIABLE_TYPE_STATIC]; VERIFY(NumStaticResources == SrcLayout.m_NumResources[SHADER_VARIABLE_TYPE_STATIC], "Inconsistent number of static resources"); VERIFY(SrcLayout.m_pResources->GetShaderType() == m_pResources->GetShaderType(), "Incosistent shader types"); @@ -707,16 +560,16 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou for(Uint32 ArrInd = 0; ArrInd < DstRes.SpirvAttribs.ArraySize; ++ArrInd) { auto SrcOffset = SrcRes.CacheOffset + ArrInd; - IDeviceObject *pObject = SrcLayout.m_pResourceCache->GetDescriptorSet(SrcRes.DescriptorSet).GetResource(SrcOffset).pObject; + IDeviceObject* pObject = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet).GetResource(SrcOffset).pObject; if (!pObject) LOG_ERROR_MESSAGE("No resource assigned to static shader variable \"", SrcRes.SpirvAttribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"."); auto DstOffset = DstRes.CacheOffset + ArrInd; - IDeviceObject *pCachedResource = m_pResourceCache->GetDescriptorSet(DstRes.DescriptorSet).GetResource(DstOffset).pObject; + IDeviceObject* pCachedResource = DstResourceCache.GetDescriptorSet(DstRes.DescriptorSet).GetResource(DstOffset).pObject; if(pCachedResource != pObject) { VERIFY(pCachedResource == nullptr, "Static resource has already been initialized, and the resource to be assigned from the shader does not match previously assigned resource"); - DstRes.SetArray(&pObject, ArrInd, 1); + DstRes.BindResource(pObject, ArrInd, DstResourceCache); } } } @@ -724,10 +577,8 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou #ifdef VERIFY_SHADER_BINDINGS -void ShaderResourceLayoutVk::dbgVerifyBindings()const +void ShaderResourceLayoutVk::dbgVerifyBindings(const ShaderResourceCacheVk& ResourceCache)const { - VERIFY(m_pResourceCache, "Resource cache is null"); - for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) { for(Uint32 r=0; r < m_NumResources[VarType]; ++r) @@ -736,7 +587,7 @@ void ShaderResourceLayoutVk::dbgVerifyBindings()const VERIFY(Res.SpirvAttribs.VarType == VarType, "Unexpected variable type"); for(Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd) { - auto &CachedDescrSet = m_pResourceCache->GetDescriptorSet(Res.DescriptorSet); + auto &CachedDescrSet = ResourceCache.GetDescriptorSet(Res.DescriptorSet); const auto &CachedRes = CachedDescrSet.GetResource(Res.CacheOffset + ArrInd); VERIFY(CachedRes.Type == Res.SpirvAttribs.Type, "Inconsistent types"); if(CachedRes.pObject == nullptr && @@ -746,7 +597,7 @@ void ShaderResourceLayoutVk::dbgVerifyBindings()const } #ifdef _DEBUG auto vkDescSet = CachedDescrSet.GetVkDescriptorSet(); - auto dbgCacheContentType = m_pResourceCache->DbgGetContentType(); + auto dbgCacheContentType = ResourceCache.DbgGetContentType(); if(dbgCacheContentType == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources) VERIFY(vkDescSet == VK_NULL_HANDLE, "Static resource cache should never have vulkan descriptor set"); else if (dbgCacheContentType == ShaderResourceCacheVk::DbgCacheContentType::SRBResources) @@ -776,11 +627,10 @@ const Char* ShaderResourceLayoutVk::GetShaderName()const } else { - RefCntAutoPtr pSRB(&m_Owner, IID_ShaderResourceBinding); - if(pSRB) + RefCntAutoPtr pPSO(&m_Owner, IID_PipelineState); + if(pPSO) { - auto *pPSO = pSRB->GetPipelineState(); - auto *pPSOVk = ValidatedCast(pPSO); + auto *pPSOVk = pPSO.RawPtr(); auto *ppShaders = pPSOVk->GetShaders(); auto NumShaders = pPSOVk->GetNumShaders(); for (Uint32 s = 0; s < NumShaders; ++s) @@ -793,25 +643,23 @@ const Char* ShaderResourceLayoutVk::GetShaderName()const } else { - UNEXPECTED("Owner is expected to be a shader or a shader resource binding"); + UNEXPECTED("Shader resource layout owner must be a shader or a pipeline state"); } } return ""; } -void ShaderResourceLayoutVk::InitializeResourcesInCache() +void ShaderResourceLayoutVk::InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache)const { - VERIFY_EXPR(m_pResourceCache); for(Uint32 r = 0; r < GetTotalResourceCount(); ++r) { const auto& Res = GetResource(r); - m_pResourceCache->InitializeResources(Res.DescriptorSet, Res.CacheOffset, Res.SpirvAttribs.ArraySize, Res.SpirvAttribs.Type); + ResourceCache.InitializeResources(Res.DescriptorSet, Res.CacheOffset, Res.SpirvAttribs.ArraySize, Res.SpirvAttribs.Type); } } -void ShaderResourceLayoutVk::CommitDynamicResources() +void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache)const { - VERIFY_EXPR(m_pResourceCache); Uint32 NumDynamicResources = m_NumResources[SHADER_VARIABLE_TYPE_DYNAMIC]; if(NumDynamicResources == 0) return; @@ -836,7 +684,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources() { const auto& Res = GetResource(SHADER_VARIABLE_TYPE_DYNAMIC, r); VERIFY_EXPR(Res.SpirvAttribs.VarType == SHADER_VARIABLE_TYPE_DYNAMIC); - auto& SetResources = m_pResourceCache->GetDescriptorSet(Res.DescriptorSet); + auto& SetResources = ResourceCache.GetDescriptorSet(Res.DescriptorSet); auto vkSet = SetResources.GetVkDescriptorSet(); VERIFY(vkSet != VK_NULL_HANDLE, "Vulkan descriptor set must not be null"); switch(Res.SpirvAttribs.Type) @@ -845,7 +693,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources() case SPIRVShaderResourceAttribs::ResourceType::StorageBuffer: for (Uint32 i = 0; i < Res.SpirvAttribs.ArraySize; ++i) { - auto CachedRes = SetResources.GetResource(Res.CacheOffset + i); + const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + i); VkDescriptorBufferInfo DescrBuffInfo = CachedRes.GetBufferDescriptorWriteInfo(); Res.UpdateDescriptorHandle(vkSet, i, nullptr, &DescrBuffInfo, nullptr); } @@ -855,7 +703,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources() case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: for (Uint32 i = 0; i < Res.SpirvAttribs.ArraySize; ++i) { - auto CachedRes = SetResources.GetResource(Res.CacheOffset + i); + const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + i); VkBufferView BuffView = CachedRes.GetBufferViewWriteInfo(); Res.UpdateDescriptorHandle(vkSet, i, nullptr, nullptr, &BuffView); } @@ -866,7 +714,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources() case SPIRVShaderResourceAttribs::ResourceType::SampledImage: for (Uint32 i = 0; i < Res.SpirvAttribs.ArraySize; ++i) { - auto CachedRes = SetResources.GetResource(Res.CacheOffset + i); + const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + i); VkDescriptorImageInfo DescrImgInfo = CachedRes.GetImageDescriptorWriteInfo(Res.SpirvAttribs.StaticSamplerInd >= 0); Res.UpdateDescriptorHandle(vkSet, i, &DescrImgInfo, nullptr, nullptr); } @@ -882,7 +730,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources() { if(Res.SpirvAttribs.StaticSamplerInd < 0) { - auto CachedRes = SetResources.GetResource(Res.CacheOffset + i); + const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + i); VkDescriptorImageInfo DescrImgInfo = CachedRes.GetSamplerDescriptorWriteInfo(); Res.UpdateDescriptorHandle(vkSet, i, &DescrImgInfo, nullptr, nullptr); } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp new file mode 100644 index 00000000..6f6f7d9e --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp @@ -0,0 +1,176 @@ +/* Copyright 2015-2018 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "ShaderVariableVk.h" + +namespace Diligent +{ + + + +// Clones layout from the reference layout maintained by the pipeline state +// Descriptor sets and bindings must be correct +// Resource cache is not initialized. +void ShaderVariableManagerVk::Initialize(const ShaderResourceLayoutVk& SrcLayout, + IMemoryAllocator& Allocator, + const SHADER_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + ShaderResourceCacheVk& ResourceCache) +{ + m_pResourceLayout = &SrcLayout; + m_pResourceCache = &ResourceCache; +#ifdef _DEBUG + m_pDbgAllocator = &Allocator; +#endif + + VERIFY_EXPR(m_NumVariables == 0); + m_NumVariables = 0; + Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) + { + m_NumVariables += IsAllowedType(VarType, AllowedTypeBits) ? SrcLayout.GetResourceCount(VarType) : 0; + } + + auto *pRawMem = ALLOCATE(Allocator, "Raw memory buffer for shader variables", m_NumVariables*sizeof(ShaderVariableVkImpl)); + m_pVariables = reinterpret_cast(pRawMem); + + Uint32 VarInd = 0; + for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) + { + if( !IsAllowedType(VarType, AllowedTypeBits)) + continue; + + Uint32 NumResources = SrcLayout.GetResourceCount(VarType); + for( Uint32 r=0; r < NumResources; ++r ) + { + const auto &SrcRes = SrcLayout.GetResource(VarType, r); + ::new (m_pVariables + VarInd) ShaderVariableVkImpl(*this, SrcRes ); + ++VarInd; + } + } + VERIFY_EXPR(VarInd == m_NumVariables); + +#if USE_VARIABLE_HASH_MAP + InitVariablesHashMap(); +#endif +} + +ShaderVariableManagerVk::~ShaderVariableManagerVk() +{ + VERIFY(m_pVariables == nullptr, "Destroy() has not been called"); +} + +void ShaderVariableManagerVk::Destroy(IMemoryAllocator &Allocator) +{ + VERIFY(m_pDbgAllocator == &Allocator, "Incosistent alloctor"); + + for(Uint32 v=0; v < m_NumVariables; ++v) + m_pVariables[v].~ShaderVariableVkImpl(); + Allocator.Free(m_pVariables); + m_pVariables = nullptr; +} + +ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) +{ + ShaderVariableVkImpl* pVar = nullptr; +#if USE_VARIABLE_HASH_MAP + // Name will be implicitly converted to HashMapStringKey without making a copy + auto it = m_VariableHash.find(Name); + if (it != m_VariableHash.end()) + pVar = it->second; +#else + for (Uint32 v = 0; v < m_NumVariables; ++v) + { + auto &Var = m_pVariables[v]; + const auto& Res = Var.m_Resource; + if (strcmp(Res.SpirvAttribs.Name, Name) == 0) + { + pVar = &Var; + break; + } + } +#endif + + if (pVar == nullptr) + { + LOG_ERROR_MESSAGE("Shader variable \"", Name, "\" is not found in shader \"", m_pResourceLayout->GetShaderName(), "\". Attempts to set the variable will be silently ignored."); + } + return pVar; +} + + + +void ShaderVariableManagerVk::BindResources( IResourceMapping* pResourceMapping, Uint32 Flags) +{ + VERIFY_EXPR(m_pResourceCache != nullptr); + + if( !pResourceMapping ) + { + LOG_ERROR_MESSAGE( "Failed to bind resources: resource mapping is null" ); + return; + } + + for(Uint32 v=0; v < m_NumVariables; ++v) + { + auto &Var = m_pVariables[v]; + const auto& Res = Var.m_Resource; + for(Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd) + { + if( Flags & BIND_SHADER_RESOURCES_RESET_BINDINGS ) + Res.BindResource(nullptr, ArrInd, *m_pResourceCache); + + if( (Flags & BIND_SHADER_RESOURCES_UPDATE_UNRESOLVED) && Res.IsBound(ArrInd, *m_pResourceCache) ) + return; + + const auto* VarName = Res.SpirvAttribs.Name; + RefCntAutoPtr pObj; + pResourceMapping->GetResource( VarName, &pObj, ArrInd ); + if( pObj ) + { + Res.BindResource(pObj, ArrInd, *m_pResourceCache); + } + else + { + if( (Flags & BIND_SHADER_RESOURCES_ALL_RESOLVED) && !Res.IsBound(ArrInd, *m_pResourceCache) ) + LOG_ERROR_MESSAGE( "Cannot bind resource to shader variable \"", Res.SpirvAttribs.GetPrintName(ArrInd), "\": resource view not found in the resource mapping" ); + } + } + } +} + +#if USE_VARIABLE_HASH_MAP +void ShaderVariableManagerVk::InitVariablesHashMap() +{ + Uint32 TotalResources = GetTotalResourceCount(); + for (Uint32 r = 0; r < TotalResources; ++r) + { + auto &Res = GetResource(r); + /* HashMapStringKey will make a copy of the string*/ + m_VariableHash.insert(std::make_pair(Diligent::HashMapStringKey(Res.Name), &Res)); + } +} +#endif + +} diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp index ae6c745d..b568c3d6 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp @@ -21,6 +21,7 @@ * of the possibility of such damages. */ +#include #include "pch.h" #include "ShaderVkImpl.h" @@ -37,9 +38,10 @@ namespace Diligent ShaderVkImpl::ShaderVkImpl(IReferenceCounters *pRefCounters, RenderDeviceVkImpl *pRenderDeviceVk, const ShaderCreationAttribs &CreationAttribs) : TShaderBase(pRefCounters, pRenderDeviceVk, CreationAttribs.Desc), - m_StaticResLayout(*this, GetRawAllocator()), + m_StaticResLayout(*this, pRenderDeviceVk->GetLogicalDevice(), GetRawAllocator()), m_DummyShaderVar(*this), - m_ConstResCache(ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources) + m_StaticResCache(ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources), + m_StaticVarsMgr(*this) { auto GLSLSource = BuildGLSLSourceString(CreationAttribs, TargetGLSLCompiler::glslang); m_SPIRV = GLSLtoSPIRV(m_Desc.ShaderType, GLSLSource.c_str()); @@ -59,29 +61,32 @@ ShaderVkImpl::ShaderVkImpl(IReferenceCounters *pRefCounters, RenderDeviceVkImpl // Clone only static resources that will be set directly in the shader // http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Special-Resource-Layout-for-Managing-Static-Shader-Resources - SHADER_VARIABLE_TYPE VarTypes[] = {SHADER_VARIABLE_TYPE_STATIC}; - m_StaticResLayout.Initialize(pRenderDeviceVk->GetLogicalDevice(), m_pShaderResources, GetRawAllocator(), VarTypes, _countof(VarTypes), &m_ConstResCache, nullptr, nullptr); + std::array VarTypes = {SHADER_VARIABLE_TYPE_STATIC}; + m_StaticResLayout.Initialize(m_pShaderResources, GetRawAllocator(), + VarTypes.data(), static_cast(VarTypes.size()), &m_StaticResCache, nullptr, nullptr); + m_StaticVarsMgr.Initialize(m_StaticResLayout, GetRawAllocator(), nullptr, 0, m_StaticResCache); } ShaderVkImpl::~ShaderVkImpl() { + m_StaticVarsMgr.Destroy(GetRawAllocator()); } void ShaderVkImpl::BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) { - m_StaticResLayout.BindResources(pResourceMapping, Flags, &m_ConstResCache); + m_StaticVarsMgr.BindResources(pResourceMapping, Flags); } IShaderVariable* ShaderVkImpl::GetShaderVariable(const Char* Name) { - IShaderVariable *pVar = m_StaticResLayout.GetShaderVariable(Name); + IShaderVariable *pVar = m_StaticVarsMgr.GetVariable(Name); return (pVar != nullptr) ? pVar : &m_DummyShaderVar; } #ifdef VERIFY_SHADER_BINDINGS void ShaderVkImpl::DbgVerifyStaticResourceBindings() { - m_StaticResLayout.dbgVerifyBindings(); + m_StaticResLayout.dbgVerifyBindings(m_StaticResCache); } #endif -- cgit v1.2.3