diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2021-01-23 04:46:14 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2021-01-23 04:46:14 +0000 |
| commit | 9eca06a41fa72a8158784ad5116c717076634e40 (patch) | |
| tree | 243933cedcf15607bf2d2a976cd7eb2e8e548da7 /Graphics/GraphicsEngineVulkan | |
| parent | PipelineState.h: updated comments (diff) | |
| parent | improvements and optimizations for resource signature (diff) | |
| download | DiligentCore-9eca06a41fa72a8158784ad5116c717076634e40.tar.gz DiligentCore-9eca06a41fa72a8158784ad5116c717076634e40.zip | |
Merge branch 'azhirnov-res_layout' into resource_signature
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
13 files changed, 446 insertions, 323 deletions
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index b5797361..358cd3bc 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -479,9 +479,6 @@ private: // Graphics/mesh, compute, ray tracing static constexpr Uint32 NUM_PIPELINE_BIND_POINTS = 3; - // Static/mutable and dynamic descriptor sets - static constexpr Uint32 MAX_DESCR_SET_PER_SIGNATURE = 2; - struct DescriptorSetBindInfo { using ShaderResourceArray = std::array<RefCntAutoPtr<ShaderResourceBindingVkImpl>, MAX_RESOURCE_SIGNATURES>; @@ -491,7 +488,7 @@ private: ShaderResourceArray Resources; VkDescSetArray vkSets = {}; BoolArray PendingVkSet = {}; // 'true' if new descriptor set must be bound - BoolArray PendingDynamicDescriptors = {}; // 'true' if dynamic descriptor set must be bound + BoolArray PendingDynamicDescriptors = {}; // 'true' if dynamic descriptor set must be bound // AZ TODO: remove ? BoolArray DynamicBuffersPresent = {}; DescriptorSetBindInfo() @@ -522,7 +519,7 @@ private: /// Descriptor set binding information for each pipeline type (graphics/mesh, compute, ray tracing) std::array<DescriptorSetBindInfo, NUM_PIPELINE_BIND_POINTS> m_DescrSetBindInfo; - /// AZ TODO: comment + /// Memory to store dynamic buffer offsets for descriptor sets. std::vector<Uint32> m_DynamicBufferOffsets; /// Render pass that matches currently bound render targets. diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp index 0e35f1ae..d1e8fb38 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp @@ -54,8 +54,7 @@ public: VkPipelineLayout GetVkPipelineLayout() const { return m_VkPipelineLayout; } Uint32 GetSignatureCount() const { return m_SignatureCount; } - Uint32 GetDescriptorSetCount() const { return m_DescrSetCount; } - Uint32 GetDynamicOffsetCount() const { return m_DynamicOffsetCount; } + //Uint32 GetDescriptorSetCount() const { return m_DescrSetCount; } PipelineResourceSignatureVkImpl* GetSignature(Uint32 index) const { @@ -70,13 +69,6 @@ public: return Index < m_SignatureCount ? m_FirstDescrSetIndex[Index] : ~0u; } - // Returns the index of the first dynamic buffer used by the given resource signature - Uint32 GetFirstDynamicBufferIndex(const IPipelineResourceSignature* pPRS) const - { - Uint32 Index = pPRS->GetDesc().BindingIndex; - return Index < m_SignatureCount ? m_FirstDynBuffIndex[Index] : 0; - } - struct ResourceInfo { SHADER_RESOURCE_TYPE Type = SHADER_RESOURCE_TYPE_UNKNOWN; @@ -86,30 +78,23 @@ public: bool GetResourceInfo(const char* Name, SHADER_TYPE Stage, ResourceInfo& Info) const; private: + using SignatureArray = std::array<RefCntAutoPtr<PipelineResourceSignatureVkImpl>, MAX_RESOURCE_SIGNATURES>; + using FirstDescrSetIndexArrayType = std::array<Uint8, MAX_RESOURCE_SIGNATURES>; + VulkanUtilities::PipelineLayoutWrapper m_VkPipelineLayout; - // The total number of dynamic offsets in this pipeline layout - Uint32 m_DynamicOffsetCount = 0; + // Index of the first descriptor set, for every resource signature + FirstDescrSetIndexArrayType m_FirstDescrSetIndex = {}; // The number of resource signatures used by this pipeline layout // (Maximum is MAX_RESOURCE_SIGNATURES) - Uint16 m_SignatureCount = 0; + Uint8 m_SignatureCount = 0; // The total number of descriptor sets used by this pipeline layout. // (Maximum is MAX_RESOURCE_SIGNATURES * 2) - Uint16 m_DescrSetCount = 0; - - using SignatureArrayType = std::array<RefCntAutoPtr<PipelineResourceSignatureVkImpl>, MAX_RESOURCE_SIGNATURES>; - using FirstDescrSetIndexArrayType = std::array<Uint8, MAX_RESOURCE_SIGNATURES>; - using FirstDynBuffIndexArrayType = std::array<Uint16, MAX_RESOURCE_SIGNATURES>; - - SignatureArrayType m_Signatures; - - // Index of the first descriptor set, for every resource signature - FirstDescrSetIndexArrayType m_FirstDescrSetIndex = {}; + Uint8 m_DescrSetCount = 0; - // Index of the first dynamic buffer, for every resource signature - FirstDynBuffIndexArrayType m_FirstDynBuffIndex = {}; + SignatureArray m_Signatures; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp index c5897f86..87bc319a 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp @@ -51,7 +51,6 @@ enum class DescriptorType : Uint8 CombinedImageSampler, SeparateImage, StorageImage, - StorageImage_ReadOnly, UniformTexelBuffer, StorageTexelBuffer, StorageTexelBuffer_ReadOnly, @@ -82,26 +81,57 @@ public: bool bIsDeviceInternal = false); ~PipelineResourceSignatureVkImpl(); - Uint32 GetDynamicBufferCount() const { return m_DynamicBufferCount; } - Uint8 GetNumShaderStages() const { return m_NumShaders; } + Uint32 GetDynamicOffsetCount() const { return m_DynamicUniformBufferCount + m_DynamicStorageBufferCount; } + Uint32 GetDynamicUniformBufferCount() const { return m_DynamicUniformBufferCount; } + Uint32 GetDynamicStorageBufferCount() const { return m_DynamicStorageBufferCount; } + Uint32 GetNumDescriptorSets() const; + + Uint32 GetNumShaderStages() const { return m_NumShaders; } SHADER_TYPE GetShaderStageType(Uint32 StageIndex) const; - Uint32 GetTotalResourceCount() const { return m_Desc.NumResources; } - Uint32 GetNumDescriptorSets() const; - static constexpr Uint32 InvalidSamplerInd = ~0u; + static constexpr Uint32 InvalidSamplerInd = (1u << 16) - 1; + enum class CacheContentType + { + Signature = 0, // only static resources + SRB = 1 // in SRB + }; + + // sizeof(ResourceAttribs) == 16, x64 struct ResourceAttribs { - DescriptorType Type; - Uint32 CacheOffset; // for ShaderResourceCacheVk - Uint16 BindingIndex; - Uint8 DescrSet : 1; - Uint8 ImmutableSamplerAssigned : 1; - Uint32 SamplerInd; - - ResourceAttribs() : - CacheOffset{~0u}, BindingIndex{0xFFFF}, DescrSet{0}, SamplerInd{InvalidSamplerInd}, ImmutableSamplerAssigned{0} - {} + private: + static constexpr Uint32 _DescrTypeBits = 4; + static constexpr Uint32 _DescrSetBits = 1; + static constexpr Uint32 _BindingIndexBits = 16; + static constexpr Uint32 _SamplerIndBits = 16; + static constexpr Uint32 _SamplerAssignedBits = 1; + static constexpr Uint32 _BitsSumm = ((sizeof(Uint32) * 8 * 2) + _DescrTypeBits + _DescrSetBits + _BindingIndexBits + _SamplerIndBits + _SamplerAssignedBits + 31) & ~31; + + static_assert((1u << _DescrTypeBits) >= static_cast<Uint32>(DescriptorType::Count), "not enought bits to store DescriptorType values"); + static_assert((1u << _SamplerIndBits) - 1 == InvalidSamplerInd, "InvalidSamplerInd is incorrect"); + static_assert((1u << _DescrSetBits) == MAX_DESCR_SET_PER_SIGNATURE, "not enoght bits to store descriptor set index"); + static_assert((1u << _BindingIndexBits) >= MAX_RESOURCES_IN_SIGNATURE, "not enoght bits to store resource binding index"); + + public: + // clang-format off + Uint32 BindingIndex : _BindingIndexBits; + Uint32 SamplerInd : _SamplerIndBits; // index in m_Desc.Resources and m_pResourceAttribs + Uint32 DescrType : _DescrTypeBits; + Uint32 DescrSet : _DescrSetBits; + Uint32 ImtblSamplerAssigned : _SamplerAssignedBits; + Uint32 CacheOffsets[2]; // static and static/mutable/dynamic offsets for ShaderResourceCacheVk + + ResourceAttribs() + { + static_assert(_BitsSumm == sizeof(ResourceAttribs) * 8, "fields is not properly packed"); + } + + Uint32 CacheOffset(CacheContentType CacheType) const { return CacheOffsets[static_cast<Uint32>(CacheType)]; } + + DescriptorType Type() const { return static_cast<DescriptorType>(DescrType); } + bool IsImmutableSamplerAssigned() const { return ImtblSamplerAssigned; } + // clang-format on }; const ResourceAttribs& GetAttribs(Uint32 ResIndex) const @@ -172,15 +202,24 @@ public: } private: + using ImmutableSamplerPtrType = RefCntAutoPtr<ISampler>; + using CacheOffsetsType = std::array<Uint32, 3 * MAX_DESCR_SET_PER_SIGNATURE>; // [dynamic uniform buffers, dynamic storage buffers, other] * [descriptor sets] includes ArraySize + using BindingCountType = std::array<Uint32, 3 * MAX_DESCR_SET_PER_SIGNATURE>; // [dynamic uniform buffers, dynamic storage buffers, other] * [descriptor sets] without ArraySize + void Destruct(); void ReserveSpaceForStaticVarsMgrs(const PipelineResourceSignatureDesc& Desc, - FixedLinearAllocator& MemPool, Int8& StaticVarStageCount, Uint32& StaticVarCount, - Uint8 DSMapping[2]); + CacheOffsetsType& CacheSizes, + BindingCountType& BindingCount, + Uint8 DSMapping[MAX_DESCR_SET_PER_SIGNATURE]); + + void CreateLayout(const CacheOffsetsType& CacheSizes, + const BindingCountType& BindingCount, + const Uint8 DSMapping[MAX_DESCR_SET_PER_SIGNATURE]); - void CreateLayout(Uint32 StaticVarCount, const Uint8 DSMapping[2]); + size_t CalculateHash() const; Uint32 FindAssignedSampler(const PipelineResourceDesc& SepImg) const; @@ -188,21 +227,21 @@ private: Uint32 GetStaticDescrSetIndex() const; Uint32 GetDynamicDescrSetIndex() const; - using ImmutableSamplerPtrType = RefCntAutoPtr<ISampler>; - private: - VulkanUtilities::DescriptorSetLayoutWrapper m_VkDescSetLayouts[2]; + VulkanUtilities::DescriptorSetLayoutWrapper m_VkDescSetLayouts[MAX_DESCR_SET_PER_SIGNATURE]; ResourceAttribs* m_pResourceAttribs = nullptr; // [m_Desc.NumResources] SHADER_TYPE m_ShaderStages = SHADER_TYPE_UNKNOWN; - Uint32 m_DynamicBufferCount : 29; // buffers with dynamic offsets - Uint32 m_NumShaders : 3; + Uint16 m_DynamicUniformBufferCount = 0; + Uint16 m_DynamicStorageBufferCount = 0; std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_StaticVarIndex = {-1, -1, -1, -1, -1, -1}; static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above"); + Uint8 m_NumShaders = 0; + ShaderResourceCacheVk* m_pResourceCache = nullptr; ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; // [m_NumShaders] diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp index 0c0b07b8..438b09e9 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp @@ -38,6 +38,7 @@ #include "ShaderVariableVk.hpp" #include "FixedBlockMemoryAllocator.hpp" #include "SRBMemoryAllocator.hpp" +#include "PipelineLayoutVk.hpp" #include "VulkanUtilities/VulkanObjectWrappers.hpp" #include "VulkanUtilities/VulkanCommandBuffer.hpp" #include "RenderDeviceVkImpl.hpp" diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index d67e33d2..baa3b786 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -49,6 +49,7 @@ #include "RenderPassCache.hpp" #include "CommandPoolManager.hpp" #include "DXCompiler.hpp" +#include "PipelineResourceSignatureVkImpl.hpp" namespace Diligent { @@ -232,7 +233,8 @@ public: return m_Properties; } - IPipelineResourceSignature* GetEmptySignature() const { return m_pEmptySignature.RawPtr<IPipelineResourceSignature>(); } + IPipelineResourceSignature* GetEmptySignature() const { return m_pEmptySignature.RawPtr<IPipelineResourceSignature>(); } + PipelineResourceSignatureVkImpl* GetEmptySignatureVk() const { return m_pEmptySignature.RawPtr<PipelineResourceSignatureVkImpl>(); } private: template <typename PSOCreateInfoType> diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp index 949bf29f..db5510d6 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp @@ -68,21 +68,16 @@ class DeviceContextVkImpl; class ShaderResourceCacheVk { public: - // This enum is used for debug purposes only - enum DbgCacheContentType - { - StaticShaderResources, - SRBResources - }; + using CacheContentType = PipelineResourceSignatureVkImpl::CacheContentType; - // clang-format off - explicit ShaderResourceCacheVk(DbgCacheContentType dbgContentType) noexcept -#ifdef DILIGENT_DEBUG - : m_DbgContentType{dbgContentType} -#endif + explicit ShaderResourceCacheVk(CacheContentType ContentType) noexcept : + m_TotalResources{0}, + m_ContentType{static_cast<Uint32>(ContentType)} { + VERIFY_EXPR(GetContentType() == ContentType); } + // clang-format off ShaderResourceCacheVk (const ShaderResourceCacheVk&) = delete; ShaderResourceCacheVk (ShaderResourceCacheVk&&) = delete; ShaderResourceCacheVk& operator = (const ShaderResourceCacheVk&) = delete; @@ -189,11 +184,12 @@ public: Uint16& GetDynamicBuffersCounter() { return m_NumDynamicBuffers; } + CacheContentType GetContentType() const { return static_cast<CacheContentType>(m_ContentType); } + #ifdef DILIGENT_DEBUG // Only for debug purposes: indicates what types of resources are stored in the cache - DbgCacheContentType DbgGetContentType() const { return m_DbgContentType; } - void DbgVerifyResourceInitialization() const; - void DbgVerifyDynamicBuffersCounter() const; + void DbgVerifyResourceInitialization() const; + void DbgVerifyDynamicBuffersCounter() const; #endif template <bool VerifyOnly> @@ -215,14 +211,15 @@ private: void* m_pMemory = nullptr; Uint16 m_NumSets = 0; - // Total number of dynamic buffers bound in the resource cache regardless of the variable type. - // This variable is not equal to dynamic offsets count, it just a indicator that dynamic descriptor has dynamic buffers. + // Total number of dynamic buffers (that was created with USAGE_DYNAMIC) bound in the resource cache regardless of the variable type. + // This variable is not equal to dynamic offsets count. Uint16 m_NumDynamicBuffers = 0; - Uint32 m_TotalResources = 0; + Uint32 m_TotalResources : 31; + + // Indicates what types of resources are stored in the cache + const Uint32 m_ContentType : 1; #ifdef DILIGENT_DEBUG - // Only for debug purposes: indicates what types of resources are stored in the cache - const DbgCacheContentType m_DbgContentType; // Debug array that stores flags indicating if resources in the cache have been initialized std::vector<std::vector<bool>> m_DbgInitializedResources; #endif @@ -245,26 +242,50 @@ __forceinline Uint32 ShaderResourceCacheVk::GetDynamicBufferOffsets(Uint32 for (Uint32 set = 0; set < m_NumSets; ++set) { const auto& DescrSet = GetDescriptorSet(set); + Uint32 res = 0; - // AZ TODO: optimize - for (Uint32 res = 0; res < DescrSet.GetSize(); ++res) + while (res < DescrSet.GetSize()) { const auto& Res = DescrSet.GetResource(res); - if (Res.Type == DescriptorType::UniformBufferDynamic) { const auto* pBufferVk = Res.pObject.RawPtr<const BufferVkImpl>(); auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0; Offsets[OffsetInd++] = Offset; + ++res; } - if (Res.Type == DescriptorType::StorageBufferDynamic || Res.Type == DescriptorType::StorageBufferDynamic_ReadOnly) + else + break; + } + + while (res < DescrSet.GetSize()) + { + const auto& Res = DescrSet.GetResource(res); + if (Res.Type == DescriptorType::StorageBufferDynamic || + Res.Type == DescriptorType::StorageBufferDynamic_ReadOnly) { const auto* pBufferVkView = Res.pObject.RawPtr<const BufferViewVkImpl>(); const auto* pBufferVk = pBufferVkView != nullptr ? pBufferVkView->GetBufferVk() : 0; auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0; Offsets[OffsetInd++] = Offset; + ++res; } + else + break; + } + +#ifdef DILIGENT_DEBUG + for (; res < DescrSet.GetSize(); ++res) + { + const auto& Res = DescrSet.GetResource(res); + // clang-format off + VERIFY(Res.Type != DescriptorType::UniformBufferDynamic && + Res.Type != DescriptorType::StorageBufferDynamic && + Res.Type != DescriptorType::StorageBufferDynamic_ReadOnly, + "All uniform and storage buffers are expected to go first in the beginning of each descriptor set"); + // clang-format on } +#endif } return OffsetInd; } diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 603ce2b6..ad6be668 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -348,7 +348,7 @@ static VkPipelineBindPoint PipelineTypeToVkBindPoint(PIPELINE_TYPE Type) return vkBindPoints[Uint32{Type}]; } -void DeviceContextVkImpl::BindShaderResources(PipelineStateVkImpl* pPipelineStateVk) +__forceinline void DeviceContextVkImpl::BindShaderResources(PipelineStateVkImpl* pPipelineStateVk) { VERIFY_EXPR(pPipelineStateVk != nullptr); @@ -366,36 +366,37 @@ void DeviceContextVkImpl::BindShaderResources(PipelineStateVkImpl* pPipelineStat // (14.2.2. Pipeline Layouts, clause 'Pipeline Layout Compatibility') // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#descriptorsets-compatibility - // AZ TODO: do we need to unbind incompatible descriptor sets here or - // should the user handle this? +#ifdef DILIGENT_DEBUG // unbind incompatible descriptor sets for (Uint32 i = 0; i < SignCount; ++i) { - auto* LayoutSign = Layout.GetSignature(i); + const auto* LayoutSign = Layout.GetSignature(i); + const auto* ResSign = Resources[i] != nullptr ? Resources[i]->GetSignature() : ValidatedCast<RenderDeviceVkImpl>(GetDevice())->GetEmptySignatureVk(); + VERIFY_EXPR(LayoutSign != nullptr); + VERIFY_EXPR(ResSign != nullptr); - if (Resources[i] != nullptr && LayoutSign->IsIncompatibleWith(*Resources[i]->GetSignature())) + if (LayoutSign->IsIncompatibleWith(*ResSign)) { - Resources[i] = nullptr; - CompatSignCount = std::min(CompatSignCount, i + 1); + CompatSignCount = i; + break; } } // reset unused states for (Uint32 i = CompatSignCount; i < MAX_RESOURCE_SIGNATURES; ++i) { - Resources[i] = nullptr; - - BindInfo.PendingVkSet[i] = false; // AZ TODO: can be optimized + BindInfo.PendingVkSet[i] = false; BindInfo.PendingDynamicDescriptors[i] = false; BindInfo.DynamicBuffersPresent[i] = false; -#ifdef DILIGENT_DEBUG + Resources[i] = nullptr; + BindInfo.vkSets[i * MAX_DESCR_SET_PER_SIGNATURE + 0] = VK_NULL_HANDLE; BindInfo.vkSets[i * MAX_DESCR_SET_PER_SIGNATURE + 1] = VK_NULL_HANDLE; -#endif } +#endif } void DeviceContextVkImpl::BindDescriptorSetsWithDynamicOffsets(DescriptorSetBindInfo& BindInfo) @@ -425,12 +426,12 @@ void DeviceContextVkImpl::BindDescriptorSetsWithDynamicOffsets(DescriptorSetBind for (Uint32 s = 0; s < DSCount; ++s) VERIFY_EXPR(BindInfo.vkSets[DSOffset + s] != VK_NULL_HANDLE); #endif - if (pSignature->GetDynamicBufferCount() > 0) + if (pSignature->GetDynamicOffsetCount() > 0) { - Offsets.resize(pSignature->GetDynamicBufferCount()); + Offsets.resize(pSignature->GetDynamicOffsetCount()); auto NumOffsetsWritten = ResourceCache.GetDynamicBufferOffsets(m_ContextId, this, Offsets); - VERIFY_EXPR(NumOffsetsWritten == pSignature->GetDynamicBufferCount()); + VERIFY_EXPR(NumOffsetsWritten == pSignature->GetDynamicOffsetCount()); // Note that there is one global dynamic buffer from which all dynamic resources are suballocated in Vulkan back-end, // and this buffer is not resizable, so the buffer handle can never change. @@ -517,7 +518,7 @@ void DeviceContextVkImpl::TransitionShaderResources(IPipelineState*, IShaderReso if (pShaderResourceBinding == nullptr) { - LOG_ERROR_MESSAGE("AZ TODO"); + LOG_ERROR_MESSAGE("pShaderResourceBinding must not be null"); return; } #endif @@ -525,6 +526,7 @@ void DeviceContextVkImpl::TransitionShaderResources(IPipelineState*, IShaderReso auto* pResBindingVkImpl = ValidatedCast<ShaderResourceBindingVkImpl>(pShaderResourceBinding); auto& ResourceCache = pResBindingVkImpl->GetResourceCache(); + // AZ TODO: exclude stages that is not supported by pipeline ResourceCache.TransitionResources<false>(this); } @@ -542,6 +544,7 @@ void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderR if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { + // AZ TODO: exclude stages that is not supported by pipeline ResourceCache.TransitionResources<false>(this); } #ifdef DILIGENT_DEVELOPMENT @@ -592,7 +595,7 @@ void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderR ++DSIndex; } - if (pSignature->GetDynamicBufferCount() > 0) + if (pSignature->GetDynamicOffsetCount() > 0) BindInfo.PendingDynamicDescriptors[Index] = true; VERIFY_EXPR(DSIndex == DSCount); diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp index 5f2a525c..c4cefb88 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp @@ -40,7 +40,6 @@ namespace Diligent PipelineLayoutVk::PipelineLayoutVk() { m_FirstDescrSetIndex.fill(std::numeric_limits<FirstDescrSetIndexArrayType::value_type>::max()); - m_FirstDynBuffIndex.fill(std::numeric_limits<FirstDynBuffIndexArrayType::value_type>::max()); } PipelineLayoutVk::~PipelineLayoutVk() @@ -58,7 +57,7 @@ void PipelineLayoutVk::Release(RenderDeviceVkImpl* pDeviceVk, Uint64 CommandQueu void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount) { - VERIFY(m_DynamicOffsetCount == 0 && m_SignatureCount == 0 && m_DescrSetCount == 0, + VERIFY(m_SignatureCount == 0 && m_DescrSetCount == 0, "This pipeline layout is already initialized"); for (Uint32 i = 0; i < SignatureCount; ++i) @@ -66,7 +65,7 @@ void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSi auto* pSignature = ValidatedCast<PipelineResourceSignatureVkImpl>(ppSignatures[i]); VERIFY(pSignature != nullptr, "Pipeline resource signature at index ", i, " is null. This error should've been caught by ValidatePipelineResourceSignatures."); - const Uint32 Index = pSignature->GetDesc().BindingIndex; + const Uint8 Index = pSignature->GetDesc().BindingIndex; VERIFY(Index < m_Signatures.size(), "Pipeline resource signature specifies binding index ", Uint32{Index}, " that exceeds the limit (", m_Signatures.size() - 1, @@ -77,7 +76,7 @@ void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSi " conflicts with another resource signature '", m_Signatures[Index]->GetDesc().Name, "' that uses the same index. This error should've been caught by ValidatePipelineResourceSignatureDesc."); - m_SignatureCount = std::max(m_SignatureCount, static_cast<Uint16>(Index + 1)); + m_SignatureCount = std::max<Uint8>(m_SignatureCount, Index + 1); m_Signatures[Index] = pSignature; } @@ -89,11 +88,9 @@ void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSi m_Signatures[i] = pEmptySign; } - std::array<VkDescriptorSetLayout, MAX_RESOURCE_SIGNATURES * 2> DescSetLayouts; - - Uint32 DescSetLayoutCount = 0; - Uint32 DynamicOffsetCount = 0; + std::array<VkDescriptorSetLayout, MAX_RESOURCE_SIGNATURES * MAX_DESCR_SET_PER_SIGNATURE> DescSetLayouts; + Uint32 DescSetLayoutCount = 0; Uint32 DynamicUniformBufferCount = 0; Uint32 DynamicStorageBufferCount = 0; @@ -106,46 +103,17 @@ void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSi "Descriptor set layout count (", DescSetLayoutCount, ") exceeds the maximum representable value"); m_FirstDescrSetIndex[i] = static_cast<FirstDescrSetIndexArrayType::value_type>(DescSetLayoutCount); - VERIFY(DescSetLayoutCount <= std::numeric_limits<FirstDynBuffIndexArrayType::value_type>::max(), - "Dynamic buffer count (", DynamicOffsetCount, ") exceeds the maximum representable value"); - m_FirstDynBuffIndex[i] = static_cast<FirstDynBuffIndexArrayType::value_type>(DynamicOffsetCount); - auto StaticDSLayout = pSignature->GetStaticVkDescriptorSetLayout(); auto DynamicDSLayout = pSignature->GetDynamicVkDescriptorSetLayout(); if (StaticDSLayout != VK_NULL_HANDLE) DescSetLayouts[DescSetLayoutCount++] = StaticDSLayout; if (DynamicDSLayout != VK_NULL_HANDLE) DescSetLayouts[DescSetLayoutCount++] = DynamicDSLayout; - DynamicOffsetCount += pSignature->GetDynamicBufferCount(); - - for (Uint32 r = 0, ResCount = pSignature->GetTotalResourceCount(); r < ResCount; ++r) - { - const auto& Attr = pSignature->GetAttribs(r); - - if (Attr.Type == DescriptorType::UniformBufferDynamic) - { - ++DynamicUniformBufferCount; - } - else if (Attr.Type == DescriptorType::StorageBufferDynamic || - Attr.Type == DescriptorType::StorageBufferDynamic_ReadOnly) - { - ++DynamicStorageBufferCount; - } - } + DynamicUniformBufferCount += pSignature->GetDynamicUniformBufferCount(); + DynamicStorageBufferCount += pSignature->GetDynamicStorageBufferCount(); } VERIFY_EXPR(DescSetLayoutCount <= MAX_RESOURCE_SIGNATURES * 2); - VkPipelineLayoutCreateInfo PipelineLayoutCI = {}; - - PipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - PipelineLayoutCI.pNext = nullptr; - PipelineLayoutCI.flags = 0; // reserved for future use - PipelineLayoutCI.setLayoutCount = DescSetLayoutCount; - PipelineLayoutCI.pSetLayouts = DescSetLayoutCount ? DescSetLayouts.data() : nullptr; - PipelineLayoutCI.pushConstantRangeCount = 0; - PipelineLayoutCI.pPushConstantRanges = nullptr; - m_VkPipelineLayout = pDeviceVk->GetLogicalDevice().CreatePipelineLayout(PipelineLayoutCI); - const auto& Limits = pDeviceVk->GetPhysicalDevice().GetProperties().limits; if (DescSetLayoutCount > Limits.maxBoundDescriptorSets) { @@ -167,8 +135,19 @@ void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSi VERIFY(m_DescrSetCount <= std::numeric_limits<decltype(m_DescrSetCount)>::max(), "Descriptor set count (", DescSetLayoutCount, ") exceeds the maximum representable value"); - m_DescrSetCount = static_cast<decltype(m_DescrSetCount)>(DescSetLayoutCount); - m_DynamicOffsetCount = DynamicOffsetCount; + + VkPipelineLayoutCreateInfo PipelineLayoutCI = {}; + + PipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + PipelineLayoutCI.pNext = nullptr; + PipelineLayoutCI.flags = 0; // reserved for future use + PipelineLayoutCI.setLayoutCount = DescSetLayoutCount; + PipelineLayoutCI.pSetLayouts = DescSetLayoutCount ? DescSetLayouts.data() : nullptr; + PipelineLayoutCI.pushConstantRangeCount = 0; + PipelineLayoutCI.pPushConstantRanges = nullptr; + m_VkPipelineLayout = pDeviceVk->GetLogicalDevice().CreatePipelineLayout(PipelineLayoutCI); + + m_DescrSetCount = static_cast<Uint8>(DescSetLayoutCount); } size_t PipelineLayoutVk::GetHash() const @@ -185,7 +164,6 @@ size_t PipelineLayoutVk::GetHash() const bool PipelineLayoutVk::GetResourceInfo(const char* Name, SHADER_TYPE Stage, ResourceInfo& Info) const { - // AZ TODO: optimize for (Uint32 i = 0, DSCount = GetSignatureCount(); i < DSCount; ++i) { auto* pSignature = GetSignature(i); @@ -200,7 +178,7 @@ bool PipelineLayoutVk::GetResourceInfo(const char* Name, SHADER_TYPE Stage, Reso { Info.Type = Res.ResourceType; Info.BindingIndex = static_cast<Uint16>(Attr.BindingIndex); - Info.DescrSetIndex = m_FirstDescrSetIndex[i] + Attr.DescrSet; + Info.DescrSetIndex = m_FirstDescrSetIndex[i] + static_cast<Uint16>(Attr.DescrSet); return true; } } diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp index 2bcafcf1..60631b9f 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp @@ -40,9 +40,51 @@ namespace Diligent { namespace { + +bool operator==(const PipelineResourceDesc& lhs, const PipelineResourceDesc& rhs) +{ + // clang-format off + return lhs.ShaderStages == rhs.ShaderStages && + lhs.ArraySize == rhs.ArraySize && + lhs.ResourceType == rhs.ResourceType && + lhs.VarType == rhs.VarType && + lhs.Flags == lhs.Flags; + // clang-format on +} + +bool operator==(const PipelineResourceSignatureVkImpl::ResourceAttribs& lhs, + const PipelineResourceSignatureVkImpl::ResourceAttribs& rhs) +{ + // clang-format off + return lhs.DescrType == rhs.DescrType && + lhs.BindingIndex == rhs.BindingIndex && + lhs.DescrSet == rhs.DescrSet && + //lhs.CacheOffset== rhs.CacheOffset && + //lhs.SamplerInd == rhs.SamplerInd && + lhs.ImtblSamplerAssigned == rhs.ImtblSamplerAssigned; + // clang-format on +} + +__forceinline Uint32 ResourceToCacheOffsetIndex(const PipelineResourceDesc& Res) +{ + const Uint32 SetIdx = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0) * 3; + const bool WithDynamicOffset = !(Res.Flags & PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS); + const bool UseTexelBuffer = (Res.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER); + + if (WithDynamicOffset && !UseTexelBuffer) + { + if (Res.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER) + return SetIdx; + + if (Res.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV || Res.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV) + return SetIdx + 1; + } + return SetIdx + 2; +} + VkDescriptorType GetVkDescriptorType(DescriptorType Type) { - static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type"); + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); switch (Type) { // clang-format off @@ -50,7 +92,6 @@ VkDescriptorType GetVkDescriptorType(DescriptorType Type) case DescriptorType::CombinedImageSampler: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; case DescriptorType::SeparateImage: return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; case DescriptorType::StorageImage: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - case DescriptorType::StorageImage_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; case DescriptorType::UniformTexelBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; case DescriptorType::StorageTexelBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; case DescriptorType::StorageTexelBuffer_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; @@ -120,7 +161,7 @@ DescriptorType GetDescriptorType(const PipelineResourceDesc& Res) BUFFER_VIEW_TYPE DescriptorTypeToBufferView(DescriptorType Type) { - static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type"); + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); switch (Type) { // clang-format off @@ -140,14 +181,13 @@ BUFFER_VIEW_TYPE DescriptorTypeToBufferView(DescriptorType Type) TEXTURE_VIEW_TYPE DescriptorTypeToTextureView(DescriptorType Type) { - static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type"); + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); switch (Type) { // clang-format off case DescriptorType::StorageImage: return TEXTURE_VIEW_UNORDERED_ACCESS; case DescriptorType::CombinedImageSampler: case DescriptorType::SeparateImage: - case DescriptorType::StorageImage_ReadOnly: case DescriptorType::InputAttachment: return TEXTURE_VIEW_SHADER_RESOURCE; // clang-format on default: @@ -193,7 +233,7 @@ Int32 FindImmutableSampler(const PipelineResourceDesc& Res, RESOURCE_STATE DescriptorTypeToResourceState(DescriptorType Type) { - static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type"); + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); switch (Type) { // clang-format off @@ -201,7 +241,6 @@ RESOURCE_STATE DescriptorTypeToResourceState(DescriptorType Type) case DescriptorType::CombinedImageSampler: return RESOURCE_STATE_SHADER_RESOURCE; case DescriptorType::SeparateImage: return RESOURCE_STATE_SHADER_RESOURCE; case DescriptorType::StorageImage: return RESOURCE_STATE_UNORDERED_ACCESS; - case DescriptorType::StorageImage_ReadOnly: return RESOURCE_STATE_SHADER_RESOURCE; case DescriptorType::UniformTexelBuffer: return RESOURCE_STATE_SHADER_RESOURCE; case DescriptorType::StorageTexelBuffer: return RESOURCE_STATE_UNORDERED_ACCESS; case DescriptorType::StorageTexelBuffer_ReadOnly: return RESOURCE_STATE_SHADER_RESOURCE; @@ -221,16 +260,14 @@ RESOURCE_STATE DescriptorTypeToResourceState(DescriptorType Type) } -#define LOG_PRS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a pipeline resource signature '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__) +#define LOG_PRS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a pipeline resource signature '", m_Desc.Name, "' is invalid: ", ##__VA_ARGS__) PipelineResourceSignatureVkImpl::PipelineResourceSignatureVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDevice, const PipelineResourceSignatureDesc& Desc, bool bIsDeviceInternal) : TPipelineResourceSignatureBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}, - m_SRBMemAllocator{GetRawAllocator()}, - m_DynamicBufferCount{0}, - m_NumShaders{0} + m_SRBMemAllocator{GetRawAllocator()} { try { @@ -242,14 +279,22 @@ PipelineResourceSignatureVkImpl::PipelineResourceSignatureVkImpl(IReferenceCount ReserveSpaceForDescription(MemPool, Desc); - Int8 StaticVarStageCount = 0; - Uint32 StaticVarCount = 0; - Uint8 DSMapping[2] = {}; - ReserveSpaceForStaticVarsMgrs(Desc, MemPool, StaticVarStageCount, StaticVarCount, DSMapping); + Int8 StaticVarStageCount = 0; + Uint32 StaticVarCount = 0; + Uint8 DSMapping[MAX_DESCR_SET_PER_SIGNATURE] = {}; + CacheOffsetsType CacheSizes = {}; + BindingCountType BindingCount = {}; + ReserveSpaceForStaticVarsMgrs(Desc, StaticVarStageCount, StaticVarCount, CacheSizes, BindingCount, DSMapping); + + if (StaticVarStageCount > 0) + { + MemPool.AddSpace<ShaderResourceCacheVk>(1); + MemPool.AddSpace<ShaderVariableManagerVk>(StaticVarStageCount); + } MemPool.Reserve(); - m_pResourceAttribs = MemPool.ConstructArray<ResourceAttribs>(std::max(1u, m_Desc.NumResources)); + m_pResourceAttribs = MemPool.Allocate<ResourceAttribs>(std::max(1u, m_Desc.NumResources)); m_ImmutableSamplers = MemPool.ConstructArray<ImmutableSamplerPtrType>(m_Desc.NumImmutableSamplers); // The memory is now owned by PipelineResourceSignatureVkImpl and will be freed by Destruct(). @@ -261,11 +306,16 @@ PipelineResourceSignatureVkImpl::PipelineResourceSignatureVkImpl(IReferenceCount if (StaticVarStageCount > 0) { - m_pResourceCache = MemPool.Construct<ShaderResourceCacheVk>(ShaderResourceCacheVk::StaticShaderResources); + m_pResourceCache = MemPool.Construct<ShaderResourceCacheVk>(CacheContentType::Signature); m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerVk>(StaticVarStageCount); m_pResourceCache->InitializeSets(GetRawAllocator(), 1, &StaticVarCount); + } + CreateLayout(CacheSizes, BindingCount, DSMapping); + + if (StaticVarStageCount > 0) + { const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; for (Uint32 i = 0; i < m_StaticVarIndex.size(); ++i) @@ -281,7 +331,7 @@ PipelineResourceSignatureVkImpl::PipelineResourceSignatureVkImpl(IReferenceCount } } - CreateLayout(StaticVarCount, DSMapping); + m_Hash = CalculateHash(); } catch (...) { @@ -291,20 +341,22 @@ PipelineResourceSignatureVkImpl::PipelineResourceSignatureVkImpl(IReferenceCount } void PipelineResourceSignatureVkImpl::ReserveSpaceForStaticVarsMgrs(const PipelineResourceSignatureDesc& Desc, - FixedLinearAllocator& MemPool, Int8& StaticVarStageCount, Uint32& StaticVarCount, - Uint8 DSMapping[2]) + CacheOffsetsType& CacheSizes, + BindingCountType& BindingCount, + Uint8 DSMapping[MAX_DESCR_SET_PER_SIGNATURE]) { // get active shader stages SHADER_TYPE Stages = SHADER_TYPE_UNKNOWN; SHADER_TYPE StaticResStages = SHADER_TYPE_UNKNOWN; - bool VarExist[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES] = {}; - for (Uint32 i = 0; i < Desc.NumResources; ++i) { - const auto& Res = Desc.Resources[i]; + const auto& Res = Desc.Resources[i]; + const Uint32 SetIdx = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0); + const Uint32 COIdx = ResourceToCacheOffsetIndex(Res); + Stages |= Res.ShaderStages; if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) @@ -313,25 +365,20 @@ void PipelineResourceSignatureVkImpl::ReserveSpaceForStaticVarsMgrs(const Pipeli StaticVarCount += Res.ArraySize; } - VarExist[Res.VarType] = true; + ++BindingCount[COIdx]; + CacheSizes[COIdx] += Res.ArraySize; } // initialize descriptor set mapping table { - Uint8 Idx = 0; - if (VarExist[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] || VarExist[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE]) - DSMapping[0] = Idx++; - else - DSMapping[0] = 0xFF; - - if (VarExist[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC]) - DSMapping[1] = Idx; - else - DSMapping[1] = 0xFF; + Uint8 Idx = 0; + DSMapping[0] = (BindingCount[0] + BindingCount[1] + BindingCount[2] ? Idx++ : 0xFF); + DSMapping[1] = (BindingCount[3] + BindingCount[4] + BindingCount[5] ? Idx++ : 0xFF); + VERIFY_EXPR(Idx <= MAX_DESCR_SET_PER_SIGNATURE); } m_ShaderStages = Stages; - m_NumShaders = PlatformMisc::CountOneBits(static_cast<Uint32>(Stages)); + m_NumShaders = static_cast<Uint8>(PlatformMisc::CountOneBits(static_cast<Uint32>(Stages))); if (Stages == SHADER_TYPE_COMPUTE) { @@ -362,39 +409,54 @@ void PipelineResourceSignatureVkImpl::ReserveSpaceForStaticVarsMgrs(const Pipeli const auto ShaderTypeInd = GetShaderTypePipelineIndex(StageBit, m_PipelineType); m_StaticVarIndex[ShaderTypeInd] = StaticVarStageCount; } - - if (StaticVarStageCount > 0) - { - MemPool.AddSpace<ShaderResourceCacheVk>(1); - MemPool.AddSpace<ShaderVariableManagerVk>(StaticVarStageCount); - } } #undef LOG_PRS_ERROR_AND_THROW -void PipelineResourceSignatureVkImpl::CreateLayout(Uint32 StaticVarCount, const Uint8 DSMapping[2]) +void PipelineResourceSignatureVkImpl::CreateLayout(const CacheOffsetsType& CacheSizes, + const BindingCountType& BindingCount, + const Uint8 DSMapping[MAX_DESCR_SET_PER_SIGNATURE]) { - std::vector<VkDescriptorSetLayoutBinding> LayoutBindings[2]; + std::vector<VkDescriptorSetLayoutBinding> LayoutBindings[MAX_DESCR_SET_PER_SIGNATURE]; DynamicLinearAllocator TempAllocator{GetRawAllocator()}; - Uint32 CacheOffsets[Uint32{SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES}] = {0, StaticVarCount, 0}; + // clang-format off + CacheOffsetsType CacheOffsets = {0, CacheSizes[0], CacheSizes[0] + CacheSizes[1], // static/mutable set + 0, CacheSizes[3], CacheSizes[3] + CacheSizes[4]}; // dynamic set + BindingCountType BindingIndices = {0, BindingCount[0], BindingCount[0] + BindingCount[1], // static/mutable set + 0, BindingCount[3], BindingCount[3] + BindingCount[4]}; // dynamic set + Uint32 StaticCacheOffset = 0; + // clang-format on for (Uint32 i = 0; i < m_Desc.NumResources; ++i) { const auto& Res = m_Desc.Resources[i]; + const auto DescrType = GetDescriptorType(Res); auto& Attribs = m_pResourceAttribs[i]; - auto& CacheOffset = CacheOffsets[Uint32{Res.VarType}]; const Uint32 SetIdx = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0); + const Uint32 COIdx = ResourceToCacheOffsetIndex(Res); + auto& CacheOffset = CacheOffsets[COIdx]; // If all resources are dynamic then signature contains only one descriptor set layout with index 0, // so remap SetIdx to actual descriptor set index. - VERIFY_EXPR(DSMapping[SetIdx] <= 1); + VERIFY_EXPR(DSMapping[SetIdx] < MAX_DESCR_SET_PER_SIGNATURE); - Attribs.DescrSet = DSMapping[SetIdx]; - Attribs.BindingIndex = static_cast<Uint16>(LayoutBindings[SetIdx].size()); - Attribs.CacheOffset = CacheOffset; - Attribs.Type = GetDescriptorType(Res); + Attribs.CacheOffsets[static_cast<Uint32>(CacheContentType::Signature)] = ~0u; + Attribs.CacheOffsets[static_cast<Uint32>(CacheContentType::SRB)] = CacheOffset; + + Attribs.DescrType = static_cast<Uint32>(DescrType); + Attribs.DescrSet = DSMapping[SetIdx]; + Attribs.BindingIndex = BindingIndices[COIdx]; + Attribs.SamplerInd = InvalidSamplerInd; + Attribs.ImtblSamplerAssigned = false; + + // verify that data is not missed during bit packing + VERIFY_EXPR(Attribs.CacheOffsets[static_cast<Uint32>(CacheContentType::SRB)] == CacheOffset); + VERIFY_EXPR(Attribs.DescrType == static_cast<Uint32>(DescrType)); + VERIFY_EXPR(Attribs.DescrSet == DSMapping[SetIdx]); + VERIFY_EXPR(Attribs.BindingIndex == BindingIndices[COIdx]); CacheOffset += Res.ArraySize; + ++BindingIndices[COIdx]; LayoutBindings[SetIdx].emplace_back(); auto& LayoutBinding = LayoutBindings[SetIdx].back(); @@ -403,18 +465,18 @@ void PipelineResourceSignatureVkImpl::CreateLayout(Uint32 StaticVarCount, const LayoutBinding.descriptorCount = Res.ArraySize; LayoutBinding.stageFlags = ShaderTypesToVkShaderStageFlags(Res.ShaderStages); LayoutBinding.pImmutableSamplers = nullptr; - LayoutBinding.descriptorType = GetVkDescriptorType(Attribs.Type); + LayoutBinding.descriptorType = GetVkDescriptorType(Attribs.Type()); - if (Attribs.Type == DescriptorType::SeparateImage) + if (Attribs.Type() == DescriptorType::SeparateImage) { Attribs.SamplerInd = FindAssignedSampler(Res); } - if (Attribs.Type == DescriptorType::CombinedImageSampler || - Attribs.Type == DescriptorType::Sampler) + if (Attribs.Type() == DescriptorType::CombinedImageSampler || + Attribs.Type() == DescriptorType::Sampler) { // Only search for the immutable sampler for combined image samplers and separate samplers - Int32 SrcImmutableSamplerInd = FindImmutableSampler(Res, Attribs.Type, m_Desc, GetCombinedSamplerSuffix()); + Int32 SrcImmutableSamplerInd = FindImmutableSampler(Res, Attribs.Type(), m_Desc, GetCombinedSamplerSuffix()); if (SrcImmutableSamplerInd >= 0) { auto& ImmutableSampler = m_ImmutableSamplers[SrcImmutableSamplerInd]; @@ -422,27 +484,37 @@ void PipelineResourceSignatureVkImpl::CreateLayout(Uint32 StaticVarCount, const if (!ImmutableSampler) GetDevice()->CreateSampler(ImmutableSamplerDesc, &ImmutableSampler); - const VkSampler VkImmutableSampler = ImmutableSampler.RawPtr<SamplerVkImpl>()->GetVkSampler(); - VkSampler* SamplerArray = TempAllocator.Allocate<VkSampler>(Res.ArraySize); - for (Uint32 a = 0; a < Res.ArraySize; ++a) - SamplerArray[a] = VkImmutableSampler; - - LayoutBinding.pImmutableSamplers = SamplerArray; - Attribs.ImmutableSamplerAssigned = true; + LayoutBinding.pImmutableSamplers = TempAllocator.ConstructArray<VkSampler>(Res.ArraySize, ImmutableSampler.RawPtr<SamplerVkImpl>()->GetVkSampler()); + Attribs.ImtblSamplerAssigned = true; } } - if (Attribs.Type == DescriptorType::UniformBufferDynamic || - Attribs.Type == DescriptorType::StorageBufferDynamic || - Attribs.Type == DescriptorType::StorageBufferDynamic_ReadOnly) + if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) { - m_DynamicBufferCount += Res.ArraySize; + Attribs.CacheOffsets[static_cast<Uint32>(CacheContentType::Signature)] = StaticCacheOffset; + m_pResourceCache->InitializeResources(Attribs.DescrSet, StaticCacheOffset, Res.ArraySize, Attribs.Type()); + StaticCacheOffset += Res.ArraySize; } - - if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) - m_pResourceCache->InitializeResources(Attribs.DescrSet, Attribs.CacheOffset, Res.ArraySize, Attribs.Type); } - VERIFY_EXPR(CacheOffsets[0] == StaticVarCount); + + m_DynamicUniformBufferCount = static_cast<Uint16>(CacheSizes[0] + CacheSizes[3]); + m_DynamicStorageBufferCount = static_cast<Uint16>(CacheSizes[1] + CacheSizes[4]); + + VERIFY_EXPR(m_pResourceCache == nullptr || m_pResourceCache->GetDescriptorSet(0).GetSize() == StaticCacheOffset); + VERIFY_EXPR(m_DynamicUniformBufferCount == CacheSizes[0] + CacheSizes[3]); + VERIFY_EXPR(m_DynamicStorageBufferCount == CacheSizes[1] + CacheSizes[4]); + VERIFY_EXPR(CacheOffsets[0] == CacheSizes[0]); + VERIFY_EXPR(CacheOffsets[1] == CacheSizes[0] + CacheSizes[1]); + VERIFY_EXPR(CacheOffsets[2] == CacheSizes[0] + CacheSizes[1] + CacheSizes[2]); + VERIFY_EXPR(CacheOffsets[3] == CacheSizes[3]); + VERIFY_EXPR(CacheOffsets[4] == CacheSizes[3] + CacheSizes[4]); + VERIFY_EXPR(CacheOffsets[5] == CacheSizes[3] + CacheSizes[4] + CacheSizes[5]); + VERIFY_EXPR(BindingIndices[0] == BindingCount[0]); + VERIFY_EXPR(BindingIndices[1] == BindingCount[0] + BindingCount[1]); + VERIFY_EXPR(BindingIndices[2] == BindingCount[0] + BindingCount[1] + BindingCount[2]); + VERIFY_EXPR(BindingIndices[3] == BindingCount[3]); + VERIFY_EXPR(BindingIndices[4] == BindingCount[3] + BindingCount[4]); + VERIFY_EXPR(BindingIndices[5] == BindingCount[3] + BindingCount[4] + BindingCount[5]); if (m_Desc.SRBAllocationGranularity > 1) { @@ -455,8 +527,9 @@ void PipelineResourceSignatureVkImpl::CreateLayout(Uint32 StaticVarCount, const ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(*this, AllowedVarTypes, _countof(AllowedVarTypes), GetShaderStageType(s), UnusedNumVars); } - Uint32 DescriptorSetSizes[2] = {CacheOffsets[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE], CacheOffsets[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC]}; + Uint32 DescriptorSetSizes[2] = {CacheSizes[0] + CacheSizes[1] + CacheSizes[2], CacheSizes[3] + CacheSizes[4] + CacheSizes[5]}; const Uint32 NumSets = !!DescriptorSetSizes[0] + !!DescriptorSetSizes[1]; + static_assert(_countof(DescriptorSetSizes) == MAX_DESCR_SET_PER_SIGNATURE, "MAX_DESCR_SET_PER_SIGNATURE was changed, update code above"); if (DescriptorSetSizes[0] == 0) DescriptorSetSizes[0] = DescriptorSetSizes[1]; @@ -491,12 +564,14 @@ Uint32 PipelineResourceSignatureVkImpl::FindAssignedSampler(const PipelineResour Uint32 SamplerInd = InvalidSamplerInd; if (IsUsingCombinedSamplers()) { - for (Uint32 i = 0; i < m_Desc.NumResources; ++i) + const auto IdxRange = GetResourceIndexRange(SepImg.VarType); + + for (Uint32 i = IdxRange.first; i < IdxRange.second; ++i) { const auto& Res = m_Desc.Resources[i]; + VERIFY_EXPR(SepImg.VarType == Res.VarType); if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && - SepImg.VarType == Res.VarType && (SepImg.ShaderStages & Res.ShaderStages) && StreqSuff(Res.Name, SepImg.Name, GetCombinedSamplerSuffix())) { @@ -509,6 +584,26 @@ Uint32 PipelineResourceSignatureVkImpl::FindAssignedSampler(const PipelineResour return SamplerInd; } +size_t PipelineResourceSignatureVkImpl::CalculateHash() const +{ + size_t Hash = ComputeHash(m_Desc.NumResources, m_Desc.NumImmutableSamplers, m_Desc.BindingIndex); + + for (Uint32 i = 0; i < m_Desc.NumResources; ++i) + { + const auto& Res = m_Desc.Resources[i]; + const auto& Attr = m_pResourceAttribs[i]; + + HashCombine(Hash, Res.ArraySize, Res.ShaderStages, Res.VarType, Attr.Type(), Attr.BindingIndex, Attr.DescrSet, Attr.IsImmutableSamplerAssigned()); + } + + for (Uint32 i = 0; i < m_Desc.NumImmutableSamplers; ++i) + { + HashCombine(Hash, m_Desc.ImmutableSamplers[i].ShaderStages, m_Desc.ImmutableSamplers[i].Desc); + } + + return Hash; +} + PipelineResourceSignatureVkImpl::~PipelineResourceSignatureVkImpl() { Destruct(); @@ -582,17 +677,9 @@ bool PipelineResourceSignatureVkImpl::IsCompatibleWith(const PipelineResourceSig for (Uint32 r = 0; r < LCount; ++r) { - const auto& LAttr = GetAttribs(r); - const auto& RAttr = Other.GetAttribs(r); - - if (LAttr.Type != RAttr.Type || - LAttr.DescrSet != RAttr.DescrSet || - LAttr.BindingIndex != RAttr.BindingIndex || - LAttr.CacheOffset != RAttr.CacheOffset || - LAttr.ImmutableSamplerAssigned != RAttr.ImmutableSamplerAssigned) - { + if (!(GetAttribs(r) == Other.GetAttribs(r)) || + !(GetResource(r) == Other.GetResource(r))) return false; - } } const Uint32 LSampCount = GetDesc().NumImmutableSamplers; @@ -678,8 +765,9 @@ void PipelineResourceSignatureVkImpl::InitResourceCache(ShaderResourceCacheVk& R IMemoryAllocator& CacheMemAllocator, const char* DbgPipelineName) const { - std::array<Uint32, 2> VarCount = {}; - Uint32 NumSets = static_cast<Uint32>(VarCount.size()); + std::array<Uint32, MAX_DESCR_SET_PER_SIGNATURE> VarCount = {}; + + Uint32 NumSets = static_cast<Uint32>(VarCount.size()); for (Uint32 r = 0; r < m_Desc.NumResources; ++r) { @@ -732,12 +820,13 @@ Uint32 PipelineResourceSignatureVkImpl::GetNumDescriptorSets() const void PipelineResourceSignatureVkImpl::InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache) const { - auto TotalResources = GetTotalResourceCount(); + const auto TotalResources = GetTotalResourceCount(); + const auto CacheType = ResourceCache.GetContentType(); for (Uint32 r = 0; r < TotalResources; ++r) { const auto& Res = GetResource(r); const auto& Attr = GetAttribs(r); - ResourceCache.InitializeResources(Attr.DescrSet, Attr.CacheOffset, Res.ArraySize, Attr.Type); + ResourceCache.InitializeResources(Attr.DescrSet, Attr.CacheOffset(CacheType), Res.ArraySize, Attr.Type()); } } @@ -751,32 +840,33 @@ void PipelineResourceSignatureVkImpl::InitializeStaticSRBResources(ShaderResourc const auto& SrcResourceCache = *m_pResourceCache; const auto& SrcDescrSet = SrcResourceCache.GetDescriptorSet(GetStaticDescrSetIndex()); auto& DstDescrSet = DstResourceCache.GetDescriptorSet(GetStaticDescrSetIndex()); + const auto ResIdxRange = GetResourceIndexRange(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + const auto SrcCacheType = SrcResourceCache.GetContentType(); + const auto DstCacheType = DstResourceCache.GetContentType(); - // AZ TODO: optimize - for (Uint32 r = 0; r < GetTotalResourceCount(); ++r) + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) { const auto& Res = GetResource(r); const auto& Attr = GetAttribs(r); + VERIFY_EXPR(Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC); - if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && Attr.ImmutableSamplerAssigned) + if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && Attr.IsImmutableSamplerAssigned()) continue; // Skip immutable separate samplers - if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) + for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd) { - for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd) + auto SrcCacheOffset = Attr.CacheOffset(SrcCacheType) + ArrInd; + const auto& SrcCachedRes = SrcDescrSet.GetResource(SrcCacheOffset); + IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr<IDeviceObject>(); + if (!pObject) + LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetPrintName(Res, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'."); + + auto DstCacheOffset = Attr.CacheOffset(DstCacheType) + ArrInd; + IDeviceObject* pCachedResource = DstDescrSet.GetResource(DstCacheOffset).pObject; + if (pCachedResource != pObject) { - auto CacheOffset = Attr.CacheOffset + ArrInd; - const auto& SrcCachedRes = SrcDescrSet.GetResource(CacheOffset); - IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr<IDeviceObject>(); - if (!pObject) - LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetPrintName(Res, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'."); - - IDeviceObject* pCachedResource = DstDescrSet.GetResource(CacheOffset).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"); - BindResource(pObject, ArrInd, r, DstResourceCache); - } + VERIFY(pCachedResource == nullptr, "Static resource has already been initialized, and the resource to be assigned from the shader does not match previously assigned resource"); + BindResource(pObject, ArrInd, r, DstResourceCache); } } } @@ -801,6 +891,7 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc { VERIFY(HasDynamicDescrSet(), "This shader resource layout does not contain dynamic resources"); VERIFY_EXPR(vkDynamicDescriptorSet != VK_NULL_HANDLE); + VERIFY_EXPR(ResourceCache.GetContentType() == CacheContentType::SRB); #ifdef DILIGENT_DEBUG static constexpr size_t ImgUpdateBatchSize = 4; @@ -831,19 +922,18 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc const auto& SetResources = ResourceCache.GetDescriptorSet(GetDynamicDescrSetIndex()); const auto& LogicalDevice = GetDevice()->GetLogicalDevice(); + const auto ResIdxRange = GetResourceIndexRange(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC); + const auto CacheType = CacheContentType::SRB; - // AZ TODO: optimize - for (Uint32 ResNum = 0, ArrElem = 0, Count = GetTotalResourceCount(); ResNum < Count;) + for (Uint32 ResNum = ResIdxRange.first, ArrElem = 0; ResNum < ResIdxRange.second;) { - const auto& Res = GetResource(ResNum); - const auto& Attr = GetAttribs(ResNum); + const auto& Res = GetResource(ResNum); + const auto& Attr = GetAttribs(ResNum); + const auto CacheOffset = Attr.CacheOffset(CacheType); - if (Res.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - VERIFY_EXPR(ArrElem == 0); - ++ResNum; - continue; - } + // AZ TODO: put ArraySize to attributes to make it more cache friendly + + VERIFY_EXPR(Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC); WriteDescrSetIt->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; WriteDescrSetIt->pNext = nullptr; @@ -854,18 +944,18 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc WriteDescrSetIt->dstArrayElement = ArrElem; // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding. // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4) - WriteDescrSetIt->descriptorType = GetVkDescriptorType(Attr.Type); + WriteDescrSetIt->descriptorType = GetVkDescriptorType(Attr.Type()); // For every resource type, try to batch as many descriptor updates as we can - static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type"); - switch (Attr.Type) + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); + switch (Attr.Type()) { case DescriptorType::UniformBuffer: case DescriptorType::UniformBufferDynamic: WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt); while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end()) { - const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem); + const auto& CachedRes = SetResources.GetResource(CacheOffset + ArrElem); *DescrBuffIt = CachedRes.GetUniformBufferDescriptorWriteInfo(); ++DescrBuffIt; ++ArrElem; @@ -879,7 +969,7 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt); while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end()) { - const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem); + const auto& CachedRes = SetResources.GetResource(CacheOffset + ArrElem); *DescrBuffIt = CachedRes.GetStorageBufferDescriptorWriteInfo(); ++DescrBuffIt; ++ArrElem; @@ -892,7 +982,7 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc WriteDescrSetIt->pTexelBufferView = &(*BuffViewIt); while (ArrElem < Res.ArraySize && BuffViewIt != DescrBuffViewArr.end()) { - const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem); + const auto& CachedRes = SetResources.GetResource(CacheOffset + ArrElem); *BuffViewIt = CachedRes.GetBufferViewWriteInfo(); ++BuffViewIt; ++ArrElem; @@ -902,13 +992,12 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc case DescriptorType::CombinedImageSampler: case DescriptorType::SeparateImage: case DescriptorType::StorageImage: - case DescriptorType::StorageImage_ReadOnly: case DescriptorType::InputAttachment: WriteDescrSetIt->pImageInfo = &(*DescrImgIt); while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end()) { - const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem); - *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Attr.ImmutableSamplerAssigned); + const auto& CachedRes = SetResources.GetResource(CacheOffset + ArrElem); + *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Attr.IsImmutableSamplerAssigned()); ++DescrImgIt; ++ArrElem; } @@ -917,12 +1006,12 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc case DescriptorType::Sampler: // Immutable samplers are permanently bound into the set layout; later binding a sampler // into an immutable sampler slot in a descriptor set is not allowed (13.2.1) - if (!Attr.ImmutableSamplerAssigned) + if (!Attr.IsImmutableSamplerAssigned()) { WriteDescrSetIt->pImageInfo = &(*DescrImgIt); while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end()) { - const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem); + const auto& CachedRes = SetResources.GetResource(CacheOffset + ArrElem); *DescrImgIt = CachedRes.GetSamplerDescriptorWriteInfo(); ++DescrImgIt; ++ArrElem; @@ -939,7 +1028,7 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc WriteDescrSetIt->pNext = &(*AccelStructIt); while (ArrElem < Res.ArraySize && AccelStructIt != DescrAccelStructArr.end()) { - const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem); + const auto& CachedRes = SetResources.GetResource(CacheOffset + ArrElem); *AccelStructIt = CachedRes.GetAccelerationStructureWriteInfo(); ++AccelStructIt; ++ArrElem; @@ -1003,7 +1092,6 @@ namespace { struct BindResourceHelper { - // AZ TODO: cache DstRes.Type and ResDesc.VarType for better performace ??? ShaderResourceCacheVk::Resource& DstRes; const PipelineResourceDesc& ResDesc; const PipelineResourceSignatureVkImpl::ResourceAttribs& Attribs; @@ -1042,7 +1130,7 @@ private: bool UpdateCachedResource(RefCntAutoPtr<ObjectType>&& pObject, TPreUpdateObject PreUpdateObject) const; - bool IsImmutableSamplerAssigned() const { return Attribs.ImmutableSamplerAssigned; } + bool IsImmutableSamplerAssigned() const { return Attribs.IsImmutableSamplerAssigned(); } // Updates resource descriptor in the descriptor set inline void UpdateDescriptorHandle(const VkDescriptorImageInfo* pImageInfo, @@ -1054,7 +1142,7 @@ private: void BindResourceHelper::BindResource(IDeviceObject* pObj) const { #ifdef DILIGENT_DEBUG - if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources) + if (ResourceCache.GetContentType() == PipelineResourceSignatureVkImpl::CacheContentType::SRB) { if (ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE) { @@ -1062,7 +1150,7 @@ void BindResourceHelper::BindResource(IDeviceObject* pObj) const // Dynamic variables do not have vulkan descriptor set only until they are assigned one the first time } } - else if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources) + else if (ResourceCache.GetContentType() == PipelineResourceSignatureVkImpl::CacheContentType::Signature) { VERIFY(vkDescrSet == VK_NULL_HANDLE, "Static shader resource cache should not have vulkan descriptor set allocation"); } @@ -1074,7 +1162,7 @@ void BindResourceHelper::BindResource(IDeviceObject* pObj) const if (pObj) { - static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type"); + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); switch (DstRes.Type) { case DescriptorType::UniformBuffer: @@ -1096,7 +1184,6 @@ void BindResourceHelper::BindResource(IDeviceObject* pObj) const break; case DescriptorType::StorageImage: - case DescriptorType::StorageImage_ReadOnly: case DescriptorType::SeparateImage: case DescriptorType::CombinedImageSampler: CacheImage(pObj); @@ -1341,8 +1428,7 @@ void BindResourceHelper::CacheTexelBuffer(IDeviceObject* pBufferView, void BindResourceHelper::CacheImage(IDeviceObject* pTexView) const { // clang-format off - VERIFY(DstRes.Type == DescriptorType::StorageImage || - DstRes.Type == DescriptorType::StorageImage_ReadOnly || + VERIFY(DstRes.Type == DescriptorType::StorageImage || DstRes.Type == DescriptorType::SeparateImage || DstRes.Type == DescriptorType::CombinedImageSampler, "Storage image, separate image or sampled image resource is expected"); @@ -1388,7 +1474,7 @@ void BindResourceHelper::CacheImage(IDeviceObject* pTexView) const auto& SamplerAttribs = Signature.GetAttribs(Attribs.SamplerInd); VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER); - if (!SamplerAttribs.ImmutableSamplerAssigned) + if (!SamplerAttribs.IsImmutableSamplerAssigned()) { auto* pSampler = pTexViewVk->GetSampler(); if (pSampler != nullptr) @@ -1401,9 +1487,10 @@ void BindResourceHelper::CacheImage(IDeviceObject* pTexView) const "' must be one or the same as the array size (", ResDesc.ArraySize, ") of separate image variable '", ResDesc.Name, "' it is assigned to"); + const auto CacheType = ResourceCache.GetContentType(); auto& DstDescrSet = ResourceCache.GetDescriptorSet(SamplerAttribs.DescrSet); const auto SamplerArrInd = SamplerResDesc.ArraySize == 1 ? 0 : ArrayIndex; - auto& SampleDstRes = DstDescrSet.GetResource(SamplerAttribs.CacheOffset + SamplerArrInd); + auto& SampleDstRes = DstDescrSet.GetResource(SamplerAttribs.CacheOffset(CacheType) + SamplerArrInd); BindResourceHelper SeparateSampler{ SampleDstRes, @@ -1544,13 +1631,14 @@ void PipelineResourceSignatureVkImpl::BindResource(IDeviceObject* pObj, Uint32 ResIndex, ShaderResourceCacheVk& ResourceCache) const { - auto& ResDesc = GetResource(ResIndex); - auto& Attribs = GetAttribs(ResIndex); - auto& DstDescrSet = ResourceCache.GetDescriptorSet(Attribs.DescrSet); - auto& DstRes = DstDescrSet.GetResource(Attribs.CacheOffset + ArrayIndex); + auto& ResDesc = GetResource(ResIndex); + auto& Attribs = GetAttribs(ResIndex); + const auto CacheType = ResourceCache.GetContentType(); + auto& DstDescrSet = ResourceCache.GetDescriptorSet(Attribs.DescrSet); + auto& DstRes = DstDescrSet.GetResource(Attribs.CacheOffset(CacheType) + ArrayIndex); VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize); - VERIFY(DstRes.Type == Attribs.Type, "Inconsistent types"); + VERIFY(DstRes.Type == Attribs.Type(), "Inconsistent types"); BindResourceHelper Helper{ DstRes, diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index b92c94f4..4ee76d8c 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -775,7 +775,7 @@ void PipelineStateVkImpl::InitPipelineLayout(const PipelineStateCreateInfo& Crea if (pCombinedSamplerSuffix != nullptr) { if (strcmp(pCombinedSamplerSuffix, ShaderResources.GetCombinedSamplerSuffix()) != 0) - LOG_ERROR_AND_THROW("AZ TODO"); + LOG_ERROR_AND_THROW("CombinedSamplerSuffix is not compatible between shaders"); } else { @@ -811,18 +811,19 @@ void PipelineStateVkImpl::InitPipelineLayout(const PipelineStateCreateInfo& Crea if (Resources.size()) { PipelineResourceSignatureDesc ResSignDesc; - ResSignDesc.Resources = Resources.data(); - ResSignDesc.NumResources = static_cast<Uint32>(Resources.size()); - ResSignDesc.ImmutableSamplers = LayoutDesc.ImmutableSamplers; - ResSignDesc.NumImmutableSamplers = LayoutDesc.NumImmutableSamplers; - ResSignDesc.BindingIndex = 0; - ResSignDesc.SRBAllocationGranularity = CreateInfo.PSODesc.SRBAllocationGranularity; - ResSignDesc.CombinedSamplerSuffix = pCombinedSamplerSuffix; + ResSignDesc.Resources = Resources.data(); + ResSignDesc.NumResources = static_cast<Uint32>(Resources.size()); + ResSignDesc.ImmutableSamplers = LayoutDesc.ImmutableSamplers; + ResSignDesc.NumImmutableSamplers = LayoutDesc.NumImmutableSamplers; + ResSignDesc.BindingIndex = 0; + ResSignDesc.SRBAllocationGranularity = CreateInfo.PSODesc.SRBAllocationGranularity; + ResSignDesc.UseCombinedTextureSamplers = pCombinedSamplerSuffix != nullptr; + ResSignDesc.CombinedSamplerSuffix = pCombinedSamplerSuffix; GetDevice()->CreatePipelineResourceSignature(ResSignDesc, &TempSignature, true); if (TempSignature == nullptr) - LOG_ERROR_AND_THROW("AZ TODO"); + LOG_ERROR_AND_THROW("Failed to create resource signature for pipeline state"); Signatures[0] = TempSignature; SignatureCount = 1; diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp index a4932563..7e05e8bc 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp @@ -45,7 +45,7 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pPRS, IsPSOInternal }, - m_ShaderResourceCache{ShaderResourceCacheVk::DbgCacheContentType::SRBResources} + m_ShaderResourceCache{ShaderResourceCacheVk::CacheContentType::SRB} // clang-format on { try diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index 28adf43a..2e538b2c 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -255,7 +255,6 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) case DescriptorType::CombinedImageSampler: case DescriptorType::SeparateImage: case DescriptorType::StorageImage: - case DescriptorType::StorageImage_ReadOnly: { auto* pTextureViewVk = Res.pObject.RawPtr<TextureViewVkImpl>(); auto* pTextureVk = pTextureViewVk != nullptr ? ValidatedCast<TextureVkImpl>(pTextureViewVk->GetTexture()) : nullptr; @@ -446,7 +445,6 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteIn { // clang-format off VERIFY(Type == DescriptorType::StorageImage || - Type == DescriptorType::StorageImage_ReadOnly || Type == DescriptorType::SeparateImage || Type == DescriptorType::CombinedImageSampler, "Storage image, separate image or sampled image resource is expected"); diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp index 4eaf49bd..c700fb97 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp @@ -44,24 +44,29 @@ size_t ShaderVariableManagerVk::GetRequiredMemorySize(const PipelineResourceSign const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); const bool UsingSeparateSamplers = Layout.IsUsingSeparateSamplers(); - for (Uint32 r = 0, Count = Layout.GetTotalResourceCount(); r < Count; ++r) + 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)) { - const auto& Res = Layout.GetResource(r); - const auto& Attr = Layout.GetAttribs(r); - - if (!IsAllowedType(Res.VarType, AllowedTypeBits)) - continue; + if (IsAllowedType(VarType, AllowedTypeBits)) + { + const auto ResIdxRange = Layout.GetResourceIndexRange(VarType); + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) + { + const auto& Res = Layout.GetResource(r); + const auto& Attr = Layout.GetAttribs(r); + VERIFY_EXPR(Res.VarType == VarType); - if (!(Res.ShaderStages & ShaderStages)) - continue; + if (!(Res.ShaderStages & ShaderStages)) + continue; - // When using HLSL-style combined image samplers, we need to skip separate samplers. - // Also always skip immutable separate samplers. - if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && - (!UsingSeparateSamplers || Attr.ImmutableSamplerAssigned)) - continue; + // When using HLSL-style combined image samplers, we need to skip separate samplers. + // Also always skip immutable separate samplers. + if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && + (!UsingSeparateSamplers || Attr.IsImmutableSamplerAssigned())) + continue; - ++NumVariables; + ++NumVariables; + } + } } return NumVariables * sizeof(ShaderVariableVkImpl); @@ -93,24 +98,29 @@ void ShaderVariableManagerVk::Initialize(const PipelineResourceSignatureVkImpl& Uint32 VarInd = 0; const bool UsingSeparateSamplers = SrcLayout.IsUsingSeparateSamplers(); - for (Uint32 r = 0, Count = SrcLayout.GetTotalResourceCount(); r < Count; ++r) + 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)) { - const auto& Res = SrcLayout.GetResource(r); - const auto& Attr = SrcLayout.GetAttribs(r); - - if (!IsAllowedType(Res.VarType, AllowedTypeBits)) - continue; + if (IsAllowedType(VarType, AllowedTypeBits)) + { + const auto ResIdxRange = SrcLayout.GetResourceIndexRange(VarType); + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) + { + const auto& Res = SrcLayout.GetResource(r); + const auto& Attr = SrcLayout.GetAttribs(r); + VERIFY_EXPR(Res.VarType == VarType); - if (!(Res.ShaderStages & ShaderType)) - continue; + if (!(Res.ShaderStages & ShaderType)) + continue; - // Skip separate samplers when using combined HLSL-style image samplers. Also always skip immutable separate samplers. - if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && - (!UsingSeparateSamplers || Attr.ImmutableSamplerAssigned)) - continue; + // Skip separate samplers when using combined HLSL-style image samplers. Also always skip immutable separate samplers. + if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && + (!UsingSeparateSamplers || Attr.IsImmutableSamplerAssigned())) + continue; - ::new (m_pVariables + VarInd) ShaderVariableVkImpl(*this, r); - ++VarInd; + ::new (m_pVariables + VarInd) ShaderVariableVkImpl(*this, r); + ++VarInd; + } + } } VERIFY_EXPR(VarInd == m_NumVariables); @@ -201,7 +211,7 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping, const auto& Attr = Var.GetAttribs(); // There should be no immutable separate samplers - VERIFY(Attr.Type != DescriptorType::Sampler || !Attr.ImmutableSamplerAssigned, + VERIFY(Attr.Type() != DescriptorType::Sampler || !Attr.IsImmutableSamplerAssigned(), "There must be no shader resource variables for immutable separate samplers"); if ((Flags & (1u << Res.VarType)) == 0) @@ -251,10 +261,10 @@ void ShaderVariableVkImpl::SetArray(IDeviceObject* const* ppObjects, bool ShaderVariableVkImpl::IsBound(Uint32 ArrayIndex) const { - auto& ResourceCache = m_ParentManager.m_ResourceCache; - const auto& ResDesc = GetDesc(); - const auto& Attribs = GetAttribs(); - Uint32 CacheOffset = Attribs.CacheOffset; + auto& ResourceCache = m_ParentManager.m_ResourceCache; + const auto& ResDesc = GetDesc(); + const auto& Attribs = GetAttribs(); + const Uint32 CacheOffset = Attribs.CacheOffset(ResourceCache.GetContentType()); VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize); |
