diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2021-03-10 23:26:13 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2021-03-19 00:38:20 +0000 |
| commit | 3303d4d49a3f3c41154d05f0c78feb7e64a2c10d (patch) | |
| tree | 1c898135f730ffd295a52c3c849e8de7fa09c92a /Graphics/GraphicsEngineVulkan | |
| parent | D3D12 backend: moved resource binding logic to shader variable manger (diff) | |
| download | DiligentCore-3303d4d49a3f3c41154d05f0c78feb7e64a2c10d.tar.gz DiligentCore-3303d4d49a3f3c41154d05f0c78feb7e64a2c10d.zip | |
Vk backend: moved resource binding logic to variable manager and cache
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
8 files changed, 742 insertions, 691 deletions
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineResourceAttribsVk.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineResourceAttribsVk.hpp index 34a19796..2d026392 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineResourceAttribsVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineResourceAttribsVk.hpp @@ -162,4 +162,33 @@ public: } }; +inline VkDescriptorType DescriptorTypeToVkDescriptorType(DescriptorType 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::Sampler: return VK_DESCRIPTOR_TYPE_SAMPLER; + 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::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; + case DescriptorType::UniformBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + case DescriptorType::UniformBufferDynamic: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + case DescriptorType::StorageBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + case DescriptorType::StorageBuffer_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + case DescriptorType::StorageBufferDynamic: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + case DescriptorType::StorageBufferDynamic_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + case DescriptorType::InputAttachment: return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + case DescriptorType::AccelerationStructure: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; + // clang-format on + default: + UNEXPECTED("Unknown descriptor type"); + return VK_DESCRIPTOR_TYPE_MAX_ENUM; + } +} + + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp index 935367dd..5823f884 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp @@ -121,17 +121,6 @@ public: // Copies static resources from the static resource cache to the destination cache void CopyStaticResources(ShaderResourceCacheVk& ResourceCache) const; - // Binds object pObj to resource with index ResIndex in m_Desc.Resources and - // array index ArrayIndex. - void BindResource(IDeviceObject* pObj, - Uint32 ArrayIndex, - Uint32 ResIndex, - ShaderResourceCacheVk& ResourceCache) const; - - bool IsBound(Uint32 ArrayIndex, - Uint32 ResIndex, - const ShaderResourceCacheVk& ResourceCache) const; - // Commits dynamic resources from ResourceCache to vkDynamicDescriptorSet void CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache, VkDescriptorSet vkDynamicDescriptorSet) const; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp index aac66247..7cab3005 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp @@ -61,6 +61,7 @@ #include "BufferVkImpl.hpp" #include "ShaderResourceCacheCommon.hpp" #include "PipelineResourceAttribsVk.hpp" +#include "VulkanUtilities/VulkanLogicalDevice.hpp" namespace Diligent { @@ -90,33 +91,40 @@ public: static size_t GetRequiredMemorySize(Uint32 NumSets, const Uint32* SetSizes); void InitializeSets(IMemoryAllocator& MemAllocator, Uint32 NumSets, const Uint32* SetSizes); - void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type); + void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type, bool HasImmutableSampler); // sizeof(Resource) == 16 (x64, msvc, Release) struct Resource { - // clang-format off - explicit Resource(DescriptorType _Type) noexcept : - Type{_Type} - {} + explicit Resource(DescriptorType _Type, bool _HasImmutableSampler) noexcept : + Type{_Type}, + HasImmutableSampler{_HasImmutableSampler} + { + VERIFY(Type == DescriptorType::CombinedImageSampler || Type == DescriptorType::Sampler || !HasImmutableSampler, + "Immutable sampler can only be assigned to a combined image sampler or a separate sampler"); + } + // clang-format off Resource (const Resource&) = delete; Resource (Resource&&) = delete; Resource& operator = (const Resource&) = delete; Resource& operator = (Resource&&) = delete; /* 0 */ const DescriptorType Type; -/*1-7*/ // Unused +/* 1 */ const bool HasImmutableSampler; +/*2-7*/ // Unused /* 8 */ RefCntAutoPtr<IDeviceObject> pObject; - VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo () const; - VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo () const; - VkDescriptorImageInfo GetImageDescriptorWriteInfo (bool IsImmutableSampler) const; + VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo() const; + VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo() const; + VkDescriptorImageInfo GetImageDescriptorWriteInfo () const; VkBufferView GetBufferViewWriteInfo () const; VkDescriptorImageInfo GetSamplerDescriptorWriteInfo() const; VkDescriptorImageInfo GetInputAttachmentDescriptorWriteInfo() const; VkWriteDescriptorSetAccelerationStructureKHR GetAccelerationStructureWriteInfo() const; // clang-format on + + bool IsNull() const { return pObject == nullptr; } }; // sizeof(DescriptorSet) == 48 (x64, msvc, Release) @@ -135,55 +143,66 @@ public: DescriptorSet& operator = (DescriptorSet&&) = delete; // clang-format on - 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 + const Resource& GetResource(Uint32 CacheOffset) const { VERIFY(CacheOffset < m_NumResources, "Offset ", CacheOffset, " is out of range"); return m_pResources[CacheOffset]; } - inline Uint32 GetSize() const { return m_NumResources; } + Uint32 GetSize() const { return m_NumResources; } VkDescriptorSet GetVkDescriptorSet() const { return m_DescriptorSetAllocation.GetVkDescriptorSet(); } - void AssignDescriptorSetAllocation(DescriptorSetAllocation&& Allocation) - { - VERIFY(m_NumResources > 0, "Descriptor set is empty"); - m_DescriptorSetAllocation = std::move(Allocation); - } - // clang-format off /* 0 */ const Uint32 m_NumResources = 0; private: + friend ShaderResourceCacheVk; + Resource& GetResource(Uint32 CacheOffset) + { + VERIFY(CacheOffset < m_NumResources, "Offset ", CacheOffset, " is out of range"); + return m_pResources[CacheOffset]; + } + /* 8 */ Resource* const m_pResources = nullptr; /*16 */ DescriptorSetAllocation m_DescriptorSetAllocation; /*48 */ // End of structure // clang-format on }; - inline DescriptorSet& GetDescriptorSet(Uint32 Index) + const DescriptorSet& GetDescriptorSet(Uint32 Index) const { VERIFY_EXPR(Index < m_NumSets); - return reinterpret_cast<DescriptorSet*>(m_pMemory.get())[Index]; + return reinterpret_cast<const DescriptorSet*>(m_pMemory.get())[Index]; } - inline const DescriptorSet& GetDescriptorSet(Uint32 Index) const + + void AssignDescriptorSetAllocation(Uint32 SetIndex, DescriptorSetAllocation&& Allocation) { - VERIFY_EXPR(Index < m_NumSets); - return reinterpret_cast<const DescriptorSet*>(m_pMemory.get())[Index]; + auto& DescrSet = GetDescriptorSet(SetIndex); + VERIFY(DescrSet.GetSize() > 0, "Descriptor set is empty"); + VERIFY(!DescrSet.m_DescriptorSetAllocation, "Descriptor set alloction has already been initialized"); + DescrSet.m_DescriptorSetAllocation = std::move(Allocation); } - inline Uint32 GetNumDescriptorSets() const { return m_NumSets; } - inline Uint32 GetNumDynamicBuffers() const { return m_NumDynamicBuffers; } + // Sets the resource at the given desriptor set index and offset + const Resource& SetResource(const VulkanUtilities::VulkanLogicalDevice* pLogicalDevice, + Uint32 SetIndex, + Uint32 Offset, + Uint32 BindingIndex, + Uint32 ArrayIndex, + RefCntAutoPtr<IDeviceObject>&& pObject); - Uint16& GetDynamicBuffersCounter() { return m_NumDynamicBuffers; } + const Resource& ResetResource(Uint32 SetIndex, + Uint32 Offset) + { + return SetResource(nullptr, SetIndex, Offset, ~0u, ~0u, RefCntAutoPtr<IDeviceObject>{}); + } + + Uint32 GetNumDescriptorSets() const { return m_NumSets; } + Uint32 GetNumDynamicBuffers() const { return m_NumDynamicBuffers; } ResourceCacheContentType GetContentType() const { return static_cast<ResourceCacheContentType>(m_ContentType); } @@ -208,6 +227,12 @@ private: return reinterpret_cast<const Resource*>(reinterpret_cast<const DescriptorSet*>(m_pMemory.get()) + m_NumSets); } + DescriptorSet& GetDescriptorSet(Uint32 Index) + { + VERIFY_EXPR(Index < m_NumSets); + return reinterpret_cast<DescriptorSet*>(m_pMemory.get())[Index]; + } + std::unique_ptr<void, STDDeleter<void, IMemoryAllocator>> m_pMemory; Uint16 m_NumSets = 0; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVariableManagerVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderVariableManagerVk.hpp index b2980659..06db6075 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderVariableManagerVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderVariableManagerVk.hpp @@ -93,6 +93,14 @@ public: ShaderVariableVkImpl* GetVariable(const Char* Name) const; ShaderVariableVkImpl* GetVariable(Uint32 Index) const; + // Binds object pObj to resource with index ResIndex and array index ArrayIndex. + void BindResource(IDeviceObject* pObj, + Uint32 ArrayIndex, + Uint32 ResIndex); + + bool IsBound(Uint32 ArrayIndex, + Uint32 ResIndex) const; + void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) const; static size_t GetRequiredMemorySize(const PipelineResourceSignatureVkImpl& Signature, @@ -183,13 +191,20 @@ public: return m_ParentManager.GetVariableIndex(*this); } - // This method can't be implemented in the header because it depends on PipelineResourceSignatureVkImpl - virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final; + virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final + { + return m_ParentManager.IsBound(ArrayIndex, m_ResIndex); + } - const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResourceDesc(m_ResIndex); } + const PipelineResourceDesc& GetDesc() const + { + return m_ParentManager.GetResourceDesc(m_ResIndex); + } - // This method can't be implemented in the header because it depends on PipelineResourceSignatureVkImpl - void BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const; + void BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const + { + return m_ParentManager.BindResource(pObj, ArrayIndex, m_ResIndex); + } private: using ResourceAttribs = PipelineResourceAttribsVk; diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index d2885d5f..a9c0a7ad 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -584,15 +584,16 @@ void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderR if (pSignature->HasDescriptorSet(PipelineResourceSignatureVkImpl::DESCRIPTOR_SET_ID_STATIC_MUTABLE)) { VERIFY_EXPR(DSIndex == pSignature->GetDescriptorSetIndex<PipelineResourceSignatureVkImpl::DESCRIPTOR_SET_ID_STATIC_MUTABLE>()); - VERIFY_EXPR(ResourceCache.GetDescriptorSet(DSIndex).GetVkDescriptorSet() != VK_NULL_HANDLE); - ResInfo.vkSets[DSIndex] = ResourceCache.GetDescriptorSet(DSIndex).GetVkDescriptorSet(); + const auto& CahedDescrSet = const_cast<const ShaderResourceCacheVk&>(ResourceCache).GetDescriptorSet(DSIndex); + VERIFY_EXPR(CahedDescrSet.GetVkDescriptorSet() != VK_NULL_HANDLE); + ResInfo.vkSets[DSIndex] = CahedDescrSet.GetVkDescriptorSet(); ++DSIndex; } if (pSignature->HasDescriptorSet(PipelineResourceSignatureVkImpl::DESCRIPTOR_SET_ID_DYNAMIC)) { VERIFY_EXPR(DSIndex == pSignature->GetDescriptorSetIndex<PipelineResourceSignatureVkImpl::DESCRIPTOR_SET_ID_DYNAMIC>()); - VERIFY_EXPR(ResourceCache.GetDescriptorSet(DSIndex).GetVkDescriptorSet() == VK_NULL_HANDLE); + VERIFY_EXPR(const_cast<const ShaderResourceCacheVk&>(ResourceCache).GetDescriptorSet(DSIndex).GetVkDescriptorSet() == VK_NULL_HANDLE); const auto vkLayout = pSignature->GetVkDescriptorSetLayout(PipelineResourceSignatureVkImpl::DESCRIPTOR_SET_ID_DYNAMIC); diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp index 0d082479..e4fce2b8 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp @@ -32,7 +32,6 @@ #include "RenderDeviceVkImpl.hpp" #include "SamplerVkImpl.hpp" #include "TextureViewVkImpl.hpp" -#include "TopLevelASVkImpl.hpp" #include "VulkanTypeConversions.hpp" #include "DynamicLinearAllocator.hpp" @@ -44,34 +43,6 @@ namespace Diligent namespace { -inline VkDescriptorType GetVkDescriptorType(DescriptorType 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::Sampler: return VK_DESCRIPTOR_TYPE_SAMPLER; - 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::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; - case DescriptorType::UniformBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - case DescriptorType::UniformBufferDynamic: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - case DescriptorType::StorageBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - case DescriptorType::StorageBuffer_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - case DescriptorType::StorageBufferDynamic: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; - case DescriptorType::StorageBufferDynamic_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; - case DescriptorType::InputAttachment: return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; - case DescriptorType::AccelerationStructure: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; - // clang-format on - default: - UNEXPECTED("Unknown descriptor type"); - return VK_DESCRIPTOR_TYPE_MAX_ENUM; - } -} - DescriptorType GetDescriptorType(const PipelineResourceDesc& Res) { VERIFY((Res.Flags & ~GetValidPipelineResourceFlags(Res.ResourceType)) == 0, @@ -116,47 +87,6 @@ DescriptorType GetDescriptorType(const PipelineResourceDesc& Res) } } -inline BUFFER_VIEW_TYPE DescriptorTypeToBufferView(DescriptorType Type) -{ - static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); - switch (Type) - { - case DescriptorType::UniformTexelBuffer: - case DescriptorType::StorageTexelBuffer_ReadOnly: - case DescriptorType::StorageBuffer_ReadOnly: - case DescriptorType::StorageBufferDynamic_ReadOnly: - return BUFFER_VIEW_SHADER_RESOURCE; - - case DescriptorType::StorageTexelBuffer: - case DescriptorType::StorageBuffer: - case DescriptorType::StorageBufferDynamic: - return BUFFER_VIEW_UNORDERED_ACCESS; - - default: - UNEXPECTED("Unsupported descriptor type for buffer view"); - return BUFFER_VIEW_UNDEFINED; - } -} - -inline TEXTURE_VIEW_TYPE DescriptorTypeToTextureView(DescriptorType Type) -{ - static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); - switch (Type) - { - case DescriptorType::StorageImage: - return TEXTURE_VIEW_UNORDERED_ACCESS; - - case DescriptorType::CombinedImageSampler: - case DescriptorType::SeparateImage: - case DescriptorType::InputAttachment: - return TEXTURE_VIEW_SHADER_RESOURCE; - - default: - UNEXPECTED("Unsupported descriptor type for texture view"); - return TEXTURE_VIEW_UNDEFINED; - } -} - Uint32 FindImmutableSamplerVk(const PipelineResourceDesc& Res, DescriptorType DescType, const PipelineResourceSignatureDesc& Desc, @@ -397,12 +327,13 @@ void PipelineResourceSignatureVkImpl::CreateSetLayouts() vkSetLayoutBinding.descriptorCount = ResDesc.ArraySize; vkSetLayoutBinding.stageFlags = ShaderTypesToVkShaderStageFlags(ResDesc.ShaderStages); vkSetLayoutBinding.pImmutableSamplers = pVkImmutableSamplers; - vkSetLayoutBinding.descriptorType = GetVkDescriptorType(pAttribs->GetDescriptorType()); + vkSetLayoutBinding.descriptorType = DescriptorTypeToVkDescriptorType(pAttribs->GetDescriptorType()); if (ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) { VERIFY(pAttribs->DescrSet == 0, "Static resources must always be allocated in descriptor set 0"); - m_pStaticResCache->InitializeResources(pAttribs->DescrSet, StaticCacheOffset, ResDesc.ArraySize, pAttribs->GetDescriptorType()); + m_pStaticResCache->InitializeResources(pAttribs->DescrSet, StaticCacheOffset, ResDesc.ArraySize, + pAttribs->GetDescriptorType(), pAttribs->IsImmutableSamplerAssigned()); StaticCacheOffset += ResDesc.ArraySize; } } @@ -419,7 +350,7 @@ void PipelineResourceSignatureVkImpl::CreateSetLayouts() VERIFY_EXPR(m_DynamicUniformBufferCount == CacheGroupSizes[CACHE_GROUP_DYN_UB_STAT_VAR] + CacheGroupSizes[CACHE_GROUP_DYN_UB_DYN_VAR]); VERIFY_EXPR(m_DynamicStorageBufferCount == CacheGroupSizes[CACHE_GROUP_DYN_SB_STAT_VAR] + CacheGroupSizes[CACHE_GROUP_DYN_SB_DYN_VAR]); - VERIFY_EXPR(m_pStaticResCache == nullptr || m_pStaticResCache->GetDescriptorSet(0).GetSize() == StaticCacheOffset); + VERIFY_EXPR(m_pStaticResCache == nullptr || const_cast<const ShaderResourceCacheVk*>(m_pStaticResCache)->GetDescriptorSet(0).GetSize() == StaticCacheOffset); VERIFY_EXPR(CacheGroupOffsets[CACHE_GROUP_DYN_UB_STAT_VAR] == CacheGroupSizes[CACHE_GROUP_DYN_UB_STAT_VAR]); VERIFY_EXPR(CacheGroupOffsets[CACHE_GROUP_DYN_SB_STAT_VAR] == CacheGroupSizes[CACHE_GROUP_DYN_UB_STAT_VAR] + CacheGroupSizes[CACHE_GROUP_DYN_SB_STAT_VAR]); VERIFY_EXPR(CacheGroupOffsets[CACHE_GROUP_OTHER_STAT_VAR] == CacheGroupSizes[CACHE_GROUP_DYN_UB_STAT_VAR] + CacheGroupSizes[CACHE_GROUP_DYN_SB_STAT_VAR] + CacheGroupSizes[CACHE_GROUP_OTHER_STAT_VAR]); @@ -583,7 +514,8 @@ void PipelineResourceSignatureVkImpl::InitSRBResourceCache(ShaderResourceCacheVk { const auto& ResDesc = GetResourceDesc(r); const auto& Attr = GetResourceAttribs(r); - ResourceCache.InitializeResources(Attr.DescrSet, Attr.CacheOffset(CacheType), ResDesc.ArraySize, Attr.GetDescriptorType()); + ResourceCache.InitializeResources(Attr.DescrSet, Attr.CacheOffset(CacheType), ResDesc.ArraySize, + Attr.GetDescriptorType(), Attr.IsImmutableSamplerAssigned()); } #ifdef DILIGENT_DEBUG @@ -599,7 +531,7 @@ void PipelineResourceSignatureVkImpl::InitSRBResourceCache(ShaderResourceCacheVk DescrSetName = _DescrSetName.c_str(); #endif DescriptorSetAllocation SetAllocation = GetDevice()->AllocateDescriptorSet(~Uint64{0}, vkLayout, DescrSetName); - ResourceCache.GetDescriptorSet(GetDescriptorSetIndex<DESCRIPTOR_SET_ID_STATIC_MUTABLE>()).AssignDescriptorSetAllocation(std::move(SetAllocation)); + ResourceCache.AssignDescriptorSetAllocation(GetDescriptorSetIndex<DESCRIPTOR_SET_ID_STATIC_MUTABLE>(), std::move(SetAllocation)); } } @@ -613,7 +545,7 @@ void PipelineResourceSignatureVkImpl::CopyStaticResources(ShaderResourceCacheVk& const auto& SrcResourceCache = *m_pStaticResCache; const auto StaticSetIdx = GetDescriptorSetIndex<DESCRIPTOR_SET_ID_STATIC_MUTABLE>(); const auto& SrcDescrSet = SrcResourceCache.GetDescriptorSet(StaticSetIdx); - auto& DstDescrSet = DstResourceCache.GetDescriptorSet(StaticSetIdx); + const auto& DstDescrSet = const_cast<const ShaderResourceCacheVk&>(DstResourceCache).GetDescriptorSet(StaticSetIdx); const auto ResIdxRange = GetResourceIndexRange(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); const auto SrcCacheType = SrcResourceCache.GetContentType(); const auto DstCacheType = DstResourceCache.GetContentType(); @@ -635,15 +567,17 @@ void PipelineResourceSignatureVkImpl::CopyStaticResources(ShaderResourceCacheVk& if (!pObject) LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetShaderResourcePrintName(ResDesc, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'."); - const auto DstCacheOffset = Attr.CacheOffset(DstCacheType) + ArrInd; - auto& DstCachedRes = DstDescrSet.GetResource(DstCacheOffset); + const auto DstCacheOffset = Attr.CacheOffset(DstCacheType) + ArrInd; + const auto& DstCachedRes = DstDescrSet.GetResource(DstCacheOffset); VERIFY_EXPR(SrcCachedRes.Type == DstCachedRes.Type); - IDeviceObject* pCachedResource = DstCachedRes.pObject; + const IDeviceObject* pCachedResource = DstCachedRes.pObject; if (pCachedResource != pObject) { VERIFY(pCachedResource == nullptr, "Static resource has already been initialized, and the new resource does not match previously assigned resource"); - BindResource(pObject, ArrInd, r, DstResourceCache); + DstResourceCache.SetResource(&GetDevice()->GetLogicalDevice(), + StaticSetIdx, DstCacheOffset, Attr.BindingIndex, ArrInd, + RefCntAutoPtr<IDeviceObject>{SrcCachedRes.pObject}); } } } @@ -732,7 +666,7 @@ 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(DescrType); + WriteDescrSetIt->descriptorType = DescriptorTypeToVkDescriptorType(DescrType); // For every resource type, try to batch as many descriptor updates as we can static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); @@ -785,7 +719,7 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc while (ArrElem < ArraySize && DescrImgIt != DescrImgInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(CacheOffset + ArrElem); - *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Attr.IsImmutableSamplerAssigned()); + *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(); ++DescrImgIt; ++ArrElem; } @@ -863,554 +797,6 @@ void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourc LogicalDevice.UpdateDescriptorSets(DescrWriteCount, WriteDescrSetArr.data(), 0, nullptr); } -namespace -{ - -struct BindResourceHelper -{ - BindResourceHelper(const PipelineResourceSignatureVkImpl& Signature, - ShaderResourceCacheVk& ResourceCache, - Uint32 ResIndex, - Uint32 ArrayIndex); - - void operator()(IDeviceObject* pObj) const; - -private: - void CacheUniformBuffer(IDeviceObject* pBuffer) const; - - void CacheStorageBuffer(IDeviceObject* pBufferView) const; - - void CacheTexelBuffer(IDeviceObject* pBufferView) const; - - void CacheImage(IDeviceObject* pTexView) const; - - void CacheSeparateSampler(IDeviceObject* pSampler) const; - - void CacheInputAttachment(IDeviceObject* pTexView) const; - - void CacheAccelerationStructure(IDeviceObject* pTLAS) const; - - template <typename ObjectType, typename TPreUpdateObject> - bool UpdateCachedResource(RefCntAutoPtr<ObjectType>&& pObject, - TPreUpdateObject PreUpdateObject) const; - - // Updates resource descriptor in the descriptor set - inline void UpdateDescriptorHandle(const VkDescriptorImageInfo* pImageInfo, - const VkDescriptorBufferInfo* pBufferInfo, - const VkBufferView* pTexelBufferView, - const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const; - -private: - using ResourceAttribs = PipelineResourceSignatureVkImpl::ResourceAttribs; - using CachedSet = ShaderResourceCacheVk::DescriptorSet; - - const PipelineResourceSignatureVkImpl& m_Signature; - ShaderResourceCacheVk& m_ResourceCache; - const Uint32 m_ArrayIndex; - const ResourceCacheContentType m_CacheType; - const PipelineResourceDesc& m_ResDesc; - const ResourceAttribs& m_Attribs; - CachedSet& m_CachedSet; - ShaderResourceCacheVk::Resource& m_DstRes; - const VkDescriptorSet m_vkDescrSet; -}; - -BindResourceHelper::BindResourceHelper(const PipelineResourceSignatureVkImpl& Signature, - ShaderResourceCacheVk& ResourceCache, - Uint32 ResIndex, - Uint32 ArrayIndex) : - m_Signature{Signature}, - m_ResourceCache{ResourceCache}, - m_ArrayIndex{ArrayIndex}, - m_CacheType{ResourceCache.GetContentType()}, - m_ResDesc{Signature.GetResourceDesc(ResIndex)}, - m_Attribs{Signature.GetResourceAttribs(ResIndex)}, - m_CachedSet{ResourceCache.GetDescriptorSet(m_Attribs.DescrSet)}, - m_DstRes{m_CachedSet.GetResource(m_Attribs.CacheOffset(m_CacheType) + ArrayIndex)}, - m_vkDescrSet{m_CachedSet.GetVkDescriptorSet()} -{ - VERIFY_EXPR(ArrayIndex < m_ResDesc.ArraySize); - VERIFY(m_DstRes.Type == m_Attribs.GetDescriptorType(), "Inconsistent types"); - -#ifdef DILIGENT_DEBUG - if (m_CacheType == ResourceCacheContentType::SRB) - { - if (m_ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || m_ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE) - { - VERIFY(m_vkDescrSet != VK_NULL_HANDLE, "Static and mutable variables must have valid Vulkan descriptor set assigned"); - // Dynamic variables do not have vulkan descriptor set only until they are assigned one the first time - } - } - else if (m_CacheType == ResourceCacheContentType::Signature) - { - VERIFY(m_vkDescrSet == VK_NULL_HANDLE, "Static shader resource cache should not have vulkan descriptor set allocation"); - } - else - { - UNEXPECTED("Unexpected shader resource cache content type"); - } -#endif -} - -void BindResourceHelper::operator()(IDeviceObject* pObj) const -{ - if (pObj) - { - static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); - switch (m_DstRes.Type) - { - case DescriptorType::UniformBuffer: - case DescriptorType::UniformBufferDynamic: - CacheUniformBuffer(pObj); - break; - - case DescriptorType::StorageBuffer: - case DescriptorType::StorageBuffer_ReadOnly: - case DescriptorType::StorageBufferDynamic: - case DescriptorType::StorageBufferDynamic_ReadOnly: - CacheStorageBuffer(pObj); - break; - - case DescriptorType::UniformTexelBuffer: - case DescriptorType::StorageTexelBuffer: - case DescriptorType::StorageTexelBuffer_ReadOnly: - CacheTexelBuffer(pObj); - break; - - case DescriptorType::StorageImage: - case DescriptorType::SeparateImage: - case DescriptorType::CombinedImageSampler: - CacheImage(pObj); - break; - - case DescriptorType::Sampler: - if (!m_Attribs.IsImmutableSamplerAssigned()) - { - CacheSeparateSampler(pObj); - } - else - { - // 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) - UNEXPECTED("Attempting to assign a sampler to an immutable sampler '", m_ResDesc.Name, '\''); - } - break; - - case DescriptorType::InputAttachment: - CacheInputAttachment(pObj); - break; - - case DescriptorType::AccelerationStructure: - CacheAccelerationStructure(pObj); - break; - - default: UNEXPECTED("Unknown resource type ", static_cast<Uint32>(m_DstRes.Type)); - } - } - else - { - if (m_DstRes.pObject && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - LOG_ERROR_MESSAGE("Shader variable '", m_ResDesc.Name, "' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. ", - "Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource."); - } - - m_DstRes.pObject.Release(); - } -} - -template <typename ObjectType, typename TPreUpdateObject> -bool BindResourceHelper::UpdateCachedResource(RefCntAutoPtr<ObjectType>&& pObject, - TPreUpdateObject PreUpdateObject) const -{ - if (pObject) - { - if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr) - { - // Do not update resource if one is already bound unless it is dynamic. This may be - // dangerous as writing descriptors while they are used by the GPU is an undefined behavior - return false; - } - - PreUpdateObject(m_DstRes.pObject.template RawPtr<const ObjectType>(), pObject.template RawPtr<const ObjectType>()); - m_DstRes.pObject.Attach(pObject.Detach()); - return true; - } - else - { - return false; - } -} - -void BindResourceHelper::CacheUniformBuffer(IDeviceObject* pBuffer) const -{ - VERIFY((m_DstRes.Type == DescriptorType::UniformBuffer || - m_DstRes.Type == DescriptorType::UniformBufferDynamic), - "Uniform buffer resource is expected"); - - // We cannot use ValidatedCast<> here as the resource can have wrong type - RefCntAutoPtr<BufferVkImpl> pBufferVk{pBuffer, IID_BufferVk}; -#ifdef DILIGENT_DEVELOPMENT - VerifyConstantBufferBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ResDesc.Flags, m_ArrayIndex, - pBuffer, pBufferVk.RawPtr(), m_DstRes.pObject.RawPtr()); -#endif - - auto UpdateDynamicBuffersCounter = [this](const BufferVkImpl* pOldBuffer, const BufferVkImpl* pNewBuffer) { - auto& DynamicBuffersCounter = m_ResourceCache.GetDynamicBuffersCounter(); - if (pOldBuffer != nullptr && pOldBuffer->GetDesc().Usage == USAGE_DYNAMIC) - { - VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache"); - --DynamicBuffersCounter; - } - if (pNewBuffer != nullptr && pNewBuffer->GetDesc().Usage == USAGE_DYNAMIC) - { - ++DynamicBuffersCounter; - VERIFY(DynamicBuffersCounter <= m_Signature.GetDynamicOffsetCount(), "Dynamic buffers counter exceeded the numer of dynamic offsets in the signature"); - } - }; - if (UpdateCachedResource(std::move(pBufferVk), UpdateDynamicBuffersCounter)) - { - // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC descriptor type require - // buffer to be created with VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT - - // Do not update descriptor for a dynamic uniform buffer. All dynamic resource - // descriptors are updated at once by CommitDynamicResources() when SRB is committed. - if (m_vkDescrSet != VK_NULL_HANDLE && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - VkDescriptorBufferInfo DescrBuffInfo = m_DstRes.GetUniformBufferDescriptorWriteInfo(); - UpdateDescriptorHandle(nullptr, &DescrBuffInfo, nullptr); - } - } -} - -void BindResourceHelper::CacheStorageBuffer(IDeviceObject* pBufferView) const -{ - VERIFY((m_DstRes.Type == DescriptorType::StorageBuffer || - m_DstRes.Type == DescriptorType::StorageBuffer_ReadOnly || - m_DstRes.Type == DescriptorType::StorageBufferDynamic || - m_DstRes.Type == DescriptorType::StorageBufferDynamic_ReadOnly), - "Storage buffer resource is expected"); - - RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk}; -#ifdef DILIGENT_DEVELOPMENT - { - // HLSL buffer SRVs are mapped to storge buffers in GLSL - const auto RequiredViewType = DescriptorTypeToBufferView(m_DstRes.Type); - VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, - pBufferView, pBufferViewVk.RawPtr(), - {RequiredViewType}, RESOURCE_DIM_BUFFER, - false, // IsMultisample - m_DstRes.pObject.RawPtr()); - if (pBufferViewVk != nullptr) - { - const auto& ViewDesc = pBufferViewVk->GetDesc(); - const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc(); - if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW) - { - LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", - m_ResDesc.Name, "': structured buffer view is expected."); - } - } - } -#endif - - auto UpdateDynamicBuffersCounter = [this](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) { - auto& DynamicBuffersCounter = m_ResourceCache.GetDynamicBuffersCounter(); - if (pOldBufferView != nullptr && pOldBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC) - { - VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache"); - --DynamicBuffersCounter; - } - if (pNewBufferView != nullptr && pNewBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC) - { - ++DynamicBuffersCounter; - VERIFY(DynamicBuffersCounter <= m_Signature.GetDynamicOffsetCount(), "Dynamic buffers counter exceeded the numer of dynamic offsets in the signature"); - } - }; - - if (UpdateCachedResource(std::move(pBufferViewVk), UpdateDynamicBuffersCounter)) - { - // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC descriptor type - // require buffer to be created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT (13.2.4) - - // Do not update descriptor for a dynamic storage buffer. All dynamic resource - // descriptors are updated at once by CommitDynamicResources() when SRB is committed. - if (m_vkDescrSet != VK_NULL_HANDLE && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - VkDescriptorBufferInfo DescrBuffInfo = m_DstRes.GetStorageBufferDescriptorWriteInfo(); - UpdateDescriptorHandle(nullptr, &DescrBuffInfo, nullptr); - } - } -} - -void BindResourceHelper::CacheTexelBuffer(IDeviceObject* pBufferView) const -{ - VERIFY((m_DstRes.Type == DescriptorType::UniformTexelBuffer || - m_DstRes.Type == DescriptorType::StorageTexelBuffer || - m_DstRes.Type == DescriptorType::StorageTexelBuffer_ReadOnly), - "Uniform or storage buffer resource is expected"); - - RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk}; -#ifdef DILIGENT_DEVELOPMENT - { - // HLSL buffer SRVs are mapped to storge buffers in GLSL - const auto RequiredViewType = DescriptorTypeToBufferView(m_DstRes.Type); - VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, - pBufferView, pBufferViewVk.RawPtr(), - {RequiredViewType}, RESOURCE_DIM_BUFFER, - false, // IsMultisample - m_DstRes.pObject.RawPtr()); - if (pBufferViewVk != nullptr) - { - const auto& ViewDesc = pBufferViewVk->GetDesc(); - const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc(); - if (!(BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED)) - { - LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", - m_ResDesc.Name, "': formatted buffer view is expected."); - } - } - } -#endif - - if (UpdateCachedResource(std::move(pBufferViewVk), [](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {})) - { - // The following bits must have been set at buffer creation time: - // * VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER -> VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT - // * VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER -> VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT - - // Do not update descriptor for a dynamic texel buffer. All dynamic resource descriptors - // are updated at once by CommitDynamicResources() when SRB is committed. - if (m_vkDescrSet != VK_NULL_HANDLE && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - VkBufferView BuffView = m_DstRes.pObject.RawPtr<BufferViewVkImpl>()->GetVkBufferView(); - UpdateDescriptorHandle(nullptr, nullptr, &BuffView); - } - } -} - -void BindResourceHelper::CacheImage(IDeviceObject* pTexView) const -{ - VERIFY((m_DstRes.Type == DescriptorType::StorageImage || - m_DstRes.Type == DescriptorType::SeparateImage || - m_DstRes.Type == DescriptorType::CombinedImageSampler), - "Storage image, separate image or sampled image resource is expected"); - - RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk}; -#ifdef DILIGENT_DEVELOPMENT - { - // HLSL buffer SRVs are mapped to storge buffers in GLSL - auto RequiredViewType = DescriptorTypeToTextureView(m_DstRes.Type); - VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, - pTexView, pTexViewVk0.RawPtr(), - {RequiredViewType}, - RESOURCE_DIM_UNDEFINED, // Required resource dimension is not known - false, // IsMultisample - m_DstRes.pObject.RawPtr()); - } -#endif - if (UpdateCachedResource(std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {})) - { - // We can do RawPtr here safely since UpdateCachedResource() returned true - auto* pTexViewVk = m_DstRes.pObject.RawPtr<TextureViewVkImpl>(); -#ifdef DILIGENT_DEVELOPMENT - if (m_DstRes.Type == DescriptorType::CombinedImageSampler && !m_Attribs.IsImmutableSamplerAssigned()) - { - if (pTexViewVk->GetSampler() == nullptr) - { - LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", - GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), "'. No sampler is assigned to the view"); - } - } -#endif - - // Do not update descriptor for a dynamic image. All dynamic resource descriptors - // are updated at once by CommitDynamicResources() when SRB is committed. - if (m_vkDescrSet != VK_NULL_HANDLE && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - VkDescriptorImageInfo DescrImgInfo = m_DstRes.GetImageDescriptorWriteInfo(m_Attribs.IsImmutableSamplerAssigned()); - UpdateDescriptorHandle(&DescrImgInfo, nullptr, nullptr); - } - - if (m_Attribs.IsCombinedWithSampler()) - { - VERIFY(m_DstRes.Type == DescriptorType::SeparateImage, - "Only separate images can be assigned separate samplers when using HLSL-style combined samplers."); - VERIFY(!m_Attribs.IsImmutableSamplerAssigned(), "Separate image can't be assigned an immutable sampler."); - - const auto& SamplerResDesc = m_Signature.GetResourceDesc(m_Attribs.SamplerInd); - const auto& SamplerAttribs = m_Signature.GetResourceAttribs(m_Attribs.SamplerInd); - VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER); - - if (!SamplerAttribs.IsImmutableSamplerAssigned()) - { - auto* pSampler = pTexViewVk->GetSampler(); - if (pSampler != nullptr) - { - DEV_CHECK_ERR(SamplerResDesc.ArraySize == 1 || SamplerResDesc.ArraySize == m_ResDesc.ArraySize, - "Array size (", SamplerResDesc.ArraySize, - ") of separate sampler variable '", - SamplerResDesc.Name, - "' must be one or the same as the array size (", m_ResDesc.ArraySize, - ") of separate image variable '", m_ResDesc.Name, "' it is assigned to"); - - BindResourceHelper BindSeparateSamler{ - m_Signature, - m_ResourceCache, - m_Attribs.SamplerInd, - SamplerResDesc.ArraySize == 1 ? 0 : m_ArrayIndex}; - BindSeparateSamler(pSampler); - } - else - { - LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerResDesc.Name, - "' assigned to separate image '", GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), - "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\''); - } - } - } - } -} - -void BindResourceHelper::CacheSeparateSampler(IDeviceObject* pSampler) const -{ - VERIFY(m_DstRes.Type == DescriptorType::Sampler, "Separate sampler resource is expected"); - VERIFY(!m_Attribs.IsImmutableSamplerAssigned(), "This separate sampler is assigned an immutable sampler"); - - RefCntAutoPtr<SamplerVkImpl> pSamplerVk{pSampler, IID_Sampler}; -#ifdef DILIGENT_DEVELOPMENT - if (pSampler != nullptr && pSamplerVk == nullptr) - { - LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", - GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), "'. Unexpected object type: sampler is expected"); - } - if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr && m_DstRes.pObject != pSamplerVk) - { - auto VarTypeStr = GetShaderVariableTypeLiteralName(m_ResDesc.VarType); - LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), - "'. Attempting to bind another sampler or null is an error and may " - "cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic."); - } -#endif - if (UpdateCachedResource(std::move(pSamplerVk), [](const SamplerVkImpl*, const SamplerVkImpl*) {})) - { - // Do not update descriptor for a dynamic sampler. All dynamic resource descriptors - // are updated at once by CommitDynamicResources() when SRB is committed. - if (m_vkDescrSet != VK_NULL_HANDLE && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - VkDescriptorImageInfo DescrImgInfo = m_DstRes.GetSamplerDescriptorWriteInfo(); - UpdateDescriptorHandle(&DescrImgInfo, nullptr, nullptr); - } - } -} - -void BindResourceHelper::CacheInputAttachment(IDeviceObject* pTexView) const -{ - VERIFY(m_DstRes.Type == DescriptorType::InputAttachment, "Input attachment resource is expected"); - RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk}; -#ifdef DILIGENT_DEVELOPMENT - VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, - pTexView, pTexViewVk0.RawPtr(), - {TEXTURE_VIEW_SHADER_RESOURCE}, - RESOURCE_DIM_UNDEFINED, - false, // IsMultisample - m_DstRes.pObject.RawPtr()); -#endif - if (UpdateCachedResource(std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {})) - { - // Do not update descriptor for a dynamic image. All dynamic resource descriptors - // are updated at once by CommitDynamicResources() when SRB is committed. - if (m_vkDescrSet != VK_NULL_HANDLE && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - VkDescriptorImageInfo DescrImgInfo = m_DstRes.GetInputAttachmentDescriptorWriteInfo(); - UpdateDescriptorHandle(&DescrImgInfo, nullptr, nullptr); - } - // - } -} - -void BindResourceHelper::CacheAccelerationStructure(IDeviceObject* pTLAS) const -{ - VERIFY(m_DstRes.Type == DescriptorType::AccelerationStructure, "Acceleration Structure resource is expected"); - RefCntAutoPtr<TopLevelASVkImpl> pTLASVk{pTLAS, IID_TopLevelASVk}; -#ifdef DILIGENT_DEVELOPMENT - VerifyTLASResourceBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, pTLAS, pTLASVk.RawPtr(), m_DstRes.pObject.RawPtr()); -#endif - if (UpdateCachedResource(std::move(pTLASVk), [](const TopLevelASVkImpl*, const TopLevelASVkImpl*) {})) - { - // Do not update descriptor for a dynamic TLAS. All dynamic resource descriptors - // are updated at once by CommitDynamicResources() when SRB is committed. - if (m_vkDescrSet != VK_NULL_HANDLE && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - VkWriteDescriptorSetAccelerationStructureKHR DescrASInfo = m_DstRes.GetAccelerationStructureWriteInfo(); - UpdateDescriptorHandle(nullptr, nullptr, nullptr, &DescrASInfo); - } - // - } -} - -void BindResourceHelper::UpdateDescriptorHandle(const VkDescriptorImageInfo* pImageInfo, - const VkDescriptorBufferInfo* pBufferInfo, - const VkBufferView* pTexelBufferView, - const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo) const -{ - VERIFY_EXPR(m_vkDescrSet != VK_NULL_HANDLE); - - VkWriteDescriptorSet WriteDescrSet; - WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - WriteDescrSet.pNext = pAccelStructInfo; - WriteDescrSet.dstSet = m_vkDescrSet; - WriteDescrSet.dstBinding = m_Attribs.BindingIndex; - WriteDescrSet.dstArrayElement = m_ArrayIndex; - WriteDescrSet.descriptorCount = 1; - // 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) - WriteDescrSet.descriptorType = GetVkDescriptorType(m_DstRes.Type); - WriteDescrSet.pImageInfo = pImageInfo; - WriteDescrSet.pBufferInfo = pBufferInfo; - WriteDescrSet.pTexelBufferView = pTexelBufferView; - - m_Signature.GetDevice()->GetLogicalDevice().UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr); -} - -} // namespace - -void PipelineResourceSignatureVkImpl::BindResource(IDeviceObject* pObj, - Uint32 ArrayIndex, - Uint32 ResIndex, - ShaderResourceCacheVk& ResourceCache) const -{ - BindResourceHelper BindHelper{ - *this, - ResourceCache, - ResIndex, - ArrayIndex}; - - BindHelper(pObj); -} - -bool PipelineResourceSignatureVkImpl::IsBound(Uint32 ArrayIndex, - Uint32 ResIndex, - const ShaderResourceCacheVk& ResourceCache) const -{ - const auto& ResDesc = GetResourceDesc(ResIndex); - const auto& Attribs = GetResourceAttribs(ResIndex); - const Uint32 CacheOffset = Attribs.CacheOffset(ResourceCache.GetContentType()); - - VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize); - - if (Attribs.DescrSet < ResourceCache.GetNumDescriptorSets()) - { - const auto& Set = ResourceCache.GetDescriptorSet(Attribs.DescrSet); - if (CacheOffset + ArrayIndex < Set.GetSize()) - { - const auto& CachedRes = Set.GetResource(CacheOffset + ArrayIndex); - return CachedRes.pObject != nullptr; - } - } - - return false; -} #ifdef DILIGENT_DEVELOPMENT bool PipelineResourceSignatureVkImpl::DvpValidateCommittedResource(const SPIRVShaderResourceAttribs& SPIRVAttribs, @@ -1436,7 +822,8 @@ bool PipelineResourceSignatureVkImpl::DvpValidateCommittedResource(const SPIRVSh bool BindingsOK = true; for (Uint32 ArrIndex = 0; ArrIndex < SPIRVAttribs.ArraySize; ++ArrIndex) { - if (!IsBound(ArrIndex, ResIndex, ResourceCache)) + const auto& Res = DescrSetResources.GetResource(CacheOffset + ArrIndex); + if (Res.IsNull()) { LOG_ERROR_MESSAGE("No resource is bound to variable '", GetShaderResourcePrintName(SPIRVAttribs, ArrIndex), "' in shader '", ShaderName, "' of PSO '", PSOName, "'"); @@ -1454,7 +841,10 @@ bool PipelineResourceSignatureVkImpl::DvpValidateCommittedResource(const SPIRVSh { if (ArrIndex < SamplerResDesc.ArraySize) { - if (!IsBound(ArrIndex, ResAttribs.SamplerInd, ResourceCache)) + const auto& SamDescrSetResources = ResourceCache.GetDescriptorSet(SamplerAttribs.DescrSet); + const auto SamCacheOffset = SamplerAttribs.CacheOffset(CacheType); + const auto& Sam = SamDescrSetResources.GetResource(SamCacheOffset + ArrIndex); + if (Sam.IsNull()) { LOG_ERROR_MESSAGE("No sampler is bound to sampler variable '", GetShaderResourcePrintName(SamplerResDesc, ArrIndex), "' combined with texture '", SPIRVAttribs.Name, "' in shader '", ShaderName, "' of PSO '", PSOName, "'."); @@ -1464,7 +854,6 @@ bool PipelineResourceSignatureVkImpl::DvpValidateCommittedResource(const SPIRVSh } } - const auto& Res = DescrSetResources.GetResource(CacheOffset + ArrIndex); switch (ResAttribs.GetDescriptorType()) { case DescriptorType::UniformBuffer: diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index c4c40f7c..83058f38 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -100,12 +100,12 @@ void ShaderResourceCacheVk::InitializeSets(IMemoryAllocator& MemAllocator, Uint3 } } -void ShaderResourceCacheVk::InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type) +void ShaderResourceCacheVk::InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type, bool HasImmutableSampler) { auto& DescrSet = GetDescriptorSet(Set); for (Uint32 res = 0; res < ArraySize; ++res) { - new (&DescrSet.GetResource(Offset + res)) Resource{Type}; + new (&DescrSet.GetResource(Offset + res)) Resource{Type, HasImmutableSampler}; #ifdef DILIGENT_DEBUG m_DbgInitializedResources[Set][Offset + res] = true; #endif @@ -174,6 +174,140 @@ ShaderResourceCacheVk::~ShaderResourceCacheVk() } } +const ShaderResourceCacheVk::Resource& ShaderResourceCacheVk::SetResource(const VulkanUtilities::VulkanLogicalDevice* pLogicalDevice, + Uint32 SetIndex, + Uint32 Offset, + Uint32 BindingIndex, + Uint32 ArrayIndex, + RefCntAutoPtr<IDeviceObject>&& pObject) +{ + auto& DescrSet = GetDescriptorSet(SetIndex); + auto& Res = DescrSet.GetResource(Offset); + + const BufferVkImpl* pOldBuffer = nullptr; + const BufferVkImpl* pNewBuffer = nullptr; + switch (Res.Type) + { + case DescriptorType::UniformBuffer: + VERIFY(!pObject || pObject.RawPtr<const BufferVkImpl>()->GetDesc().Usage != USAGE_DYNAMIC, + "Dynamic uniform buffer is being bound to a non-dynamic descriptor. The buffer's dynamic offset will not be properly handled."); + break; + + case DescriptorType::UniformBufferDynamic: + pOldBuffer = Res.pObject.RawPtr<const BufferVkImpl>(); + pNewBuffer = pObject.RawPtr<const BufferVkImpl>(); + break; + + case DescriptorType::StorageBuffer: + case DescriptorType::StorageBuffer_ReadOnly: + VERIFY(!pObject || pObject.RawPtr<const BufferViewVkImpl>()->GetBuffer<const BufferVkImpl>()->GetDesc().Usage != USAGE_DYNAMIC, + "Dynamic storage buffer is being bound to a non-dynamic descriptor. The buffer's dynamic offset will not be properly handled."); + break; + + case DescriptorType::StorageBufferDynamic: + case DescriptorType::StorageBufferDynamic_ReadOnly: + pOldBuffer = Res.pObject ? Res.pObject.RawPtr<const BufferViewVkImpl>()->GetBuffer<const BufferVkImpl>() : nullptr; + pNewBuffer = pObject ? pObject.RawPtr<const BufferViewVkImpl>()->GetBuffer<const BufferVkImpl>() : nullptr; + break; + + default: + // Do nothing + break; + } + + if (pOldBuffer != nullptr && pOldBuffer->GetDesc().Usage == USAGE_DYNAMIC) + { + VERIFY(m_NumDynamicBuffers > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache"); + --m_NumDynamicBuffers; + } + if (pNewBuffer != nullptr && pNewBuffer->GetDesc().Usage == USAGE_DYNAMIC) + { + ++m_NumDynamicBuffers; + } + + Res.pObject = std::move(pObject); + + auto vkSet = DescrSet.GetVkDescriptorSet(); + if (vkSet != VK_NULL_HANDLE && Res.pObject) + { + VERIFY(pLogicalDevice != nullptr, "Logical device must not be null to write descriptor to a non-null set"); + + VkWriteDescriptorSet WriteDescrSet; + WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + WriteDescrSet.pNext = nullptr; + WriteDescrSet.dstSet = vkSet; + WriteDescrSet.dstBinding = BindingIndex; + WriteDescrSet.dstArrayElement = ArrayIndex; + WriteDescrSet.descriptorCount = 1; + // 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) + WriteDescrSet.descriptorType = DescriptorTypeToVkDescriptorType(Res.Type); + WriteDescrSet.pImageInfo = nullptr; + WriteDescrSet.pBufferInfo = nullptr; + WriteDescrSet.pTexelBufferView = nullptr; + + // Do not zero-initialize! + VkDescriptorImageInfo vkDescrImageInfo; + VkDescriptorBufferInfo vkDescrBufferInfo; + VkBufferView vkDescrBufferView; + VkWriteDescriptorSetAccelerationStructureKHR vkDescrAccelStructInfo; + + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); + switch (Res.Type) + { + case DescriptorType::Sampler: + vkDescrImageInfo = Res.GetSamplerDescriptorWriteInfo(); + WriteDescrSet.pImageInfo = &vkDescrImageInfo; + break; + + case DescriptorType::CombinedImageSampler: + case DescriptorType::SeparateImage: + case DescriptorType::StorageImage: + vkDescrImageInfo = Res.GetImageDescriptorWriteInfo(); + WriteDescrSet.pImageInfo = &vkDescrImageInfo; + break; + + case DescriptorType::UniformTexelBuffer: + case DescriptorType::StorageTexelBuffer: + case DescriptorType::StorageTexelBuffer_ReadOnly: + vkDescrBufferView = Res.GetBufferViewWriteInfo(); + WriteDescrSet.pTexelBufferView = &vkDescrBufferView; + break; + + case DescriptorType::UniformBuffer: + case DescriptorType::UniformBufferDynamic: + vkDescrBufferInfo = Res.GetUniformBufferDescriptorWriteInfo(); + WriteDescrSet.pBufferInfo = &vkDescrBufferInfo; + break; + + case DescriptorType::StorageBuffer: + case DescriptorType::StorageBuffer_ReadOnly: + case DescriptorType::StorageBufferDynamic: + case DescriptorType::StorageBufferDynamic_ReadOnly: + vkDescrBufferInfo = Res.GetStorageBufferDescriptorWriteInfo(); + WriteDescrSet.pBufferInfo = &vkDescrBufferInfo; + break; + + case DescriptorType::InputAttachment: + vkDescrImageInfo = Res.GetInputAttachmentDescriptorWriteInfo(); + WriteDescrSet.pImageInfo = &vkDescrImageInfo; + break; + + case DescriptorType::AccelerationStructure: + vkDescrAccelStructInfo = Res.GetAccelerationStructureWriteInfo(); + WriteDescrSet.pNext = &vkDescrAccelStructInfo; + break; + + default: + UNEXPECTED("Unexpected descriptor type"); + } + + pLogicalDevice->UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr); + } + + return Res; +} + static RESOURCE_STATE DescriptorTypeToResourceState(DescriptorType Type) { static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); @@ -486,7 +620,7 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript return DescrBuffInfo; } -VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteInfo(bool IsImmutableSampler) const +VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteInfo() const { // clang-format off VERIFY(Type == DescriptorType::StorageImage || @@ -503,9 +637,9 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteIn VkDescriptorImageInfo DescrImgInfo; DescrImgInfo.sampler = VK_NULL_HANDLE; - VERIFY(Type == DescriptorType::CombinedImageSampler || !IsImmutableSampler, + VERIFY(Type == DescriptorType::CombinedImageSampler || !HasImmutableSampler, "Immutable sampler can't be assigned to separarate image or storage image"); - if (Type == DescriptorType::CombinedImageSampler && !IsImmutableSampler) + if (Type == DescriptorType::CombinedImageSampler && !HasImmutableSampler) { // 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) @@ -563,6 +697,7 @@ VkBufferView ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo() const VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWriteInfo() const { VERIFY(Type == DescriptorType::Sampler, "Separate sampler resource is expected"); + VERIFY(!HasImmutableSampler, "Separate immutable samplers can't be updated"); DEV_CHECK_ERR(pObject != nullptr, "Unable to get separate sampler descriptor write info: cached object is null"); const auto* pSamplerVk = pObject.RawPtr<const SamplerVkImpl>(); diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVariableManagerVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVariableManagerVk.cpp index 58b16b90..a159b8b9 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVariableManagerVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableManagerVk.cpp @@ -30,6 +30,9 @@ #include "ShaderVariableManagerVk.hpp" #include "RenderDeviceVkImpl.hpp" #include "PipelineResourceSignatureVkImpl.hpp" +#include "SamplerVkImpl.hpp" +#include "TextureViewVkImpl.hpp" +#include "TopLevelASVkImpl.hpp" namespace Diligent { @@ -210,14 +213,479 @@ void ShaderVariableVkImpl::SetArray(IDeviceObject* const* ppObjects, BindResource(ppObjects[Elem], FirstElement + Elem); } -bool ShaderVariableVkImpl::IsBound(Uint32 ArrayIndex) const + +namespace +{ + +inline BUFFER_VIEW_TYPE DescriptorTypeToBufferView(DescriptorType Type) +{ + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); + switch (Type) + { + case DescriptorType::UniformTexelBuffer: + case DescriptorType::StorageTexelBuffer_ReadOnly: + case DescriptorType::StorageBuffer_ReadOnly: + case DescriptorType::StorageBufferDynamic_ReadOnly: + return BUFFER_VIEW_SHADER_RESOURCE; + + case DescriptorType::StorageTexelBuffer: + case DescriptorType::StorageBuffer: + case DescriptorType::StorageBufferDynamic: + return BUFFER_VIEW_UNORDERED_ACCESS; + + default: + UNEXPECTED("Unsupported descriptor type for buffer view"); + return BUFFER_VIEW_UNDEFINED; + } +} + +inline TEXTURE_VIEW_TYPE DescriptorTypeToTextureView(DescriptorType Type) +{ + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); + switch (Type) + { + case DescriptorType::StorageImage: + return TEXTURE_VIEW_UNORDERED_ACCESS; + + case DescriptorType::CombinedImageSampler: + case DescriptorType::SeparateImage: + case DescriptorType::InputAttachment: + return TEXTURE_VIEW_SHADER_RESOURCE; + + default: + UNEXPECTED("Unsupported descriptor type for texture view"); + return TEXTURE_VIEW_UNDEFINED; + } +} + + +struct BindResourceHelper +{ + BindResourceHelper(const PipelineResourceSignatureVkImpl& Signature, + ShaderResourceCacheVk& ResourceCache, + Uint32 ResIndex, + Uint32 ArrayIndex); + + void operator()(IDeviceObject* pObj) const; + +private: + void CacheUniformBuffer(IDeviceObject* pBuffer) const; + + void CacheStorageBuffer(IDeviceObject* pBufferView) const; + + void CacheTexelBuffer(IDeviceObject* pBufferView) const; + + void CacheImage(IDeviceObject* pTexView) const; + + void CacheSeparateSampler(IDeviceObject* pSampler) const; + + void CacheInputAttachment(IDeviceObject* pTexView) const; + + void CacheAccelerationStructure(IDeviceObject* pTLAS) const; + + template <typename ObjectType> + bool UpdateCachedResource(RefCntAutoPtr<ObjectType>&& pObject) const; + + // Updates resource descriptor in the descriptor set + inline void UpdateDescriptorHandle(const VkDescriptorImageInfo* pImageInfo, + const VkDescriptorBufferInfo* pBufferInfo, + const VkBufferView* pTexelBufferView, + const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const; + +private: + using ResourceAttribs = PipelineResourceSignatureVkImpl::ResourceAttribs; + using CachedSet = ShaderResourceCacheVk::DescriptorSet; + + const PipelineResourceSignatureVkImpl& m_Signature; + ShaderResourceCacheVk& m_ResourceCache; + const Uint32 m_ArrayIndex; + const ResourceCacheContentType m_CacheType; + const PipelineResourceDesc& m_ResDesc; + const ResourceAttribs& m_Attribs; + const Uint32 m_DstResCacheOffset; + const CachedSet& m_CachedSet; + const ShaderResourceCacheVk::Resource& m_DstRes; +}; + +BindResourceHelper::BindResourceHelper(const PipelineResourceSignatureVkImpl& Signature, + ShaderResourceCacheVk& ResourceCache, + Uint32 ResIndex, + Uint32 ArrayIndex) : + // clang-format off + m_Signature {Signature}, + m_ResourceCache {ResourceCache}, + m_ArrayIndex {ArrayIndex}, + m_CacheType {ResourceCache.GetContentType()}, + m_ResDesc {Signature.GetResourceDesc(ResIndex)}, + m_Attribs {Signature.GetResourceAttribs(ResIndex)}, + m_DstResCacheOffset {m_Attribs.CacheOffset(m_CacheType) + ArrayIndex}, + m_CachedSet {const_cast<const ShaderResourceCacheVk&>(ResourceCache).GetDescriptorSet(m_Attribs.DescrSet)}, + m_DstRes {m_CachedSet.GetResource(m_DstResCacheOffset)} +// clang-format on +{ + VERIFY_EXPR(ArrayIndex < m_ResDesc.ArraySize); + VERIFY(m_DstRes.Type == m_Attribs.GetDescriptorType(), "Inconsistent types"); + +#ifdef DILIGENT_DEBUG + { + auto vkDescrSet = m_CachedSet.GetVkDescriptorSet(); + if (m_CacheType == ResourceCacheContentType::SRB) + { + if (m_ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || + m_ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE) + { + VERIFY(vkDescrSet != VK_NULL_HANDLE, "Static and mutable variables must have a valid Vulkan descriptor set assigned"); + } + else + { + VERIFY(vkDescrSet == VK_NULL_HANDLE, "Dynamic variables must never have valid Vulkan descriptor set assigned"); + } + } + else if (m_CacheType == ResourceCacheContentType::Signature) + { + VERIFY(vkDescrSet == VK_NULL_HANDLE, "Static shader resource cache should not have Vulkan descriptor set allocation"); + } + else + { + UNEXPECTED("Unexpected shader resource cache content type"); + } + } +#endif +} + +void BindResourceHelper::operator()(IDeviceObject* pObj) const +{ + if (pObj) + { + static_assert(static_cast<Uint32>(DescriptorType::Count) == 15, "Please update the switch below to handle the new descriptor type"); + switch (m_DstRes.Type) + { + case DescriptorType::UniformBuffer: + case DescriptorType::UniformBufferDynamic: + CacheUniformBuffer(pObj); + break; + + case DescriptorType::StorageBuffer: + case DescriptorType::StorageBuffer_ReadOnly: + case DescriptorType::StorageBufferDynamic: + case DescriptorType::StorageBufferDynamic_ReadOnly: + CacheStorageBuffer(pObj); + break; + + case DescriptorType::UniformTexelBuffer: + case DescriptorType::StorageTexelBuffer: + case DescriptorType::StorageTexelBuffer_ReadOnly: + CacheTexelBuffer(pObj); + break; + + case DescriptorType::StorageImage: + case DescriptorType::SeparateImage: + case DescriptorType::CombinedImageSampler: + CacheImage(pObj); + break; + + case DescriptorType::Sampler: + if (!m_Attribs.IsImmutableSamplerAssigned()) + { + CacheSeparateSampler(pObj); + } + else + { + // 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) + UNEXPECTED("Attempting to assign a sampler to an immutable sampler '", m_ResDesc.Name, '\''); + } + break; + + case DescriptorType::InputAttachment: + CacheInputAttachment(pObj); + break; + + case DescriptorType::AccelerationStructure: + CacheAccelerationStructure(pObj); + break; + + default: UNEXPECTED("Unknown resource type ", static_cast<Uint32>(m_DstRes.Type)); + } + } + else + { + if (m_DstRes.pObject && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) + { + LOG_ERROR_MESSAGE("Shader variable '", m_ResDesc.Name, "' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. ", + "Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource."); + } + + m_ResourceCache.ResetResource(m_Attribs.DescrSet, m_DstResCacheOffset); + } +} + +template <typename ObjectType> +bool BindResourceHelper::UpdateCachedResource(RefCntAutoPtr<ObjectType>&& pObject) const +{ + if (pObject) + { + if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr) + { + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as writing descriptors while they are used by the GPU is an undefined behavior + return false; + } + + m_ResourceCache.SetResource(&m_Signature.GetDevice()->GetLogicalDevice(), + m_Attribs.DescrSet, m_DstResCacheOffset, + m_Attribs.BindingIndex, m_ArrayIndex, + std::move(pObject)); + return true; + } + else + { + return false; + } +} + +void BindResourceHelper::CacheUniformBuffer(IDeviceObject* pBuffer) const +{ + VERIFY((m_DstRes.Type == DescriptorType::UniformBuffer || + m_DstRes.Type == DescriptorType::UniformBufferDynamic), + "Uniform buffer resource is expected"); + + // We cannot use ValidatedCast<> here as the resource can have wrong type + RefCntAutoPtr<BufferVkImpl> pBufferVk{pBuffer, IID_BufferVk}; +#ifdef DILIGENT_DEVELOPMENT + VerifyConstantBufferBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ResDesc.Flags, m_ArrayIndex, + pBuffer, pBufferVk.RawPtr(), m_DstRes.pObject.RawPtr()); +#endif + + UpdateCachedResource(std::move(pBufferVk)); +} + +void BindResourceHelper::CacheStorageBuffer(IDeviceObject* pBufferView) const +{ + VERIFY((m_DstRes.Type == DescriptorType::StorageBuffer || + m_DstRes.Type == DescriptorType::StorageBuffer_ReadOnly || + m_DstRes.Type == DescriptorType::StorageBufferDynamic || + m_DstRes.Type == DescriptorType::StorageBufferDynamic_ReadOnly), + "Storage buffer resource is expected"); + + RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk}; +#ifdef DILIGENT_DEVELOPMENT + { + // HLSL buffer SRVs are mapped to storge buffers in GLSL + const auto RequiredViewType = DescriptorTypeToBufferView(m_DstRes.Type); + VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, + pBufferView, pBufferViewVk.RawPtr(), + {RequiredViewType}, RESOURCE_DIM_BUFFER, + false, // IsMultisample + m_DstRes.pObject.RawPtr()); + if (pBufferViewVk != nullptr) + { + const auto& ViewDesc = pBufferViewVk->GetDesc(); + const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc(); + if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + m_ResDesc.Name, "': structured buffer view is expected."); + } + } + } +#endif + + UpdateCachedResource(std::move(pBufferViewVk)); +} + +void BindResourceHelper::CacheTexelBuffer(IDeviceObject* pBufferView) const { - return m_ParentManager.m_pSignature->IsBound(ArrayIndex, m_ResIndex, m_ParentManager.m_ResourceCache); + VERIFY((m_DstRes.Type == DescriptorType::UniformTexelBuffer || + m_DstRes.Type == DescriptorType::StorageTexelBuffer || + m_DstRes.Type == DescriptorType::StorageTexelBuffer_ReadOnly), + "Uniform or storage buffer resource is expected"); + + RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk}; +#ifdef DILIGENT_DEVELOPMENT + { + // HLSL buffer SRVs are mapped to storge buffers in GLSL + const auto RequiredViewType = DescriptorTypeToBufferView(m_DstRes.Type); + VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, + pBufferView, pBufferViewVk.RawPtr(), + {RequiredViewType}, RESOURCE_DIM_BUFFER, + false, // IsMultisample + m_DstRes.pObject.RawPtr()); + if (pBufferViewVk != nullptr) + { + const auto& ViewDesc = pBufferViewVk->GetDesc(); + const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc(); + if (!(BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED)) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + m_ResDesc.Name, "': formatted buffer view is expected."); + } + } + } +#endif + + UpdateCachedResource(std::move(pBufferViewVk)); +} + +void BindResourceHelper::CacheImage(IDeviceObject* pTexView) const +{ + VERIFY((m_DstRes.Type == DescriptorType::StorageImage || + m_DstRes.Type == DescriptorType::SeparateImage || + m_DstRes.Type == DescriptorType::CombinedImageSampler), + "Storage image, separate image or sampled image resource is expected"); + + RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk}; +#ifdef DILIGENT_DEVELOPMENT + { + // HLSL buffer SRVs are mapped to storge buffers in GLSL + auto RequiredViewType = DescriptorTypeToTextureView(m_DstRes.Type); + VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, + pTexView, pTexViewVk0.RawPtr(), + {RequiredViewType}, + RESOURCE_DIM_UNDEFINED, // Required resource dimension is not known + false, // IsMultisample + m_DstRes.pObject.RawPtr()); + } +#endif + + TextureViewVkImpl* pTexViewVk = pTexViewVk0; + if (UpdateCachedResource(std::move(pTexViewVk0))) + { +#ifdef DILIGENT_DEVELOPMENT + if (m_DstRes.Type == DescriptorType::CombinedImageSampler && !m_Attribs.IsImmutableSamplerAssigned()) + { + if (pTexViewVk->GetSampler() == nullptr) + { + LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", + GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), "'. No sampler is assigned to the view"); + } + } +#endif + + if (m_Attribs.IsCombinedWithSampler()) + { + VERIFY(m_DstRes.Type == DescriptorType::SeparateImage, + "Only separate images can be assigned separate samplers when using HLSL-style combined samplers."); + VERIFY(!m_Attribs.IsImmutableSamplerAssigned(), "Separate image can't be assigned an immutable sampler."); + + const auto& SamplerResDesc = m_Signature.GetResourceDesc(m_Attribs.SamplerInd); + const auto& SamplerAttribs = m_Signature.GetResourceAttribs(m_Attribs.SamplerInd); + VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER); + + if (!SamplerAttribs.IsImmutableSamplerAssigned()) + { + auto* pSampler = pTexViewVk->GetSampler(); + if (pSampler != nullptr) + { + DEV_CHECK_ERR(SamplerResDesc.ArraySize == 1 || SamplerResDesc.ArraySize == m_ResDesc.ArraySize, + "Array size (", SamplerResDesc.ArraySize, + ") of separate sampler variable '", + SamplerResDesc.Name, + "' must be one or the same as the array size (", m_ResDesc.ArraySize, + ") of separate image variable '", m_ResDesc.Name, "' it is assigned to"); + + BindResourceHelper BindSeparateSamler{ + m_Signature, + m_ResourceCache, + m_Attribs.SamplerInd, + SamplerResDesc.ArraySize == 1 ? 0 : m_ArrayIndex}; + BindSeparateSamler(pSampler); + } + else + { + LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerResDesc.Name, + "' assigned to separate image '", GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), + "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\''); + } + } + } + } } -void ShaderVariableVkImpl::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const +void BindResourceHelper::CacheSeparateSampler(IDeviceObject* pSampler) const { - m_ParentManager.m_pSignature->BindResource(pObj, ArrayIndex, m_ResIndex, m_ParentManager.m_ResourceCache); + VERIFY(m_DstRes.Type == DescriptorType::Sampler, "Separate sampler resource is expected"); + VERIFY(!m_Attribs.IsImmutableSamplerAssigned(), "This separate sampler is assigned an immutable sampler"); + + RefCntAutoPtr<SamplerVkImpl> pSamplerVk{pSampler, IID_Sampler}; +#ifdef DILIGENT_DEVELOPMENT + if (pSampler != nullptr && pSamplerVk == nullptr) + { + LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", + GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), "'. Unexpected object type: sampler is expected"); + } + if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr && m_DstRes.pObject != pSamplerVk) + { + auto VarTypeStr = GetShaderVariableTypeLiteralName(m_ResDesc.VarType); + LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), + "'. Attempting to bind another sampler or null is an error and may " + "cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic."); + } +#endif + + UpdateCachedResource(std::move(pSamplerVk)); +} + +void BindResourceHelper::CacheInputAttachment(IDeviceObject* pTexView) const +{ + VERIFY(m_DstRes.Type == DescriptorType::InputAttachment, "Input attachment resource is expected"); + RefCntAutoPtr<TextureViewVkImpl> pTexViewVk{pTexView, IID_TextureViewVk}; +#ifdef DILIGENT_DEVELOPMENT + VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, + pTexView, pTexViewVk.RawPtr(), + {TEXTURE_VIEW_SHADER_RESOURCE}, + RESOURCE_DIM_UNDEFINED, + false, // IsMultisample + m_DstRes.pObject.RawPtr()); +#endif + + UpdateCachedResource(std::move(pTexViewVk)); +} + +void BindResourceHelper::CacheAccelerationStructure(IDeviceObject* pTLAS) const +{ + VERIFY(m_DstRes.Type == DescriptorType::AccelerationStructure, "Acceleration Structure resource is expected"); + RefCntAutoPtr<TopLevelASVkImpl> pTLASVk{pTLAS, IID_TopLevelASVk}; +#ifdef DILIGENT_DEVELOPMENT + VerifyTLASResourceBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex, pTLAS, pTLASVk.RawPtr(), m_DstRes.pObject.RawPtr()); +#endif + + UpdateCachedResource(std::move(pTLASVk)); +} + +} // namespace + + +void ShaderVariableManagerVk::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex, Uint32 ResIndex) +{ + BindResourceHelper BindHelper{ + *m_pSignature, + m_ResourceCache, + ResIndex, + ArrayIndex}; + + BindHelper(pObj); +} + +bool ShaderVariableManagerVk::IsBound(Uint32 ArrayIndex, Uint32 ResIndex) const +{ + const auto& ResDesc = GetResourceDesc(ResIndex); + const auto& Attribs = GetAttribs(ResIndex); + const Uint32 CacheOffset = Attribs.CacheOffset(m_ResourceCache.GetContentType()); + + VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize); + + if (Attribs.DescrSet < m_ResourceCache.GetNumDescriptorSets()) + { + const auto& Set = const_cast<const ShaderResourceCacheVk&>(m_ResourceCache).GetDescriptorSet(Attribs.DescrSet); + if (CacheOffset + ArrayIndex < Set.GetSize()) + { + const auto& CachedRes = Set.GetResource(CacheOffset + ArrayIndex); + return !CachedRes.IsNull(); + } + } + + return false; } } // namespace Diligent |
