summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2021-01-21 03:21:32 +0000
committerazhirnov <zh1dron@gmail.com>2021-01-21 03:35:02 +0000
commitcf7b7505e93c96e3b63d9dc9a775b994a1572fa8 (patch)
treea1a81e131b10a0edeb87740c56435c37d1dfc5c3 /Graphics/GraphicsEngineVulkan
parentadded pipeline resource signature (wip) (diff)
downloadDiligentCore-cf7b7505e93c96e3b63d9dc9a775b994a1572fa8.tar.gz
DiligentCore-cf7b7505e93c96e3b63d9dc9a775b994a1572fa8.zip
pipeline resource signature for vulkan
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/CMakeLists.txt2
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp49
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp82
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp93
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp152
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp29
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp12
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp17
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp85
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp261
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp80
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp149
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp1526
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp238
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp33
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp26
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp116
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp590
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp27
19 files changed, 2135 insertions, 1432 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
index 40a0dd49..79e61acd 100644
--- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt
+++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
@@ -17,7 +17,6 @@ set(INCLUDE
include/GenerateMipsVkHelper.hpp
include/pch.h
include/PipelineLayoutVk.hpp
- include/PipelineLayoutCacheVk.hpp
include/PipelineStateVkImpl.hpp
include/QueryManagerVk.hpp
include/QueryVkImpl.hpp
@@ -93,7 +92,6 @@ set(SRC
src/VulkanDynamicHeap.cpp
src/FramebufferCache.cpp
src/GenerateMipsVkHelper.cpp
- src/PipelineLayoutCacheVk.cpp
src/PipelineLayoutVk.cpp
src/PipelineStateVkImpl.cpp
src/QueryManagerVk.cpp
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
index d91feae3..4e6d2b30 100644
--- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
@@ -397,7 +397,6 @@ private:
void CommitVkVertexBuffers();
void CommitViewports();
void CommitScissorRects();
- void BindShaderResources(PipelineStateVkImpl* pPipelineStateVk);
__forceinline void TransitionOrVerifyBufferState(BufferVkImpl& Buffer,
RESOURCE_STATE_TRANSITION_MODE TransitionMode,
@@ -477,14 +476,54 @@ private:
Uint32 NumCommands = 0;
} m_State;
+ // graphics, compute, ray tracing
+ static constexpr Uint32 PIPELINE_BIND_POINTS = 3;
+
+ // static and dynamic descriptor sets
+ static constexpr Uint32 MAX_DESCR_SET_PER_SIGNATURE = 2;
+
+ struct DescriptorSetBindInfo
+ {
+ using ShaderResourceArray = std::array<RefCntAutoPtr<ShaderResourceBindingVkImpl>, MAX_RESOURCE_SIGNATURES>;
+ using VkDescSetArray = std::array<VkDescriptorSet, MAX_RESOURCE_SIGNATURES * MAX_DESCR_SET_PER_SIGNATURE>;
+ using BoolArray = std::bitset<MAX_RESOURCE_SIGNATURES>;
+
+ ShaderResourceArray Resources;
+ VkDescSetArray vkSets = {};
+ BoolArray PendingVkSet = {0}; // 'true' if new descriptor set must be bound
+ BoolArray PendingDynamicDescriptors = {0}; // 'true' if dynamic descriptor set must be bound
+ BoolArray DynamicBuffersPresent = {0};
+
+ DescriptorSetBindInfo()
+ {}
+
+ void Reset()
+ {
+ PendingVkSet.reset();
+ DynamicBuffersPresent.reset();
+ PendingDynamicDescriptors.reset();
+ Resources.fill({});
+
+#ifdef DILIGENT_DEBUG
+ vkSets.fill(VK_NULL_HANDLE);
+#endif
+ }
+
+ __forceinline bool RequireUpdate(bool Intact = false) const
+ {
+ return PendingVkSet.any() || PendingDynamicDescriptors.any() || (DynamicBuffersPresent.any() && !Intact);
+ }
+ };
+
+ void BindShaderResources(PipelineStateVkImpl* pPipelineStateVk);
+ void BindDescriptorSetsWithDynamicOffsets(DescriptorSetBindInfo& DescrSetBindInfo);
+ void ValidateShaderResources();
/// AZ TODO: comment
- using DescSetBindingInfoArray = std::array<PipelineLayoutVk::DescriptorSetBindInfo, 3>;
- DescSetBindingInfoArray m_DescrSetBindInfo;
+ std::array<DescriptorSetBindInfo, PIPELINE_BIND_POINTS> m_DescrSetBindInfo;
/// AZ TODO: comment
- using ShaderResourcePerPipelineType = std::array<std::array<RefCntAutoPtr<ShaderResourceBindingVkImpl>, MAX_RESOURCE_SIGNATURES>, 3>;
- ShaderResourcePerPipelineType m_ShaderResources;
+ std::vector<Uint32> m_DynamicBufferOffsets;
/// Render pass that matches currently bound render targets.
/// This render pass may or may not be currently set in the command buffer
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp
deleted file mode 100644
index f34110f7..00000000
--- a/Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2019-2021 Diligent Graphics LLC
- * Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#pragma once
-
-/// \file
-/// Declaration of Diligent::PipelineLayoutCacheVk class
-
-#include <unordered_set>
-#include <mutex>
-#include "VulkanUtilities/VulkanObjectWrappers.hpp"
-#include "PipelineLayoutVk.hpp"
-
-namespace Diligent
-{
-
-class PipelineLayoutCacheVk
-{
-public:
- PipelineLayoutCacheVk(RenderDeviceVkImpl& DeviceVKImpl) :
- m_DeviceVk{DeviceVKImpl}
- {}
-
- // clang-format off
- PipelineLayoutCacheVk (const PipelineLayoutCacheVk&) = delete;
- PipelineLayoutCacheVk (PipelineLayoutCacheVk&&) = delete;
- PipelineLayoutCacheVk& operator = (const PipelineLayoutCacheVk&) = delete;
- PipelineLayoutCacheVk& operator = (PipelineLayoutCacheVk&&) = delete;
- // clang-format on
-
- ~PipelineLayoutCacheVk();
-
- RefCntAutoPtr<PipelineLayoutVk> GetLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
-
- void OnDestroyLayout(PipelineLayoutVk* pLayout);
-
-private:
- struct PipelineLayoutHash
- {
- std::size_t operator()(const PipelineLayoutVk* Key) const noexcept
- {
- return Key->GetHash();
- }
- };
-
- struct PipelineLayoutCompare
- {
- bool operator()(const PipelineLayoutVk* lhs, const PipelineLayoutVk* rhs) const noexcept;
- };
-
- RenderDeviceVkImpl& m_DeviceVk;
-
- std::mutex m_Mutex;
-
- std::unordered_set<PipelineLayoutVk*, PipelineLayoutHash, PipelineLayoutCompare> m_Cache;
-};
-
-} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp
index fd27d0a3..cbc654b7 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp
@@ -43,43 +43,34 @@ class DeviceContextVkImpl;
class ShaderResourceCacheVk;
/// Implementation of the Diligent::PipelineLayoutVk class
-class PipelineLayoutVk final : public ObjectBase<IObject>
+class PipelineLayoutVk
{
public:
- PipelineLayoutVk(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
- ~PipelineLayoutVk();
+ PipelineLayoutVk();
- using ObjectBase<IObject>::Release;
-
- void Finalize();
+ void Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
+ void Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask);
size_t GetHash() const;
VkPipelineLayout GetVkPipelineLayout() const { return m_VkPipelineLayout; }
- PIPELINE_TYPE GetPipelineType() const { return m_PipelineType; }
Uint32 GetSignatureCount() const { return m_SignatureCount; }
Uint32 GetDescriptorSetCount() const { return m_DescrSetCount; }
Uint32 GetDynamicOffsetCount() const { return m_DynamicOffsetCount; }
- IPipelineResourceSignature* GetSignature(Uint32 index) const
+ PipelineResourceSignatureVkImpl* GetSignature(Uint32 index) const
{
VERIFY_EXPR(index < m_SignatureCount);
- return m_Signatures[index].RawPtr<IPipelineResourceSignature>();
- }
-
- bool HasSignature(IPipelineResourceSignature* pPRS) const
- {
- Uint32 Index = pPRS->GetDesc().BindingIndex;
- return Index < m_SignatureCount && m_Signatures[Index].RawPtr() == pPRS;
+ return m_Signatures[index].RawPtr<PipelineResourceSignatureVkImpl>();
}
- Uint32 GetDescrSetIndex(IPipelineResourceSignature* pPRS) const
+ Uint32 GetDescrSetIndex(const IPipelineResourceSignature* pPRS) const
{
Uint32 Index = pPRS->GetDesc().BindingIndex;
return Index < m_SignatureCount ? m_DescSetOffset[Index] : ~0u;
}
- Uint32 GetDynamicBufferOffset(IPipelineResourceSignature* pPRS) const
+ Uint32 GetDynamicBufferOffset(const IPipelineResourceSignature* pPRS) const
{
Uint32 Index = pPRS->GetDesc().BindingIndex;
return Index < m_SignatureCount ? m_DynBufOffset[Index] : 0;
@@ -93,25 +84,16 @@ public:
};
bool GetResourceInfo(const char* Name, SHADER_TYPE Stage, ResourceInfo& Info) const;
- using DescriptorSetBindInfo = PipelineResourceSignatureVkImpl::DescriptorSetBindInfo;
-
- // Computes dynamic offsets and binds descriptor sets
- __forceinline void BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
- Uint32 CtxId,
- DeviceContextVkImpl* pCtxVkImpl,
- DescriptorSetBindInfo& BindInfo) const;
-
private:
VulkanUtilities::PipelineLayoutWrapper m_VkPipelineLayout;
- RenderDeviceVkImpl* m_pDeviceVk;
+ Uint32 m_DynamicOffsetCount : 25;
- // AZ TODO: pack bits
- Uint16 m_DynamicOffsetCount = 0;
- Uint8 m_SignatureCount = 0;
- Uint8 m_DescrSetCount = 0;
+ Uint32 m_SignatureCount : 3;
+ static_assert(MAX_RESOURCE_SIGNATURES == (1 << 3), "update m_SignatureCount bits count");
- PIPELINE_TYPE m_PipelineType = PIPELINE_TYPE(0xFF);
+ Uint32 m_DescrSetCount : 4;
+ static_assert(MAX_RESOURCE_SIGNATURES * 2 == (1 << 4), "update m_DescrSetCount bits count");
using SignatureArray = std::array<RefCntAutoPtr<PipelineResourceSignatureVkImpl>, MAX_RESOURCE_SIGNATURES>;
using DescSetOffsetArray = std::array<Uint8, MAX_RESOURCE_SIGNATURES>;
@@ -122,53 +104,4 @@ private:
DynBufOffsetArray m_DynBufOffset = {};
};
-
-__forceinline void PipelineLayoutVk::BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
- Uint32 CtxId,
- DeviceContextVkImpl* pCtxVkImpl,
- DescriptorSetBindInfo& BindInfo) const
-{
- /*
- VERIFY(BindInfo.pDbgPipelineLayout != nullptr, "Pipeline layout is not initialized, which most likely means that CommitShaderResources() has never been called");
- VERIFY(BindInfo.pDbgPipelineLayout->IsSameAs(*this), "Inconsistent pipeline layout");
- VERIFY(BindInfo.DynamicOffsetCount > 0, "This function should only be called for pipelines that contain dynamic descriptors");
- VERIFY_EXPR(BindInfo.pResourceCache != nullptr);
-
-#ifdef DILIGENT_DEBUG
- Uint32 TotalDynamicDescriptors = 0;
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
- VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC;
- VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
- {
- const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType);
- TotalDynamicDescriptors += Set.NumDynamicDescriptors;
- }
- VERIFY(BindInfo.DynamicOffsetCount == TotalDynamicDescriptors, "Incosistent dynamic buffer size");
- VERIFY_EXPR(BindInfo.DynamicOffsets.size() >= BindInfo.DynamicOffsetCount);
-#endif
-
- auto NumOffsetsWritten = BindInfo.pResourceCache->GetDynamicBufferOffsets(CtxId, pCtxVkImpl, BindInfo.DynamicOffsets);
- VERIFY_EXPR(NumOffsetsWritten == BindInfo.DynamicOffsetCount);
- (void)NumOffsetsWritten;
-
- // 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.
-
- // vkCmdBindDescriptorSets causes the sets numbered [firstSet .. firstSet+descriptorSetCount-1] to use the
- // bindings stored in pDescriptorSets[0 .. descriptorSetCount-1] for subsequent rendering commands
- // (either compute or graphics, according to the pipelineBindPoint). Any bindings that were previously
- // applied via these sets are no longer valid (13.2.5)
- CmdBuffer.BindDescriptorSets(BindInfo.BindPoint,
- m_LayoutMgr.GetVkPipelineLayout(),
- 0, // First set
- BindInfo.SetCout,
- BindInfo.vkSets.data(), // BindInfo.vkSets is never empty
- // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound (13.2.5)
- BindInfo.DynamicOffsetCount,
- BindInfo.DynamicOffsets.data());
-
- BindInfo.DynamicDescriptorsBound = true;
-*/
-}
-
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp
index 6b01b4cd..c5897f86 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp
@@ -30,6 +30,7 @@
/// \file
/// Declaration of Diligent::PipelineResourceSignatureVkImpl class
#include <array>
+#include <bitset>
#include "PipelineResourceSignatureBase.hpp"
#include "VulkanUtilities/VulkanObjectWrappers.hpp"
@@ -44,6 +45,31 @@ class ShaderResourceCacheVk;
class ShaderVariableManagerVk;
class DeviceContextVkImpl;
+enum class DescriptorType : Uint8
+{
+ Sampler,
+ CombinedImageSampler,
+ SeparateImage,
+ StorageImage,
+ StorageImage_ReadOnly,
+ UniformTexelBuffer,
+ StorageTexelBuffer,
+ StorageTexelBuffer_ReadOnly,
+ UniformBuffer,
+ StorageBuffer,
+ StorageBuffer_ReadOnly,
+ UniformBufferDynamic,
+ StorageBufferDynamic,
+ StorageBufferDynamic_ReadOnly,
+ InputAttachment,
+ AccelerationStructure,
+ Count,
+ Unknown = 0xFF,
+};
+
+RESOURCE_STATE DescriptorTypeToResourceState(DescriptorType Type);
+
+
/// Implementation of the Diligent::PipelineResourceSignatureVkImpl class
class PipelineResourceSignatureVkImpl final : public PipelineResourceSignatureBase<IPipelineResourceSignature, RenderDeviceVkImpl>
{
@@ -56,23 +82,32 @@ public:
bool bIsDeviceInternal = false);
~PipelineResourceSignatureVkImpl();
- Uint32 GetDynamicBufferCount() const { return m_DynamicBufferCount; }
- Uint8 GetNumShaderStages() const { return m_NumShaders; }
- Uint32 GetTotalResourceCount() const { return m_Desc.NumResources; }
+ Uint32 GetDynamicBufferCount() const { return m_DynamicBufferCount; }
+ Uint8 GetNumShaderStages() const { return m_NumShaders; }
+ SHADER_TYPE GetShaderStageType(Uint32 StageIndex) const;
+ Uint32 GetTotalResourceCount() const { return m_Desc.NumResources; }
+ Uint32 GetNumDescriptorSets() const;
- static constexpr Uint8 InvalidSamplerInd = 0xFF;
+ static constexpr Uint32 InvalidSamplerInd = ~0u;
- struct PackedBindingIndex
+ struct ResourceAttribs
{
- Uint16 Binding;
- Uint8 DescSet : 1; // 0 - static, 1 - dynamic
- Uint8 SamplerInd = InvalidSamplerInd;
+ 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}
+ {}
};
- const PackedBindingIndex& GetBinding(Uint32 ResIndex) const
+ const ResourceAttribs& GetAttribs(Uint32 ResIndex) const
{
VERIFY_EXPR(ResIndex < m_Desc.NumResources);
- return m_pBindingIndices[ResIndex];
+ return m_pResourceAttribs[ResIndex];
}
const PipelineResourceDesc& GetResource(Uint32 ResIndex) const
@@ -84,6 +119,9 @@ public:
VkDescriptorSetLayout GetStaticVkDescriptorSetLayout() const { return m_VkDescSetLayouts[0]; }
VkDescriptorSetLayout GetDynamicVkDescriptorSetLayout() const { return m_VkDescSetLayouts[1]; }
+ bool HasStaticDescrSet() const { return GetStaticVkDescriptorSetLayout() != VK_NULL_HANDLE; }
+ bool HasDynamicDescrSet() const { return GetDynamicVkDescriptorSetLayout() != VK_NULL_HANDLE; }
+
virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding,
bool InitStaticResources) override final;
@@ -93,51 +131,14 @@ public:
virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final;
- using VkDescSetArray = std::array<VkDescriptorSet, MAX_RESOURCE_SIGNATURES * 2>;
+ virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags,
+ IResourceMapping* pResourceMapping,
+ Uint32 Flags) override final;
- struct DescriptorSetBindInfo
+ virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineResourceSignature* pPRS) const override final
{
- VkDescSetArray vkSets;
- std::vector<uint32_t> DynamicOffsets;
- const ShaderResourceCacheVk* pResourceCache = nullptr;
- Uint32 SetCout = 0;
- Uint32 DynamicOffsetCount = 0;
- bool DynamicBuffersPresent = false;
- bool DynamicDescriptorsBound = false;
-#ifdef DILIGENT_DEBUG
- //const PipelineLayoutVk* pDbgPipelineLayout = nullptr;
-#endif
- DescriptorSetBindInfo() :
- DynamicOffsets(64)
- {
- }
-
- void Reset()
- {
- pResourceCache = nullptr;
- SetCout = 0;
- DynamicOffsetCount = 0;
- DynamicBuffersPresent = false;
- DynamicDescriptorsBound = false;
-
-#ifdef DILIGENT_DEBUG
- // In release mode, do not clear vectors as this causes unnecessary work
- DynamicOffsets.clear();
-
- //pDbgPipelineLayout = nullptr;
-#endif
- }
- };
-
- void PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
- VkPipelineBindPoint BindPoint,
- const ShaderResourceCacheVk& ResourceCache,
- DescriptorSetBindInfo& BindInfo,
- VkDescriptorSet VkDynamicDescrSet) const;
-
- static VkDescriptorType GetVkDescriptorType(const PipelineResourceDesc& Res);
-
- SHADER_TYPE GetShaderStageType(Uint32 StageIndex) const;
+ return IsCompatibleWith(*ValidatedCast<const PipelineResourceSignatureVkImpl>(pPRS));
+ }
SRBMemoryAllocator& GetSRBMemoryAllocator()
{
@@ -153,25 +154,60 @@ public:
void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const;
+ static String GetPrintName(const PipelineResourceDesc& ResDesc, Uint32 ArrayInd);
+
+ void BindResource(IDeviceObject* pObj,
+ Uint32 ArrayIndex,
+ Uint32 ResIndex,
+ ShaderResourceCacheVk& ResourceCache) const;
+
+ void CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache,
+ VkDescriptorSet vkDynamicDescriptorSet) const;
+
+ bool IsCompatibleWith(const PipelineResourceSignatureVkImpl& Other) const;
+
+ bool IsIncompatibleWith(const PipelineResourceSignatureVkImpl& Other) const
+ {
+ return GetHash() != Other.GetHash();
+ }
+
private:
void Destruct();
+ void ReserveSpaceForStaticVarsMgrs(const PipelineResourceSignatureDesc& Desc,
+ FixedLinearAllocator& MemPool,
+ Int8& StaticVarStageCount,
+ Uint32& StaticVarCount,
+ Uint8 DSMapping[2]);
+
+ void CreateLayout(Uint32 StaticVarCount, const Uint8 DSMapping[2]);
+
+ Uint32 FindAssignedSampler(const PipelineResourceDesc& SepImg) const;
+
+ // returns descriptor set index in resource cache
+ Uint32 GetStaticDescrSetIndex() const;
+ Uint32 GetDynamicDescrSetIndex() const;
+
+ using ImmutableSamplerPtrType = RefCntAutoPtr<ISampler>;
+
+private:
VulkanUtilities::DescriptorSetLayoutWrapper m_VkDescSetLayouts[2];
- PackedBindingIndex* m_pBindingIndices = nullptr; // [m_Desc.NumResources]
+ ResourceAttribs* m_pResourceAttribs = nullptr; // [m_Desc.NumResources]
SHADER_TYPE m_ShaderStages = SHADER_TYPE_UNKNOWN;
- Uint16 m_DynamicBufferCount = 0;
- Uint8 m_NumShaders = 0;
+ Uint32 m_DynamicBufferCount : 29; // buffers with dynamic offsets
+ Uint32 m_NumShaders : 3;
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");
ShaderResourceCacheVk* m_pResourceCache = nullptr;
- ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; // [0..MAX_SHADERS_IN_PIPELINE]
+ ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; // [m_NumShaders]
- SRBMemoryAllocator m_SRBMemAllocator;
+ ImmutableSamplerPtrType* m_ImmutableSamplers = nullptr; // [m_Desc.NumImmutableSamplers]
+ SRBMemoryAllocator m_SRBMemAllocator;
};
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
index 46d0fc93..0c0b07b8 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
@@ -72,24 +72,13 @@ public:
/// Implementation of IPipelineStateVk::GetVkPipeline().
virtual VkPipeline DILIGENT_CALL_TYPE GetVkPipeline() const override final { return m_Pipeline; }
- /// Implementation of IPipelineState::BindStaticResources() in Vulkan backend.
- virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) override final;
-
/// Implementation of IPipelineState::GetResourceSignatureCount() in Vulkan backend.
- virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_PipelineLayout->GetSignatureCount(); }
+ virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_PipelineLayout.GetSignatureCount(); }
/// Implementation of IPipelineState::GetResourceSignature() in Vulkan backend.
- virtual IPipelineResourceSignature* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final { return m_PipelineLayout->GetSignature(Index); }
-
- __forceinline void BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
- Uint32 CtxId,
- DeviceContextVkImpl* pCtxVkImpl,
- PipelineLayoutVk::DescriptorSetBindInfo& BindInfo)
- {
- m_PipelineLayout->BindDescriptorSetsWithDynamicOffsets(CmdBuffer, CtxId, pCtxVkImpl, BindInfo);
- }
+ virtual IPipelineResourceSignature* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final { return m_PipelineLayout.GetSignature(Index); }
- const PipelineLayoutVk& GetPipelineLayout() const { return *m_PipelineLayout; }
+ const PipelineLayoutVk& GetPipelineLayout() const { return m_PipelineLayout; }
static RenderPassDesc GetImplicitRenderPassDesc(Uint32 NumRenderTargets,
const TEXTURE_FORMAT RTVFormats[],
@@ -102,11 +91,6 @@ public:
void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const;
- bool IsIncompatibleWith(IPipelineResourceSignature* pPRS) const
- {
- return !m_PipelineLayout->HasSignature(pPRS);
- }
-
struct ShaderStageInfo
{
ShaderStageInfo() {}
@@ -137,13 +121,10 @@ private:
void Destruct();
- void* m_pRawMem = nullptr; // AZ TODO: remove
+ void* m_pRawMem = nullptr; // AZ TODO: move to base class
VulkanUtilities::PipelineWrapper m_Pipeline;
- RefCntAutoPtr<PipelineLayoutVk> m_PipelineLayout;
-
- bool m_HasStaticResources = false;
- bool m_HasNonStaticResources = false;
+ PipelineLayoutVk m_PipelineLayout;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
index 2547dbb0..d67e33d2 100644
--- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
@@ -47,7 +47,6 @@
#include "VulkanUploadHeap.hpp"
#include "FramebufferCache.hpp"
#include "RenderPassCache.hpp"
-#include "PipelineLayoutCacheVk.hpp"
#include "CommandPoolManager.hpp"
#include "DXCompiler.hpp"
@@ -135,6 +134,10 @@ public:
virtual void DILIGENT_CALL_TYPE CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc,
IPipelineResourceSignature** ppSignature) override final;
+ void CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc,
+ IPipelineResourceSignature** ppSignature,
+ bool IsDeviceInternal);
+
/// Implementation of IRenderDeviceVk::GetVkDevice().
virtual VkDevice DILIGENT_CALL_TYPE GetVkDevice() override final { return m_LogicalVkDevice->GetVkDevice(); }
@@ -195,8 +198,6 @@ public:
FramebufferCache& GetFramebufferCache() { return m_FramebufferCache; }
RenderPassCache& GetImplicitRenderPassCache() { return m_ImplicitRenderPassCache; }
- PipelineLayoutCacheVk& GetPipelineLayoutCache() { return m_PipelineLayoutCache; }
-
VulkanUtilities::VulkanMemoryAllocation AllocateMemory(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProperties, VkMemoryAllocateFlags AllocateFlags = 0)
{
return m_MemoryMgr.Allocate(MemReqs, MemoryProperties, AllocateFlags);
@@ -231,7 +232,7 @@ public:
return m_Properties;
}
- void CreatePipelineLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount, PipelineLayoutVk** ppPipelineLayout);
+ IPipelineResourceSignature* GetEmptySignature() const { return m_pEmptySignature.RawPtr<IPipelineResourceSignature>(); }
private:
template <typename PSOCreateInfoType>
@@ -253,7 +254,6 @@ private:
EngineVkCreateInfo m_EngineAttribs;
FramebufferCache m_FramebufferCache;
- PipelineLayoutCacheVk m_PipelineLayoutCache;
RenderPassCache m_ImplicitRenderPassCache;
DescriptorSetAllocator m_DescriptorSetAllocator;
DescriptorPoolManager m_DynamicDescriptorPool;
@@ -271,7 +271,7 @@ private:
Properties m_Properties;
- FixedBlockMemoryAllocator m_PipelineLayoutAllocator;
+ RefCntAutoPtr<IPipelineResourceSignature> m_pEmptySignature;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
index 77ce5d8b..949bf29f 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
@@ -57,6 +57,7 @@
#include "DescriptorPoolManager.hpp"
#include "SPIRVShaderResources.hpp"
#include "BufferVkImpl.hpp"
+#include "PipelineResourceSignatureVkImpl.hpp"
namespace Diligent
{
@@ -93,13 +94,13 @@ 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, VkDescriptorType Type);
+ void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type);
// sizeof(Resource) == 16 (x64, msvc, Release)
struct Resource
{
// clang-format off
- explicit Resource(VkDescriptorType _Type) noexcept :
+ explicit Resource(DescriptorType _Type) noexcept :
Type{_Type}
{}
@@ -108,8 +109,8 @@ public:
Resource& operator = (const Resource&) = delete;
Resource& operator = (Resource&&) = delete;
-/* 0 */ const VkDescriptorType Type;
-/*4-7*/ // Unused
+/* 0 */ const DescriptorType Type;
+/*1-7*/ // Unused
/* 8 */ RefCntAutoPtr<IDeviceObject> pObject;
VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo () const;
@@ -244,27 +245,25 @@ __forceinline Uint32 ShaderResourceCacheVk::GetDynamicBufferOffsets(Uint32
for (Uint32 set = 0; set < m_NumSets; ++set)
{
const auto& DescrSet = GetDescriptorSet(set);
- Uint32 res = 0;
// AZ TODO: optimize
- while (res < DescrSet.GetSize())
+ for (Uint32 res = 0; res < DescrSet.GetSize(); ++res)
{
const auto& Res = DescrSet.GetResource(res);
- if (Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)
+ 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;
}
- if (Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
+ 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;
}
}
return OffsetInd;
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
index 6eaaf35c..68dd7807 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
@@ -83,7 +83,8 @@ public:
void Initialize(const PipelineResourceSignatureVkImpl& SrcLayout,
IMemoryAllocator& Allocator,
const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes);
+ Uint32 NumAllowedTypes,
+ SHADER_TYPE ShaderType);
~ShaderVariableManagerVk();
@@ -97,13 +98,14 @@ public:
static size_t GetRequiredMemorySize(const PipelineResourceSignatureVkImpl& Layout,
const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
Uint32 NumAllowedTypes,
+ SHADER_TYPE ShaderStages,
Uint32& NumVariables);
Uint32 GetVariableCount() const { return m_NumVariables; }
private:
friend ShaderVariableVkImpl;
- using PackedBindingIndex = PipelineResourceSignatureVkImpl::PackedBindingIndex;
+ using ResourceAttribs = PipelineResourceSignatureVkImpl::ResourceAttribs;
Uint32 GetVariableIndex(const ShaderVariableVkImpl& Variable);
@@ -112,10 +114,10 @@ private:
VERIFY_EXPR(m_pSignature);
return m_pSignature->GetResource(Index);
}
- const PackedBindingIndex& GetBinding(Uint32 Index) const
+ const ResourceAttribs& GetAttribs(Uint32 Index) const
{
VERIFY_EXPR(m_pSignature);
- return m_pSignature->GetBinding(Index);
+ return m_pSignature->GetAttribs(Index);
}
private:
@@ -144,8 +146,10 @@ private:
class ShaderVariableVkImpl final : public IShaderResourceVariable
{
public:
- explicit ShaderVariableVkImpl(ShaderVariableManagerVk& ParentManager) :
- m_ParentManager{ParentManager}
+ ShaderVariableVkImpl(ShaderVariableManagerVk& ParentManager,
+ Uint32 ResIndex) :
+ m_ParentManager{ParentManager},
+ m_ResIndex{ResIndex}
{}
// clang-format off
@@ -205,82 +209,23 @@ public:
virtual Uint32 DILIGENT_CALL_TYPE GetIndex() const override final
{
- VERIFY_EXPR(m_ParentManager.m_pVariables);
- return Uint32(size_t(this - m_ParentManager.m_pVariables));
+ return m_ParentManager.GetVariableIndex(*this);
}
virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final;
- String GetPrintName(Uint32 ArrayInd) const;
-
- RESOURCE_DIMENSION GetResourceDimension() const;
-
- bool IsMultisample() const;
-
private:
friend ShaderVariableManagerVk;
- using PackedBindingIndex = PipelineResourceSignatureVkImpl::PackedBindingIndex;
+ using ResourceAttribs = PipelineResourceSignatureVkImpl::ResourceAttribs;
- const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResource(GetIndex()); }
- const PackedBindingIndex& GetBinding() const { return m_ParentManager.GetBinding(GetIndex()); }
+ const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResource(m_ResIndex); }
+ const ResourceAttribs& GetAttribs() const { return m_ParentManager.GetAttribs(m_ResIndex); }
void BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const;
- struct UpdateInfo
- {
- ShaderResourceCacheVk::Resource& DstRes;
- const VkDescriptorSet vkDescrSet;
- const Uint32 ArrayIndex;
- const SHADER_RESOURCE_VARIABLE_TYPE VarType;
- const Uint16 Binding;
- const Uint8 SamplerInd;
- char const* const Name;
- };
-
- void CacheUniformBuffer(IDeviceObject* pBuffer,
- UpdateInfo& Info,
- Uint16& DynamicBuffersCounter) const;
-
- void CacheStorageBuffer(IDeviceObject* pBufferView,
- UpdateInfo& Info,
- Uint16& DynamicBuffersCounter) const;
-
- void CacheTexelBuffer(IDeviceObject* pBufferView,
- UpdateInfo& Info,
- Uint16& DynamicBuffersCounter) const;
-
- template <typename TCacheSampler>
- void CacheImage(IDeviceObject* pTexView,
- UpdateInfo& Info,
- TCacheSampler CacheSampler) const;
-
- void CacheSeparateSampler(IDeviceObject* pSampler,
- UpdateInfo& Info) const;
-
- void CacheInputAttachment(IDeviceObject* pTexView,
- UpdateInfo& Info) const;
-
- void CacheAccelerationStructure(IDeviceObject* pTLAS,
- UpdateInfo& Info) const;
-
- template <typename ObjectType, typename TPreUpdateObject>
- bool UpdateCachedResource(UpdateInfo& Info,
- RefCntAutoPtr<ObjectType>&& pObject,
- TPreUpdateObject PreUpdateObject) const;
-
- bool IsImmutableSamplerAssigned() const;
-
- // Updates resource descriptor in the descriptor set
- inline void UpdateDescriptorHandle(UpdateInfo& Info,
- const VkDescriptorImageInfo* pImageInfo,
- const VkDescriptorBufferInfo* pBufferInfo,
- const VkBufferView* pTexelBufferView,
- const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const;
-
- static constexpr Uint8 InvalidSamplerInd = PipelineResourceSignatureVkImpl::InvalidSamplerInd;
-
private:
ShaderVariableManagerVk& m_ParentManager;
+ const Uint32 m_ResIndex;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
index bea9f29b..958a5e80 100644
--- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -118,6 +118,8 @@ DeviceContextVkImpl::DeviceContextVkImpl(IReferenceCounters* p
m_vkClearValues.reserve(16);
+ m_DynamicBufferOffsets.reserve(64);
+
CreateASCompactedSizeQueryPool();
}
@@ -231,8 +233,6 @@ inline void DeviceContextVkImpl::DisposeCurrentCmdBuffer(Uint32 CmdQueue, Uint64
void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState)
{
auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(pPipelineState);
- BindShaderResources(pPipelineStateVk);
-
if (PipelineStateVkImpl::IsSameObject(m_pPipelineState, pPipelineStateVk))
return;
@@ -308,6 +308,8 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState)
default:
UNEXPECTED("unknown pipeline type");
}
+
+ BindShaderResources(pPipelineStateVk);
}
static Uint32 PipelineTypeToBindPointIndex(PIPELINE_TYPE Type)
@@ -338,32 +340,156 @@ void DeviceContextVkImpl::BindShaderResources(PipelineStateVkImpl* pPipelineStat
{
VERIFY_EXPR(pPipelineStateVk != nullptr);
- const auto& Layout = pPipelineStateVk->GetPipelineLayout();
- auto& Resources = m_ShaderResources[PipelineTypeToBindPointIndex(Layout.GetPipelineType())];
- auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(Layout.GetPipelineType())];
+ const auto& Layout = pPipelineStateVk->GetPipelineLayout();
+ const auto BindIndex = PipelineTypeToBindPointIndex(pPipelineStateVk->GetDesc().PipelineType);
+ auto& BindInfo = m_DescrSetBindInfo[BindIndex];
+ auto& Resources = BindInfo.Resources;
+ const auto BindPoint = PipelineTypeToBindPoint(pPipelineStateVk->GetDesc().PipelineType);
+ const auto SignCount = Layout.GetSignatureCount();
+ Uint32 CompatSignCount = SignCount;
-#ifdef DILIGENT_DEVELOPMENT
- for (Uint32 i = 0, Count = Layout.GetSignatureCount(); i < Count; ++i)
+ // Layout compatibility means that descriptor sets can be bound to a command buffer
+ // for use by any pipeline created with a compatible pipeline layout, and without having bound
+ // a particular pipeline first. It also means that descriptor sets can remain valid across
+ // a pipeline change, and the same resources will be accessible to the newly bound pipeline.
+ // (14.2.2. Pipeline Layouts, clause 'Pipeline Layout Compatibility')
+ // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#descriptorsets-compatibility
+
+ // unbind incompatible descriptor sets
+ for (Uint32 i = 0; i < SignCount; ++i)
{
auto* LayoutSign = Layout.GetSignature(i);
- auto* ResSign = Resources[i] ? Resources[i]->GetPipelineResourceSignature() : nullptr;
+ VERIFY_EXPR(LayoutSign != nullptr);
- if (LayoutSign != ResSign)
+ if (Resources[i] != nullptr && LayoutSign->IsIncompatibleWith(*Resources[i]->GetSignature()))
{
- LOG_ERROR_MESSAGE("Shader resource binding '", (ResSign ? ResSign->GetDesc().Name : ""),
- "' is not compatible with pipeline layout in current pipeline '", pPipelineStateVk->GetDesc().Name, "'.");
- Resources[i] = nullptr;
+ Resources[i] = nullptr;
+ CompatSignCount = std::min(CompatSignCount, i + 1);
}
}
+
+ // 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.PendingDynamicDescriptors[i] = false;
+ BindInfo.DynamicBuffersPresent[i] = false;
+
+#ifdef DILIGENT_DEBUG
+ 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
+ }
+}
+
+void DeviceContextVkImpl::BindDescriptorSetsWithDynamicOffsets(DescriptorSetBindInfo& BindInfo)
+{
+ auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(m_pPipelineState.RawPtr());
+ const auto& Layout = pPipelineStateVk->GetPipelineLayout();
+ const auto BindIndex = PipelineTypeToBindPointIndex(pPipelineStateVk->GetDesc().PipelineType);
+ auto& Resources = BindInfo.Resources;
+ const auto BindPoint = PipelineTypeToBindPoint(pPipelineStateVk->GetDesc().PipelineType);
+ const auto SignCount = Layout.GetSignatureCount();
+ auto& Offsets = m_DynamicBufferOffsets;
+ const auto VkLayout = Layout.GetVkPipelineLayout();
+
+ for (Uint32 i = 0; i < SignCount; ++i)
+ {
+ VERIFY_EXPR(Resources[i] != nullptr);
+
+ if ((BindInfo.PendingVkSet[i] || BindInfo.PendingDynamicDescriptors[i]) && Resources[i] != nullptr)
+ {
+ const auto* pSignature = Resources[i]->GetSignature();
+ const Uint32 DescrSetIdx = Layout.GetDescrSetIndex(pSignature);
+ const auto& ResourceCache = Resources[i]->GetResourceCache();
+ const Uint32 DSCount = ResourceCache.GetNumDescriptorSets();
+ const auto DSOffset = i * MAX_DESCR_SET_PER_SIGNATURE;
+
+#ifdef DILIGENT_DEBUG
+ for (Uint32 s = 0; s < DSCount; ++s)
+ VERIFY_EXPR(BindInfo.vkSets[DSOffset + s] != VK_NULL_HANDLE);
#endif
+ if (pSignature->GetDynamicBufferCount() > 0)
+ {
+ Offsets.resize(pSignature->GetDynamicBufferCount());
+
+ auto NumOffsetsWritten = ResourceCache.GetDynamicBufferOffsets(m_ContextId, this, Offsets);
+ VERIFY_EXPR(NumOffsetsWritten == pSignature->GetDynamicBufferCount());
+
+ // 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.
+
+ // vkCmdBindDescriptorSets causes the sets numbered [firstSet .. firstSet+descriptorSetCount-1] to use the
+ // bindings stored in pDescriptorSets[0 .. descriptorSetCount-1] for subsequent rendering commands
+ // (either compute or graphics, according to the pipelineBindPoint). Any bindings that were previously
+ // applied via these sets are no longer valid (13.2.5)
+ m_CommandBuffer.BindDescriptorSets(BindPoint, VkLayout, DescrSetIdx, DSCount, &BindInfo.vkSets[DSOffset], static_cast<Uint32>(Offsets.size()), Offsets.data());
+ BindInfo.PendingDynamicDescriptors[i] = false;
+ }
+ else
+ {
+ VERIFY_EXPR(!BindInfo.PendingDynamicDescriptors[i]);
+ m_CommandBuffer.BindDescriptorSets(BindPoint, VkLayout, DescrSetIdx, DSCount, &BindInfo.vkSets[DSOffset], 0, nullptr);
+ }
- // the number of bound descriptor sets and dynamic offsets may be greater then actually used in pipeline layout,
- // see https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#descriptorsets-compatibility
- VERIFY_EXPR(Layout.GetDescriptorSetCount() <= DescrSetBindInfo.SetCout);
- VERIFY_EXPR(Layout.GetDynamicOffsetCount() <= DescrSetBindInfo.DynamicOffsetCount);
+ BindInfo.PendingVkSet[i] = false;
+ }
+ }
- // AZ TODO: optimize - bind DS that was changed
- GetCommandBuffer().BindDescriptorSets(PipelineTypeToBindPoint(Layout.GetPipelineType()), Layout.GetVkPipelineLayout(), 0, Layout.GetDescriptorSetCount(), DescrSetBindInfo.vkSets.data(), Layout.GetDynamicOffsetCount(), DescrSetBindInfo.DynamicOffsets.data());
+ VERIFY_EXPR(!BindInfo.PendingVkSet.any());
+ VERIFY_EXPR(!BindInfo.PendingDynamicDescriptors.any());
+}
+
+void DeviceContextVkImpl::ValidateShaderResources()
+{
+#ifdef DILIGENT_DEBUG
+ auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(m_pPipelineState.RawPtr());
+ const auto& Layout = pPipelineStateVk->GetPipelineLayout();
+ const auto BindIndex = PipelineTypeToBindPointIndex(pPipelineStateVk->GetDesc().PipelineType);
+ auto& BindInfo = m_DescrSetBindInfo[BindIndex];
+ const auto SignCount = Layout.GetSignatureCount();
+
+ for (Uint32 i = 0; i < SignCount; ++i)
+ {
+ auto* LayoutSign = Layout.GetSignature(i);
+ if (LayoutSign == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Pipeline resource signature for index (", i, ") is null, this may indicate a bug");
+ return;
+ }
+
+ if (BindInfo.Resources[i] == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Shader resource binding is not bound to index (", i, ").");
+ return;
+ }
+
+ auto* ResSign = BindInfo.Resources[i]->GetSignature();
+ VERIFY_EXPR(ResSign != nullptr);
+
+ if (!LayoutSign->IsCompatibleWith(*ResSign))
+ {
+ LOG_ERROR_MESSAGE("Shader resource binding with signature '", ResSign->GetDesc().Name,
+ "' is not compatible with pipeline layout in current pipeline '", pPipelineStateVk->GetDesc().Name, "'.");
+ }
+
+ // You must call BindDescriptorSetsWithDynamicOffsets() before validation.
+ VERIFY_EXPR(!BindInfo.PendingVkSet[i]);
+ VERIFY_EXPR(!BindInfo.PendingDynamicDescriptors[i]);
+
+ const auto DSCount = LayoutSign->GetNumDescriptorSets();
+ const auto DSOffset = i * MAX_DESCR_SET_PER_SIGNATURE;
+
+ for (Uint32 s = 0; s < DSCount; ++s)
+ {
+ VERIFY(BindInfo.vkSets[DSOffset + s] != VK_NULL_HANDLE,
+ "descriptor set with index (", s, ") is not bound for resource signature '",
+ LayoutSign->GetDesc().Name, "' binding index (", i, ").");
+ }
+ }
+#endif
}
void DeviceContextVkImpl::TransitionShaderResources(IPipelineState*, IShaderResourceBinding* pShaderResourceBinding)
@@ -377,7 +503,7 @@ void DeviceContextVkImpl::TransitionShaderResources(IPipelineState*, IShaderReso
if (pShaderResourceBinding == nullptr)
{
- LOG_ERROR_MESSAGE("TODO");
+ LOG_ERROR_MESSAGE("AZ TODO");
return;
}
#endif
@@ -411,14 +537,53 @@ void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderR
}
#endif
- Uint32 Index = PipelineTypeToBindPointIndex(pResBindingVkImpl->GetPipelineType());
- auto& DescrSetBindInfo = m_DescrSetBindInfo[Index];
- auto& ResourceBinding = m_ShaderResources[Index];
+ const auto BindIndex = PipelineTypeToBindPointIndex(pResBindingVkImpl->GetPipelineType());
+ const auto Index = pResBindingVkImpl->GetBindingIndex();
+ auto& BindInfo = m_DescrSetBindInfo[BindIndex];
+ const auto* pSignature = pResBindingVkImpl->GetSignature();
+ const auto DSOffset = Index * MAX_DESCR_SET_PER_SIGNATURE;
+ const auto DSCount = ResourceCache.GetNumDescriptorSets();
+ Uint32 DSIndex = 0;
+
+ BindInfo.PendingVkSet[Index] = true;
+ BindInfo.PendingDynamicDescriptors[Index] = false;
+ BindInfo.DynamicBuffersPresent[Index] = ResourceCache.GetNumDynamicBuffers() > 0;
- // AZ TODO: create dynamic descriptor set
- (void)(DescrSetBindInfo);
+ if (pSignature->HasStaticDescrSet())
+ {
+ VERIFY_EXPR(DSIndex < DSCount);
+ BindInfo.vkSets[DSOffset + DSIndex] = ResourceCache.GetDescriptorSet(DSIndex).GetVkDescriptorSet();
+ ++DSIndex;
+ }
- ResourceBinding[pResBindingVkImpl->GetBindingIndex()] = pResBindingVkImpl;
+ if (auto VkLayout = pSignature->GetDynamicVkDescriptorSetLayout())
+ {
+ VERIFY_EXPR(DSIndex < DSCount);
+ VERIFY_EXPR(ResourceCache.GetDescriptorSet(DSIndex).GetVkDescriptorSet() == VK_NULL_HANDLE);
+
+ VkDescriptorSet DynamicDescrSet = VK_NULL_HANDLE;
+ const char* DynamicDescrSetName = "Dynamic Descriptor Set";
+#ifdef DILIGENT_DEVELOPMENT
+ String _DynamicDescrSetName("AZ TODO");
+ _DynamicDescrSetName.append(" - dynamic set");
+ DynamicDescrSetName = _DynamicDescrSetName.c_str();
+#endif
+ // Allocate vulkan descriptor set for dynamic resources
+ DynamicDescrSet = AllocateDynamicDescriptorSet(VkLayout, DynamicDescrSetName);
+
+ // Commit all dynamic resource descriptors
+ pSignature->CommitDynamicResources(ResourceCache, DynamicDescrSet);
+
+ BindInfo.vkSets[DSOffset + DSIndex] = DynamicDescrSet;
+ ++DSIndex;
+ }
+
+ if (pSignature->GetDynamicBufferCount() > 0)
+ BindInfo.PendingDynamicDescriptors[Index] = true;
+
+ VERIFY_EXPR(DSIndex == DSCount);
+
+ BindInfo.Resources[Index] = pResBindingVkImpl;
}
void DeviceContextVkImpl::SetStencilRef(Uint32 StencilRef)
@@ -558,18 +723,14 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags)
}
#endif
- auto& DescrSetBindInfo = m_DescrSetBindInfo[0];
+ auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(PIPELINE_TYPE_GRAPHICS)];
- if (DescrSetBindInfo.DynamicOffsetCount != 0)
+ // First time we must always bind descriptor sets with dynamic offsets.
+ // If there are no dynamic buffers bound in the resource cache, for all subsequent
+ // cals we do not need to bind the sets again.
+ if (DescrSetBindInfo.RequireUpdate(Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT))
{
- // First time we must always bind descriptor sets with dynamic offsets.
- // If there are no dynamic buffers bound in the resource cache, for all subsequent
- // cals we do not need to bind the sets again.
- if (!DescrSetBindInfo.DynamicDescriptorsBound ||
- (DescrSetBindInfo.DynamicBuffersPresent && (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) == 0))
- {
- m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
- }
+ BindDescriptorSetsWithDynamicOffsets(DescrSetBindInfo);
}
#if 0
# ifdef DILIGENT_DEBUG
@@ -594,6 +755,8 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags)
CommitRenderPassAndFramebuffer((Flags & DRAW_FLAG_VERIFY_STATES) != 0);
}
+
+ ValidateShaderResources();
}
BufferVkImpl* DeviceContextVkImpl::PrepareIndirectDrawAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode)
@@ -713,14 +876,11 @@ void DeviceContextVkImpl::PrepareForDispatchCompute()
if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE)
m_CommandBuffer.EndRenderPass();
- auto& DescrSetBindInfo = m_DescrSetBindInfo[1];
+ auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(PIPELINE_TYPE_COMPUTE)];
- if (DescrSetBindInfo.DynamicOffsetCount != 0)
+ if (DescrSetBindInfo.RequireUpdate())
{
- if (!DescrSetBindInfo.DynamicDescriptorsBound || DescrSetBindInfo.DynamicBuffersPresent)
- {
- m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
- }
+ BindDescriptorSetsWithDynamicOffsets(DescrSetBindInfo);
}
#if 0
# ifdef DILIGENT_DEBUG
@@ -731,21 +891,22 @@ void DeviceContextVkImpl::PrepareForDispatchCompute()
}
# endif
#endif
+
+ ValidateShaderResources();
}
void DeviceContextVkImpl::PrepareForRayTracing()
{
EnsureVkCmdBuffer();
- auto& DescrSetBindInfo = m_DescrSetBindInfo[2];
+ auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(PIPELINE_TYPE_RAY_TRACING)];
- if (DescrSetBindInfo.DynamicOffsetCount != 0)
+ if (DescrSetBindInfo.RequireUpdate())
{
- if (!DescrSetBindInfo.DynamicDescriptorsBound || DescrSetBindInfo.DynamicBuffersPresent)
- {
- m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
- }
+ BindDescriptorSetsWithDynamicOffsets(DescrSetBindInfo);
}
+
+ ValidateShaderResources();
}
void DeviceContextVkImpl::DispatchCompute(const DispatchComputeAttribs& Attribs)
@@ -1129,9 +1290,6 @@ void DeviceContextVkImpl::Flush()
for (auto& BindInfo : m_DescrSetBindInfo)
BindInfo.Reset();
- for (auto& ResourcesPerBindPoint : m_ShaderResources)
- ResourcesPerBindPoint.fill({});
-
m_State = ContextState{};
m_CommandBuffer.Reset();
m_pPipelineState = nullptr;
@@ -1172,9 +1330,6 @@ void DeviceContextVkImpl::InvalidateState()
for (auto& BindInfo : m_DescrSetBindInfo)
BindInfo.Reset();
- for (auto& ResourcesPerBindPoint : m_ShaderResources)
- ResourcesPerBindPoint.fill({});
-
VERIFY(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE, "Invalidating context with unifinished render pass");
m_CommandBuffer.Reset();
}
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp
deleted file mode 100644
index 6ca53a44..00000000
--- a/Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2019-2021 Diligent Graphics LLC
- * Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#include "PipelineLayoutCacheVk.hpp"
-#include "RenderDeviceVkImpl.hpp"
-
-namespace Diligent
-{
-
-bool PipelineLayoutCacheVk::PipelineLayoutCompare::operator()(const PipelineLayoutVk* lhs, const PipelineLayoutVk* rhs) const noexcept
-{
- if (lhs->GetSignatureCount() != rhs->GetSignatureCount())
- return false;
-
- for (Uint32 i = 0, Cnt = lhs->GetSignatureCount(); i < Cnt; ++i)
- {
- if (lhs->GetSignature(i) != rhs->GetSignature(i))
- return false;
- }
- return true;
-}
-
-PipelineLayoutCacheVk::~PipelineLayoutCacheVk()
-{
- std::lock_guard<std::mutex> Lock{m_Mutex};
- VERIFY(m_Cache.empty(), "All pipeline layouts must be released");
-}
-
-RefCntAutoPtr<PipelineLayoutVk> PipelineLayoutCacheVk::GetLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount)
-{
- RefCntAutoPtr<PipelineLayoutVk> pNewLayout;
- m_DeviceVk.CreatePipelineLayout(ppSignatures, SignatureCount, &pNewLayout);
-
- if (pNewLayout == nullptr)
- return {};
-
- std::lock_guard<std::mutex> Lock{m_Mutex};
-
- PipelineLayoutVk* pResult = *m_Cache.insert(pNewLayout).first;
-
- if (pNewLayout == pResult)
- {
- pNewLayout->Finalize();
- void(pNewLayout.Detach());
- }
- return RefCntAutoPtr<PipelineLayoutVk>{pResult};
-}
-
-void PipelineLayoutCacheVk::OnDestroyLayout(PipelineLayoutVk* pLayout)
-{
- std::lock_guard<std::mutex> Lock{m_Mutex};
-
- m_Cache.erase(pLayout);
-}
-
-} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp
index 446c41bb..376417ce 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp
@@ -39,69 +39,90 @@
namespace Diligent
{
-PipelineLayoutVk::PipelineLayoutVk(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount) :
- ObjectBase<IObject>{pRefCounters},
- m_pDeviceVk{pDeviceVk},
- m_SignatureCount{0}
+PipelineLayoutVk::PipelineLayoutVk() :
+ m_DynamicOffsetCount{0},
+ m_SignatureCount{0},
+ m_DescrSetCount{0}
{
+}
+
+void PipelineLayoutVk::Release(RenderDeviceVkImpl* pDeviceVk, Uint64 CommandQueueMask)
+{
+ pDeviceVk->SafeReleaseDeviceObject(std::move(m_VkPipelineLayout), CommandQueueMask);
+}
+
+void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount)
+{
+ VERIFY(m_DynamicOffsetCount == 0 && m_SignatureCount == 0 && m_DescrSetCount == 0,
+ "pipeline layout is already initialized");
+
for (Uint32 i = 0; i < SignatureCount; ++i)
{
- auto* pSign = ValidatedCast<PipelineResourceSignatureVkImpl>(ppSignatures[i]);
- if (pSign)
- {
- const Uint8 Index = pSign->GetDesc().BindingIndex;
+ auto* pSignature = ValidatedCast<PipelineResourceSignatureVkImpl>(ppSignatures[i]);
+ if (!pSignature)
+ LOG_ERROR_AND_THROW("pipeline resource signature (", i, ") must not be null");
- if (Index >= m_Signatures.size())
- LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' index (", Uint32{Index}, ") must be less than (", m_Signatures.size(), ").");
+ const Uint32 Index = pSignature->GetDesc().BindingIndex;
- if (m_Signatures[Index] != nullptr)
- LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' with index (", Uint32{Index}, ") overrides another resource signature '", m_Signatures[Index]->GetDesc().Name, "'.");
+ if (Index >= m_Signatures.size())
+ LOG_ERROR_AND_THROW("Pipeline resource signature '", pSignature->GetDesc().Name, "' index (", Uint32{Index}, ") must be less than (", m_Signatures.size(), ").");
- m_SignatureCount = std::max(m_SignatureCount, Uint8(Index + 1));
- m_Signatures[Index] = pSign;
+ if (m_Signatures[Index] != nullptr)
+ LOG_ERROR_AND_THROW("Pipeline resource signature '", pSignature->GetDesc().Name, "' with index (", Uint32{Index}, ") overrides another resource signature '", m_Signatures[Index]->GetDesc().Name, "'.");
- if (m_PipelineType <= PIPELINE_TYPE_LAST)
- {
- if (m_PipelineType != pSign->GetPipelineType())
- {
- LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' with index (", Uint32{Index}, ") has different pipeline type (",
- GetPipelineTypeString(pSign->GetPipelineType()), ") than other (", GetPipelineTypeString(m_PipelineType), ").");
- }
- }
- else
- m_PipelineType = pSign->GetPipelineType();
- }
+ m_SignatureCount = std::max(m_SignatureCount, Index + 1);
+ m_Signatures[Index] = pSignature;
}
-}
-PipelineLayoutVk::~PipelineLayoutVk()
-{
- m_pDeviceVk->GetPipelineLayoutCache().OnDestroyLayout(this);
- m_pDeviceVk->SafeReleaseDeviceObject(std::move(m_VkPipelineLayout), ~0ull);
-}
+ auto* pEmptySign = ValidatedCast<PipelineResourceSignatureVkImpl>(pDeviceVk->GetEmptySignature());
+
+ for (Uint32 i = 0; i < m_SignatureCount; ++i)
+ {
+ if (m_Signatures[i] == nullptr)
+ m_Signatures[i] = pEmptySign;
+ }
-void PipelineLayoutVk::Finalize()
-{
std::array<VkDescriptorSetLayout, MAX_RESOURCE_SIGNATURES * 2> DescSetLayouts;
Uint32 DescSetLayoutCount = 0;
- Uint32 DynamicBufferCount = 0;
+ Uint32 DynamicOffsetCount = 0;
+#ifdef DILIGENT_DEBUG
+ Uint32 DynamicUniformBufferCount = 0;
+ Uint32 DynamicStorageBufferCount = 0;
+#endif
for (Uint32 i = 0; i < m_SignatureCount; ++i)
{
- if (m_Signatures[i] == nullptr)
- continue;
+ const auto& pSignature = m_Signatures[i];
+ VERIFY_EXPR(pSignature != nullptr);
m_DescSetOffset[i] = static_cast<Uint8>(DescSetLayoutCount);
- m_DynBufOffset[i] = static_cast<Uint16>(DynamicBufferCount);
+ m_DynBufOffset[i] = static_cast<Uint16>(DynamicOffsetCount);
- auto StaticDSLayout = m_Signatures[i]->GetStaticVkDescriptorSetLayout();
- auto DynamicDSLayout = m_Signatures[i]->GetDynamicVkDescriptorSetLayout();
+ auto StaticDSLayout = pSignature->GetStaticVkDescriptorSetLayout();
+ auto DynamicDSLayout = pSignature->GetDynamicVkDescriptorSetLayout();
if (StaticDSLayout) DescSetLayouts[DescSetLayoutCount++] = StaticDSLayout;
if (DynamicDSLayout) DescSetLayouts[DescSetLayoutCount++] = DynamicDSLayout;
- DynamicBufferCount += m_Signatures[i]->GetDynamicBufferCount();
+ DynamicOffsetCount += pSignature->GetDynamicBufferCount();
+
+#ifdef DILIGENT_DEBUG
+ 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;
+ }
+ }
+#endif
}
VkPipelineLayoutCreateInfo PipelineLayoutCI = {};
@@ -113,14 +134,19 @@ void PipelineLayoutVk::Finalize()
PipelineLayoutCI.pSetLayouts = DescSetLayoutCount ? DescSetLayouts.data() : nullptr;
PipelineLayoutCI.pushConstantRangeCount = 0;
PipelineLayoutCI.pPushConstantRanges = nullptr;
- m_VkPipelineLayout = m_pDeviceVk->GetLogicalDevice().CreatePipelineLayout(PipelineLayoutCI);
+ m_VkPipelineLayout = pDeviceVk->GetLogicalDevice().CreatePipelineLayout(PipelineLayoutCI);
- const auto& Limits = m_pDeviceVk->GetPhysicalDevice().GetProperties().limits;
+ const auto& Limits = pDeviceVk->GetPhysicalDevice().GetProperties().limits;
VERIFY_EXPR(DescSetLayoutCount <= Limits.maxBoundDescriptorSets);
- VERIFY_EXPR(DynamicBufferCount <= (Limits.maxDescriptorSetUniformBuffersDynamic + Limits.maxDescriptorSetStorageBuffersDynamic)); // AZ TODO
+ VERIFY_EXPR(DescSetLayoutCount <= MAX_RESOURCE_SIGNATURES * 2);
+
+#ifdef DILIGENT_DEBUG
+ VERIFY_EXPR(DynamicUniformBufferCount <= Limits.maxDescriptorSetUniformBuffersDynamic);
+ VERIFY_EXPR(DynamicStorageBufferCount <= Limits.maxDescriptorSetStorageBuffersDynamic);
+#endif
m_DescrSetCount = static_cast<Uint8>(DescSetLayoutCount);
- m_DynamicOffsetCount = static_cast<Uint16>(DynamicBufferCount);
+ m_DynamicOffsetCount = DynamicOffsetCount;
}
size_t PipelineLayoutVk::GetHash() const
@@ -129,10 +155,8 @@ size_t PipelineLayoutVk::GetHash() const
HashCombine(hash, m_SignatureCount);
for (Uint32 i = 0; i < m_SignatureCount; ++i)
{
- if (m_Signatures[i] != nullptr)
- HashCombine(hash, m_Signatures[i]->GetHash());
- else
- HashCombine(hash, 0);
+ VERIFY_EXPR(m_Signatures[i] != nullptr);
+ HashCombine(hash, m_Signatures[i]->GetHash());
}
return hash;
}
@@ -140,27 +164,22 @@ size_t PipelineLayoutVk::GetHash() const
bool PipelineLayoutVk::GetResourceInfo(const char* Name, SHADER_TYPE Stage, ResourceInfo& Info) const
{
// AZ TODO: optimize
- for (Uint32 i = 0, Count = GetSignatureCount(); i < Count; ++i)
+ for (Uint32 i = 0, DSCount = GetSignatureCount(); i < DSCount; ++i)
{
- auto* pSign = GetSignature(i);
- if (pSign)
+ auto* pSignature = GetSignature(i);
+ VERIFY_EXPR(pSignature != nullptr);
+
+ for (Uint32 r = 0, ResCount = pSignature->GetTotalResourceCount(); r < ResCount; ++r)
{
- auto& Desc = pSign->GetDesc();
- Uint32 BindingCount[2] = {};
+ const auto& Res = pSignature->GetResource(r);
+ const auto& Attr = pSignature->GetAttribs(r);
- for (Uint32 j = 0; j < Desc.NumResources; ++j)
+ if ((Res.ShaderStages & Stage) && strcmp(Res.Name, Name) == 0)
{
- auto& Res = Desc.Resources[j];
- Uint16 DSIndex = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0);
-
- if ((Res.ShaderStages & Stage) && strcmp(Res.Name, Name) == 0)
- {
- Info.Type = Res.ResourceType;
- Info.BindingIndex = static_cast<Uint16>(BindingCount[DSIndex]);
- Info.DescrSetIndex = m_DescSetOffset[i] + DSIndex;
- return true;
- }
- BindingCount[DSIndex] += Res.ArraySize;
+ Info.Type = Res.ResourceType;
+ Info.BindingIndex = static_cast<Uint16>(Attr.BindingIndex);
+ Info.DescrSetIndex = m_DescSetOffset[i] + Attr.DescrSet;
+ return true;
}
}
}
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp
index da646a96..8513a161 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp
@@ -30,124 +30,231 @@
#include "ShaderResourceBindingVkImpl.hpp"
#include "RenderDeviceVkImpl.hpp"
#include "VulkanTypeConversions.hpp"
+#include "SamplerVkImpl.hpp"
+#include "TextureViewVkImpl.hpp"
+#include "TopLevelASVkImpl.hpp"
+#include "BasicMath.hpp"
+#include "DynamicLinearAllocator.hpp"
namespace Diligent
{
+namespace
+{
+VkDescriptorType GetVkDescriptorType(DescriptorType Type)
+{
+ static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "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::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;
+ 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;
+ }
+}
-VkDescriptorType PipelineResourceSignatureVkImpl::GetVkDescriptorType(const PipelineResourceDesc& Res)
+DescriptorType GetDescriptorType(const PipelineResourceDesc& Res)
{
const bool WithDynamicOffset = !(Res.Flags & PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS);
const bool CombinedSampler = (Res.Flags & PIPELINE_RESOURCE_FLAG_COMBINED_IMAGE);
const bool UseTexelBuffer = (Res.Flags & PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER);
- VERIFY_EXPR(WithDynamicOffset ^ UseTexelBuffer);
- VERIFY_EXPR(CombinedSampler ? !(WithDynamicOffset | UseTexelBuffer) : true);
-
static_assert(SHADER_RESOURCE_TYPE_LAST == SHADER_RESOURCE_TYPE_ACCEL_STRUCT, "Please update the switch below to handle the new shader resource type");
switch (Res.ResourceType)
{
+ case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER:
+ VERIFY_EXPR(!(Res.Flags & ~PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS));
+ return WithDynamicOffset ? DescriptorType::UniformBufferDynamic : DescriptorType::UniformBuffer;
+
+ case SHADER_RESOURCE_TYPE_BUFFER_UAV:
+ VERIFY_EXPR(!(Res.Flags & ~(PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS | PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER)));
+ return UseTexelBuffer ? DescriptorType::StorageTexelBuffer :
+ (WithDynamicOffset ? DescriptorType::StorageBufferDynamic : DescriptorType::StorageBuffer);
+
+ case SHADER_RESOURCE_TYPE_TEXTURE_SRV:
+ VERIFY_EXPR(!(Res.Flags & ~PIPELINE_RESOURCE_FLAG_COMBINED_IMAGE));
+ return CombinedSampler ? DescriptorType::CombinedImageSampler : DescriptorType::SeparateImage;
+
+ case SHADER_RESOURCE_TYPE_BUFFER_SRV:
+ VERIFY_EXPR(!(Res.Flags & ~(PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS | PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER)));
+ return UseTexelBuffer ? DescriptorType::UniformTexelBuffer :
+ (WithDynamicOffset ? DescriptorType::StorageBufferDynamic_ReadOnly : DescriptorType::StorageBuffer_ReadOnly);
+
+ case SHADER_RESOURCE_TYPE_TEXTURE_UAV:
+ VERIFY_EXPR(!Res.Flags);
+ return DescriptorType::StorageImage;
+
+ case SHADER_RESOURCE_TYPE_SAMPLER:
+ VERIFY_EXPR(!Res.Flags);
+ return DescriptorType::Sampler;
+
+ case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT:
+ VERIFY_EXPR(!Res.Flags);
+ return DescriptorType::InputAttachment;
+
+ case SHADER_RESOURCE_TYPE_ACCEL_STRUCT:
+ VERIFY_EXPR(!Res.Flags);
+ return DescriptorType::AccelerationStructure;
+
+ default:
+ UNEXPECTED("unknown resource type");
+ return DescriptorType::Unknown;
+ }
+}
+
+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");
+ switch (Type)
+ {
+ // clang-format off
+ 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;
+ // clang-format on
+ default:
+ UNEXPECTED("unsupported descriptor type for buffer view");
+ return BUFFER_VIEW_UNDEFINED;
+ }
+}
+
+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");
+ switch (Type)
+ {
// clang-format off
- case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER: return WithDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- case SHADER_RESOURCE_TYPE_BUFFER_UAV: return UseTexelBuffer ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : (WithDynamicOffset ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
- case SHADER_RESOURCE_TYPE_TEXTURE_SRV: return CombinedSampler ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
- case SHADER_RESOURCE_TYPE_BUFFER_SRV: return UseTexelBuffer ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : (WithDynamicOffset ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
- case SHADER_RESOURCE_TYPE_TEXTURE_UAV: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- case SHADER_RESOURCE_TYPE_SAMPLER: return VK_DESCRIPTOR_TYPE_SAMPLER;
- case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT: return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
- case SHADER_RESOURCE_TYPE_ACCEL_STRUCT: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
- default: UNEXPECTED("unknown resource type");
+ 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:
+ UNEXPECTED("unsupported descriptor type for texture view");
+ return TEXTURE_VIEW_UNDEFINED;
}
- return VK_DESCRIPTOR_TYPE_MAX_ENUM;
}
+Int32 FindImmutableSampler(const PipelineResourceDesc& Res,
+ DescriptorType DescType,
+ const PipelineResourceSignatureDesc& Desc,
+ const char* SamplerSuffix)
+{
+ if (DescType == DescriptorType::CombinedImageSampler)
+ {
+ SamplerSuffix = nullptr;
+ }
+ else if (DescType == DescriptorType::Sampler)
+ {
+ // Use SamplerSuffix. If HLSL-style combined images samplers are not used,
+ // SamplerSuffix will be null and we will be looking for the sampler itself.
+ }
+ else
+ {
+ UNEXPECTED("Immutable sampler can only be assigned to a sampled image or separate sampler");
+ return -1;
+ }
+
+ for (Uint32 s = 0; s < Desc.NumImmutableSamplers; ++s)
+ {
+ const auto& ImtblSam = Desc.ImmutableSamplers[s];
+ if (((ImtblSam.ShaderStages & Res.ShaderStages) != 0) && StreqSuff(Res.Name, ImtblSam.SamplerOrTextureName, SamplerSuffix))
+ {
+ VERIFY_EXPR((ImtblSam.ShaderStages & Res.ShaderStages) == Res.ShaderStages);
+ return s;
+ }
+ }
+
+ return -1;
+}
+} // namespace
+
+
+RESOURCE_STATE DescriptorTypeToResourceState(DescriptorType Type)
+{
+ static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type");
+ switch (Type)
+ {
+ // clang-format off
+ case DescriptorType::Sampler: return RESOURCE_STATE_UNKNOWN;
+ 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;
+ case DescriptorType::UniformBuffer: return RESOURCE_STATE_CONSTANT_BUFFER;
+ case DescriptorType::UniformBufferDynamic: return RESOURCE_STATE_CONSTANT_BUFFER;
+ case DescriptorType::StorageBuffer: return RESOURCE_STATE_UNORDERED_ACCESS;
+ case DescriptorType::StorageBuffer_ReadOnly: return RESOURCE_STATE_SHADER_RESOURCE;
+ case DescriptorType::StorageBufferDynamic: return RESOURCE_STATE_UNORDERED_ACCESS;
+ case DescriptorType::StorageBufferDynamic_ReadOnly: return RESOURCE_STATE_SHADER_RESOURCE;
+ case DescriptorType::InputAttachment: return RESOURCE_STATE_SHADER_RESOURCE;
+ case DescriptorType::AccelerationStructure: return RESOURCE_STATE_SHADER_RESOURCE;
+ // clang-format on
+ default:
+ UNEXPECTED("unknown descriptor type");
+ return RESOURCE_STATE_UNKNOWN;
+ }
+}
+
+
+#define LOG_PRS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a pipeline resource signature '", (Desc.Name ? 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_SRBMemAllocator{GetRawAllocator()},
+ m_DynamicBufferCount{0},
+ m_NumShaders{0}
{
-#define LOG_PRS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a pipeline resource signature '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
-
try
{
FixedLinearAllocator MemPool{GetRawAllocator()};
- MemPool.AddSpace<PackedBindingIndex>(Desc.NumResources);
+ // reserve at least 1 element because m_pResourceAttribs must hold pointer to memory
+ MemPool.AddSpace<ResourceAttribs>(std::max(1u, Desc.NumResources));
+ MemPool.AddSpace<ImmutableSamplerPtrType>(Desc.NumImmutableSamplers);
ReserveSpaceForDescription(MemPool, Desc);
Int8 StaticVarStageCount = 0;
Uint32 StaticVarCount = 0;
- {
- // get active shader stages
- SHADER_TYPE Stages = SHADER_TYPE_UNKNOWN;
- SHADER_TYPE StaticResStages = SHADER_TYPE_UNKNOWN;
-
- for (Uint32 i = 0; i < Desc.NumResources; ++i)
- {
- const auto& Res = Desc.Resources[i];
- Stages |= Res.ShaderStages;
-
- if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
- {
- StaticResStages |= Res.ShaderStages;
- StaticVarCount += Res.ArraySize;
- }
- }
-
- m_ShaderStages = Stages;
- m_NumShaders = static_cast<Uint8>(PlatformMisc::CountOneBits(static_cast<Uint32>(Stages)));
-
- if (Stages == SHADER_TYPE_COMPUTE)
- {
- m_PipelineType = PIPELINE_TYPE_COMPUTE;
- }
- else if (Stages & (SHADER_TYPE_AMPLIFICATION | SHADER_TYPE_MESH))
- {
- m_PipelineType = PIPELINE_TYPE_MESH;
- }
- else if (Stages < SHADER_TYPE_COMPUTE)
- {
- m_PipelineType = PIPELINE_TYPE_GRAPHICS;
- }
- else if (Stages >= SHADER_TYPE_RAY_GEN)
- {
- m_PipelineType = PIPELINE_TYPE_RAY_TRACING;
- }
- else
- {
- LOG_PRS_ERROR_AND_THROW("can not deduce pipeline type - used incompatible shader stages");
- }
-
- m_StaticVarIndex.fill(-1);
-
- for (; StaticResStages != SHADER_TYPE_UNKNOWN; ++StaticVarStageCount)
- {
- auto StageBit = static_cast<SHADER_TYPE>(1 << PlatformMisc::GetLSB(Uint32{StaticResStages}));
- StaticResStages = StaticResStages & ~StageBit;
-
- const auto ShaderTypeInd = GetShaderTypePipelineIndex(StageBit, m_PipelineType);
- m_StaticVarIndex[ShaderTypeInd] = StaticVarStageCount;
- }
-
- if (StaticVarStageCount > 0)
- {
- MemPool.AddSpace<ShaderResourceCacheVk>(1);
- MemPool.AddSpace<ShaderVariableManagerVk>(StaticVarStageCount);
- }
- }
-
+ Uint8 DSMapping[2] = {};
+ ReserveSpaceForStaticVarsMgrs(Desc, MemPool, StaticVarStageCount, StaticVarCount, DSMapping);
MemPool.Reserve();
-
- m_pBindingIndices = MemPool.Allocate<PackedBindingIndex>(m_Desc.NumResources);
+ m_pResourceAttribs = MemPool.ConstructArray<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().
auto* Ptr = MemPool.ReleaseOwnership();
- VERIFY_EXPR(Ptr == m_pBindingIndices);
+ VERIFY_EXPR(Ptr == m_pResourceAttribs);
(void)Ptr;
CopyDescription(MemPool, Desc);
@@ -161,79 +268,245 @@ PipelineResourceSignatureVkImpl::PipelineResourceSignatureVkImpl(IReferenceCount
const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
- for (Int8 i = 0; i < StaticVarStageCount; ++i)
+ for (Uint32 i = 0; i < m_StaticVarIndex.size(); ++i)
{
- new (m_StaticVarsMgrs + i) ShaderVariableManagerVk{*this, *m_pResourceCache};
- m_StaticVarsMgrs[i].Initialize(*this, GetRawAllocator(), AllowedVarTypes, _countof(AllowedVarTypes));
+ Int8 Idx = m_StaticVarIndex[i];
+ if (Idx >= 0)
+ {
+ VERIFY_EXPR(Idx < StaticVarStageCount);
+ const auto ShaderType = GetShaderTypeFromPipelineIndex(i, GetPipelineType());
+ new (m_StaticVarsMgrs + Idx) ShaderVariableManagerVk{*this, *m_pResourceCache};
+ m_StaticVarsMgrs[Idx].Initialize(*this, GetRawAllocator(), AllowedVarTypes, _countof(AllowedVarTypes), ShaderType);
+ }
}
}
- std::vector<VkDescriptorSetLayoutBinding> LayoutBindings[2];
+ CreateLayout(StaticVarCount, DSMapping);
+ }
+ catch (...)
+ {
+ Destruct();
+ throw;
+ }
+}
- for (Uint32 i = 0; i < m_Desc.NumResources; ++i)
+void PipelineResourceSignatureVkImpl::ReserveSpaceForStaticVarsMgrs(const PipelineResourceSignatureDesc& Desc,
+ FixedLinearAllocator& MemPool,
+ Int8& StaticVarStageCount,
+ Uint32& StaticVarCount,
+ Uint8 DSMapping[2])
+{
+ // 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];
+ Stages |= Res.ShaderStages;
+
+ if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
{
- const auto& Res = m_Desc.Resources[i];
- auto& Binding = m_pBindingIndices[i];
+ StaticResStages |= Res.ShaderStages;
+ StaticVarCount += Res.ArraySize;
+ }
- Binding.DescSet = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0);
- Binding.Binding = static_cast<Uint16>(LayoutBindings[Binding.DescSet].size());
- Binding.SamplerInd = 0; // AZ TODO
+ VarExist[Res.VarType] = true;
+ }
- LayoutBindings[Binding.DescSet].emplace_back();
- auto& LayoutBinding = LayoutBindings[Binding.DescSet].back();
+ // 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;
+ }
- LayoutBinding.binding = Binding.Binding;
- LayoutBinding.descriptorCount = Res.ArraySize;
- LayoutBinding.stageFlags = ShaderTypesToVkShaderStageFlags(Res.ShaderStages);
- LayoutBinding.pImmutableSamplers = nullptr;
- LayoutBinding.descriptorType = GetVkDescriptorType(Res);
+ m_ShaderStages = Stages;
+ m_NumShaders = PlatformMisc::CountOneBits(static_cast<Uint32>(Stages));
- if (!(Res.Flags & PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS))
- m_DynamicBufferCount += static_cast<Uint16>(Res.ArraySize);
+ if (Stages == SHADER_TYPE_COMPUTE)
+ {
+ m_PipelineType = PIPELINE_TYPE_COMPUTE;
+ }
+ else if (Stages & (SHADER_TYPE_AMPLIFICATION | SHADER_TYPE_MESH))
+ {
+ m_PipelineType = PIPELINE_TYPE_MESH;
+ }
+ else if (Stages < SHADER_TYPE_COMPUTE)
+ {
+ m_PipelineType = PIPELINE_TYPE_GRAPHICS;
+ }
+ else if (Stages >= SHADER_TYPE_RAY_GEN)
+ {
+ m_PipelineType = PIPELINE_TYPE_RAY_TRACING;
+ }
+ else
+ {
+ LOG_PRS_ERROR_AND_THROW("can not deduce pipeline type - used incompatible shader stages");
+ }
- if (m_pResourceCache && Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
- m_pResourceCache->InitializeResources(0, Binding.Binding, Res.ArraySize, LayoutBinding.descriptorType);
- }
+ m_StaticVarIndex.fill(-1);
- if (m_Desc.SRBAllocationGranularity > 1)
- {
- const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
+ for (; StaticResStages != SHADER_TYPE_UNKNOWN; ++StaticVarStageCount)
+ {
+ const auto StageBit = ExtractBit(StaticResStages);
+ 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
- Uint32 UnusedNumVars = 0;
- const size_t ShaderVariableDataSize = ShaderVariableManagerVk::GetRequiredMemorySize(*this, AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars);
+void PipelineResourceSignatureVkImpl::CreateLayout(Uint32 StaticVarCount, const Uint8 DSMapping[2])
+{
+ std::vector<VkDescriptorSetLayoutBinding> LayoutBindings[2];
+ DynamicLinearAllocator TempAllocator{GetRawAllocator()};
+
+ Uint32 CacheOffsets[Uint32{SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES}] = {0, StaticVarCount, 0};
+
+ for (Uint32 i = 0; i < m_Desc.NumResources; ++i)
+ {
+ const auto& Res = m_Desc.Resources[i];
+ auto& Attribs = m_pResourceAttribs[i];
+ auto& CacheOffset = CacheOffsets[Uint32{Res.VarType}];
+ const Uint32 SetIdx = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0);
+
+ // 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);
+
+ Attribs.DescrSet = DSMapping[SetIdx];
+ Attribs.BindingIndex = static_cast<Uint16>(LayoutBindings[SetIdx].size());
+ Attribs.CacheOffset = CacheOffset;
+ Attribs.Type = GetDescriptorType(Res);
+
+ CacheOffset += Res.ArraySize;
+
+ LayoutBindings[SetIdx].emplace_back();
+ auto& LayoutBinding = LayoutBindings[SetIdx].back();
- const Uint32 NumSets = !LayoutBindings[0].empty() + !LayoutBindings[1].empty();
- const Uint32 DescriptorSetSizes[] = {static_cast<Uint32>(LayoutBindings[0].size()), static_cast<Uint32>(LayoutBindings[1].size())};
- const size_t CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes);
+ LayoutBinding.binding = Attribs.BindingIndex;
+ LayoutBinding.descriptorCount = Res.ArraySize;
+ LayoutBinding.stageFlags = ShaderTypesToVkShaderStageFlags(Res.ShaderStages);
+ LayoutBinding.pImmutableSamplers = nullptr;
+ LayoutBinding.descriptorType = GetVkDescriptorType(Attribs.Type);
- m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, 1, &ShaderVariableDataSize, 1, &CacheMemorySize);
+ if (Attribs.Type == DescriptorType::SeparateImage)
+ {
+ Attribs.SamplerInd = FindAssignedSampler(Res);
}
- VkDescriptorSetLayoutCreateInfo SetLayoutCI = {};
+ 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());
+ if (SrcImmutableSamplerInd >= 0)
+ {
+ auto& ImmutableSampler = m_ImmutableSamplers[SrcImmutableSamplerInd];
+ const auto& ImmutableSamplerDesc = m_Desc.ImmutableSamplers[SrcImmutableSamplerInd].Desc;
+ 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;
+ }
+ }
- SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- SetLayoutCI.pNext = nullptr;
- SetLayoutCI.flags = 0;
+ if (Attribs.Type == DescriptorType::UniformBufferDynamic ||
+ Attribs.Type == DescriptorType::StorageBufferDynamic ||
+ Attribs.Type == DescriptorType::StorageBufferDynamic_ReadOnly)
+ {
+ m_DynamicBufferCount += Res.ArraySize;
+ }
- const auto& LogicalDevice = pDevice->GetLogicalDevice();
+ if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
+ m_pResourceCache->InitializeResources(Attribs.DescrSet, Attribs.CacheOffset, Res.ArraySize, Attribs.Type);
+ }
+ VERIFY_EXPR(CacheOffsets[0] == StaticVarCount);
- for (Uint32 i = 0; i < _countof(LayoutBindings); ++i)
+ if (m_Desc.SRBAllocationGranularity > 1)
+ {
+ std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {};
+ for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
{
- auto& LayoutBinding = LayoutBindings[i];
- if (LayoutBinding.empty())
- continue;
+ const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
- SetLayoutCI.bindingCount = static_cast<Uint32>(LayoutBinding.size());
- SetLayoutCI.pBindings = LayoutBinding.data();
- m_VkDescSetLayouts[i] = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI);
+ Uint32 UnusedNumVars = 0;
+ 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]};
+ const Uint32 NumSets = !!DescriptorSetSizes[0] + !!DescriptorSetSizes[1];
+
+ if (DescriptorSetSizes[0] == 0)
+ DescriptorSetSizes[0] = DescriptorSetSizes[1];
+
+ const size_t CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes);
+
+ m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderVariableDataSizes.data(), 1, &CacheMemorySize);
}
- catch (...)
+
+ VkDescriptorSetLayoutCreateInfo SetLayoutCI = {};
+
+ SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ SetLayoutCI.pNext = nullptr;
+ SetLayoutCI.flags = 0;
+
+ const auto& LogicalDevice = GetDevice()->GetLogicalDevice();
+
+ for (Uint32 i = 0; i < _countof(LayoutBindings); ++i)
{
- Destruct();
- throw;
+ auto& LayoutBinding = LayoutBindings[i];
+ if (LayoutBinding.empty())
+ continue;
+
+ SetLayoutCI.bindingCount = static_cast<Uint32>(LayoutBinding.size());
+ SetLayoutCI.pBindings = LayoutBinding.data();
+ m_VkDescSetLayouts[i] = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI);
}
-#undef LOG_PRS_ERROR_AND_THROW
+}
+
+Uint32 PipelineResourceSignatureVkImpl::FindAssignedSampler(const PipelineResourceDesc& SepImg) const
+{
+ Uint32 SamplerInd = InvalidSamplerInd;
+ if (IsUsingCombinedSamplers())
+ {
+ for (Uint32 i = 0; i < m_Desc.NumResources; ++i)
+ {
+ const auto& Res = m_Desc.Resources[i];
+
+ if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER &&
+ SepImg.VarType == Res.VarType &&
+ (SepImg.ShaderStages & Res.ShaderStages) &&
+ StreqSuff(Res.Name, SepImg.Name, GetCombinedSamplerSuffix()))
+ {
+ VERIFY_EXPR((Res.ShaderStages & SepImg.ShaderStages) == SepImg.ShaderStages);
+ SamplerInd = i;
+ break;
+ }
+ }
+ }
+ return SamplerInd;
}
PipelineResourceSignatureVkImpl::~PipelineResourceSignatureVkImpl()
@@ -251,21 +524,25 @@ void PipelineResourceSignatureVkImpl::Destruct()
m_pDevice->SafeReleaseDeviceObject(std::move(Layout), ~0ull);
}
- if (m_pBindingIndices == nullptr)
+ if (m_pResourceAttribs == nullptr)
return; // memory is not allocated
auto& RawAllocator = GetRawAllocator();
- for (size_t i = 0; m_StaticVarsMgrs && i < m_StaticVarIndex.size(); ++i)
+ if (m_StaticVarsMgrs != nullptr)
{
- Int8 Idx = m_StaticVarIndex[i];
- if (Idx >= 0)
+ for (size_t i = 0; i < m_StaticVarIndex.size(); ++i)
{
- m_StaticVarsMgrs[Idx].DestroyVariables(RawAllocator);
- m_StaticVarsMgrs[Idx].~ShaderVariableManagerVk();
+ Int8 Idx = m_StaticVarIndex[i];
+ if (Idx >= 0)
+ {
+ m_StaticVarsMgrs[Idx].DestroyVariables(RawAllocator);
+ m_StaticVarsMgrs[Idx].~ShaderVariableManagerVk();
+ }
}
+ m_StaticVarIndex.fill(-1);
+ m_StaticVarsMgrs = nullptr;
}
- m_StaticVarsMgrs = nullptr;
if (m_pResourceCache != nullptr)
{
@@ -273,93 +550,78 @@ void PipelineResourceSignatureVkImpl::Destruct()
m_pResourceCache = nullptr;
}
- if (void* pRawMem = m_pBindingIndices)
+ for (Uint32 i = 0; i < m_Desc.NumImmutableSamplers; ++i)
+ {
+ m_ImmutableSamplers[i].~ImmutableSamplerPtrType();
+ }
+ m_ImmutableSamplers = nullptr;
+
+ if (void* pRawMem = m_pResourceAttribs)
{
RawAllocator.Free(pRawMem);
- m_pBindingIndices = nullptr;
+ m_pResourceAttribs = nullptr;
}
}
-void PipelineResourceSignatureVkImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding,
- bool InitStaticResources)
+bool PipelineResourceSignatureVkImpl::IsCompatibleWith(const PipelineResourceSignatureVkImpl& Other) const
{
- auto& SRBAllocator = m_pDevice->GetSRBAllocator();
- auto pResBindingVk = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl)(this, false);
- if (InitStaticResources)
- pResBindingVk->InitializeStaticResources(nullptr);
- pResBindingVk->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
-}
+ if (this == &Other)
+ return true;
-void PipelineResourceSignatureVkImpl::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
- VkPipelineBindPoint BindPoint,
- const ShaderResourceCacheVk& ResourceCache,
- DescriptorSetBindInfo& BindInfo,
- VkDescriptorSet VkDynamicDescrSet) const
-{
- /*
-#ifdef DILIGENT_DEBUG
- BindInfo.vkSets.clear();
-#endif
+ if (GetHash() != Other.GetHash())
+ return false;
+
+ if (GetDesc().BindingIndex != Other.GetDesc().BindingIndex)
+ return false;
- // Do not use vector::resize for BindInfo.vkSets and BindInfo.DynamicOffsets as this
- // causes unnecessary work to zero-initialize new elements
+ const Uint32 LCount = GetTotalResourceCount();
+ const Uint32 RCount = Other.GetTotalResourceCount();
- VERIFY(m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC).SetIndex == m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE).SetIndex,
- "Static and mutable variables are expected to share the same descriptor set");
- Uint32 TotalDynamicDescriptors = 0;
+ if (LCount != RCount)
+ return false;
- BindInfo.SetCout = 0;
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
+ for (Uint32 r = 0; r < LCount; ++r)
{
- const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType);
- if (Set.SetIndex >= 0)
+ 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)
{
- BindInfo.SetCout = std::max(BindInfo.SetCout, static_cast<Uint32>(Set.SetIndex + 1));
- if (BindInfo.SetCout > BindInfo.vkSets.size())
- BindInfo.vkSets.resize(BindInfo.SetCout);
- VERIFY_EXPR(BindInfo.vkSets[Set.SetIndex] == VK_NULL_HANDLE);
- if (VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
- BindInfo.vkSets[Set.SetIndex] = ResourceCache.GetDescriptorSet(Set.SetIndex).GetVkDescriptorSet();
- else
- {
- VERIFY_EXPR(ResourceCache.GetDescriptorSet(Set.SetIndex).GetVkDescriptorSet() == VK_NULL_HANDLE);
- BindInfo.vkSets[Set.SetIndex] = VkDynamicDescrSet;
- }
- VERIFY(BindInfo.vkSets[Set.SetIndex] != VK_NULL_HANDLE, "Descriptor set must not be null");
+ return false;
}
- TotalDynamicDescriptors += Set.NumDynamicDescriptors;
}
-#ifdef DILIGENT_DEBUG
- for (const auto& set : BindInfo.vkSets)
- VERIFY(set != VK_NULL_HANDLE, "Descriptor set must not be null");
-#endif
+ const Uint32 LSampCount = GetDesc().NumImmutableSamplers;
+ const Uint32 RSampCount = Other.GetDesc().NumImmutableSamplers;
- BindInfo.DynamicOffsetCount = TotalDynamicDescriptors;
- if (TotalDynamicDescriptors > BindInfo.DynamicOffsets.size())
- BindInfo.DynamicOffsets.resize(TotalDynamicDescriptors);
- BindInfo.BindPoint = BindPoint;
- BindInfo.pResourceCache = &ResourceCache;
-#ifdef DILIGENT_DEBUG
- BindInfo.pDbgPipelineLayout = this;
-#endif
- BindInfo.DynamicBuffersPresent = ResourceCache.GetNumDynamicBuffers() > 0;
+ if (LSampCount != RSampCount)
+ return false;
- if (TotalDynamicDescriptors == 0)
+ for (Uint32 s = 0; s < LSampCount; ++s)
{
- // There are no dynamic descriptors, so we can bind descriptor sets right now
- auto& CmdBuffer = pCtxVkImpl->GetCommandBuffer();
- CmdBuffer.BindDescriptorSets(BindInfo.BindPoint,
- m_LayoutMgr.GetVkPipelineLayout(),
- 0, // First set
- BindInfo.SetCout,
- BindInfo.vkSets.data(), // BindInfo.vkSets is never empty
- 0,
- nullptr);
+ const auto& LSamp = GetDesc().ImmutableSamplers[s];
+ const auto& RSamp = Other.GetDesc().ImmutableSamplers[s];
+
+ if (LSamp.ShaderStages != RSamp.ShaderStages ||
+ !(LSamp.Desc == RSamp.Desc))
+ return false;
}
- BindInfo.DynamicDescriptorsBound = false;
- */
+ return true;
+}
+
+void PipelineResourceSignatureVkImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding,
+ bool InitStaticResources)
+{
+ auto& SRBAllocator = m_pDevice->GetSRBAllocator();
+ auto pResBindingVk = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl)(this, false);
+ if (InitStaticResources)
+ pResBindingVk->InitializeStaticResources(nullptr);
+ pResBindingVk->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
}
Uint32 PipelineResourceSignatureVkImpl::GetStaticVariableCount(SHADER_TYPE ShaderType) const
@@ -392,21 +654,48 @@ IShaderResourceVariable* PipelineResourceSignatureVkImpl::GetStaticVariableByInd
return StaticVarMgr.GetVariable(Index);
}
+void PipelineResourceSignatureVkImpl::BindStaticResources(Uint32 ShaderFlags,
+ IResourceMapping* pResMapping,
+ Uint32 Flags)
+{
+ const auto PipelineType = GetPipelineType();
+ for (Uint32 ShaderInd = 0; ShaderInd < m_StaticVarIndex.size(); ++ShaderInd)
+ {
+ const auto VarMngrInd = m_StaticVarIndex[ShaderInd];
+ if (VarMngrInd >= 0)
+ {
+ // ShaderInd is the shader type pipeline index here
+ const auto ShaderType = GetShaderTypeFromPipelineIndex(ShaderInd, PipelineType);
+ if (ShaderFlags & ShaderType)
+ {
+ m_StaticVarsMgrs[VarMngrInd].BindResources(pResMapping, Flags);
+ }
+ }
+ }
+}
+
void PipelineResourceSignatureVkImpl::InitResourceCache(ShaderResourceCacheVk& ResourceCache,
IMemoryAllocator& CacheMemAllocator,
const char* DbgPipelineName) const
{
std::array<Uint32, 2> VarCount = {};
+ Uint32 NumSets = static_cast<Uint32>(VarCount.size());
+
for (Uint32 r = 0; r < m_Desc.NumResources; ++r)
{
const auto& Res = GetResource(r);
- const auto& Bind = GetBinding(r);
- VarCount[Bind.DescSet] += Res.ArraySize;
+ const auto& Attr = GetAttribs(r);
+ VarCount[Attr.DescrSet] += Res.ArraySize;
}
+ if (VarCount[1] == 0)
+ --NumSets;
+
+ VERIFY_EXPR(NumSets > 0 && VarCount[0] > 0);
+
// This call only initializes descriptor sets (ShaderResourceCacheVk::DescriptorSet) in the resource cache
// Resources are initialized by source layout when shader resource binding objects are created
- ResourceCache.InitializeSets(CacheMemAllocator, static_cast<Uint32>(VarCount.size()), VarCount.data());
+ ResourceCache.InitializeSets(CacheMemAllocator, NumSets, VarCount.data());
if (auto VkLayout = GetStaticVkDescriptorSetLayout())
{
@@ -417,7 +706,7 @@ void PipelineResourceSignatureVkImpl::InitResourceCache(ShaderResourceCacheVk& R
DescrSetName = _DescrSetName.c_str();
#endif
DescriptorSetAllocation SetAllocation = GetDevice()->AllocateDescriptorSet(~Uint64{0}, VkLayout, DescrSetName);
- ResourceCache.GetDescriptorSet(0).AssignDescriptorSetAllocation(std::move(SetAllocation));
+ ResourceCache.GetDescriptorSet(GetStaticDescrSetIndex()).AssignDescriptorSetAllocation(std::move(SetAllocation));
}
}
@@ -426,8 +715,7 @@ SHADER_TYPE PipelineResourceSignatureVkImpl::GetShaderStageType(Uint32 StageInde
SHADER_TYPE Stages = m_ShaderStages;
for (Uint32 Index = 0; Stages != SHADER_TYPE_UNKNOWN; ++Index)
{
- auto StageBit = static_cast<SHADER_TYPE>(1 << PlatformMisc::GetLSB(Uint32{Stages}));
- Stages = Stages & ~StageBit;
+ auto StageBit = ExtractBit(Stages);
if (Index == StageIndex)
return StageBit;
@@ -437,29 +725,843 @@ SHADER_TYPE PipelineResourceSignatureVkImpl::GetShaderStageType(Uint32 StageInde
return SHADER_TYPE_UNKNOWN;
}
+Uint32 PipelineResourceSignatureVkImpl::GetNumDescriptorSets() const
+{
+ return Uint32{m_VkDescSetLayouts[0] != VK_NULL_HANDLE} + Uint32{m_VkDescSetLayouts[1] != VK_NULL_HANDLE};
+}
+
void PipelineResourceSignatureVkImpl::InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache) const
{
auto TotalResources = GetTotalResourceCount();
for (Uint32 r = 0; r < TotalResources; ++r)
{
const auto& Res = GetResource(r);
- const auto& Bind = GetBinding(r);
- ResourceCache.InitializeResources(Bind.DescSet, Bind.Binding, Res.ArraySize, GetVkDescriptorType(Res));
+ const auto& Attr = GetAttribs(r);
+ ResourceCache.InitializeResources(Attr.DescrSet, Attr.CacheOffset, Res.ArraySize, Attr.Type);
}
}
void PipelineResourceSignatureVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& DstResourceCache) const
{
+ if (GetStaticVkDescriptorSetLayout() == VK_NULL_HANDLE || m_pResourceCache == nullptr)
+ return;
+
+ // SrcResourceCache contains only static resources.
+ // DstResourceCache contains static and mutable resources.
const auto& SrcResourceCache = *m_pResourceCache;
- (void)(SrcResourceCache);
+ const auto& SrcDescrSet = SrcResourceCache.GetDescriptorSet(GetStaticDescrSetIndex());
+ auto& DstDescrSet = DstResourceCache.GetDescriptorSet(GetStaticDescrSetIndex());
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
+ // AZ TODO: optimize
+ for (Uint32 r = 0; r < GetTotalResourceCount(); ++r)
{
- // AZ TODO
+ const auto& Res = GetResource(r);
+ const auto& Attr = GetAttribs(r);
+
+ if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && Attr.ImmutableSamplerAssigned)
+ continue; // Skip immutable separate samplers
+
+ if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
+ {
+ for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd)
+ {
+ 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);
+ }
+ }
+ }
}
+
#ifdef DILIGENT_DEBUG
DstResourceCache.DbgVerifyDynamicBuffersCounter();
#endif
}
+Uint32 PipelineResourceSignatureVkImpl::GetStaticDescrSetIndex() const
+{
+ return m_VkDescSetLayouts[0] != VK_NULL_HANDLE ? 0 : ~0u;
+}
+
+Uint32 PipelineResourceSignatureVkImpl::GetDynamicDescrSetIndex() const
+{
+ return m_VkDescSetLayouts[1] != VK_NULL_HANDLE ? Uint32{m_VkDescSetLayouts[0] != VK_NULL_HANDLE} : ~0u;
+}
+
+void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache,
+ VkDescriptorSet vkDynamicDescriptorSet) const
+{
+ VERIFY(HasDynamicDescrSet(), "This shader resource layout does not contain dynamic resources");
+ VERIFY_EXPR(vkDynamicDescriptorSet != VK_NULL_HANDLE);
+
+#ifdef DILIGENT_DEBUG
+ static constexpr size_t ImgUpdateBatchSize = 4;
+ static constexpr size_t BuffUpdateBatchSize = 2;
+ static constexpr size_t TexelBuffUpdateBatchSize = 2;
+ static constexpr size_t AccelStructBatchSize = 2;
+ static constexpr size_t WriteDescriptorSetBatchSize = 2;
+#else
+ static constexpr size_t ImgUpdateBatchSize = 128;
+ static constexpr size_t BuffUpdateBatchSize = 64;
+ static constexpr size_t TexelBuffUpdateBatchSize = 32;
+ static constexpr size_t AccelStructBatchSize = 32;
+ static constexpr size_t WriteDescriptorSetBatchSize = 32;
+#endif
+
+ // Do not zero-initiaize arrays!
+ std::array<VkDescriptorImageInfo, ImgUpdateBatchSize> DescrImgInfoArr;
+ std::array<VkDescriptorBufferInfo, BuffUpdateBatchSize> DescrBuffInfoArr;
+ std::array<VkBufferView, TexelBuffUpdateBatchSize> DescrBuffViewArr;
+ std::array<VkWriteDescriptorSetAccelerationStructureKHR, AccelStructBatchSize> DescrAccelStructArr;
+ std::array<VkWriteDescriptorSet, WriteDescriptorSetBatchSize> WriteDescrSetArr;
+
+ auto DescrImgIt = DescrImgInfoArr.begin();
+ auto DescrBuffIt = DescrBuffInfoArr.begin();
+ auto BuffViewIt = DescrBuffViewArr.begin();
+ auto AccelStructIt = DescrAccelStructArr.begin();
+ auto WriteDescrSetIt = WriteDescrSetArr.begin();
+
+ const auto& SetResources = ResourceCache.GetDescriptorSet(GetDynamicDescrSetIndex());
+ const auto& LogicalDevice = GetDevice()->GetLogicalDevice();
+
+ // AZ TODO: optimize
+ for (Uint32 ResNum = 0, ArrElem = 0, Count = GetTotalResourceCount(); ResNum < Count;)
+ {
+ const auto& Res = GetResource(ResNum);
+ const auto& Attr = GetAttribs(ResNum);
+
+ if (Res.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VERIFY_EXPR(ArrElem == 0);
+ ++ResNum;
+ continue;
+ }
+
+ WriteDescrSetIt->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ WriteDescrSetIt->pNext = nullptr;
+ VERIFY(SetResources.GetVkDescriptorSet() == VK_NULL_HANDLE, "Dynamic descriptor set must not be assigned to the resource cache");
+ WriteDescrSetIt->dstSet = vkDynamicDescriptorSet;
+ VERIFY(WriteDescrSetIt->dstSet != VK_NULL_HANDLE, "Vulkan descriptor set must not be null");
+ WriteDescrSetIt->dstBinding = Attr.BindingIndex;
+ 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);
+
+ // 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)
+ {
+ case DescriptorType::UniformBuffer:
+ case DescriptorType::UniformBufferDynamic:
+ WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt);
+ while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
+ {
+ const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
+ *DescrBuffIt = CachedRes.GetUniformBufferDescriptorWriteInfo();
+ ++DescrBuffIt;
+ ++ArrElem;
+ }
+ break;
+
+ case DescriptorType::StorageBuffer:
+ case DescriptorType::StorageBufferDynamic:
+ case DescriptorType::StorageBuffer_ReadOnly:
+ case DescriptorType::StorageBufferDynamic_ReadOnly:
+ WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt);
+ while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
+ {
+ const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
+ *DescrBuffIt = CachedRes.GetStorageBufferDescriptorWriteInfo();
+ ++DescrBuffIt;
+ ++ArrElem;
+ }
+ break;
+
+ case DescriptorType::UniformTexelBuffer:
+ case DescriptorType::StorageTexelBuffer:
+ case DescriptorType::StorageTexelBuffer_ReadOnly:
+ WriteDescrSetIt->pTexelBufferView = &(*BuffViewIt);
+ while (ArrElem < Res.ArraySize && BuffViewIt != DescrBuffViewArr.end())
+ {
+ const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
+ *BuffViewIt = CachedRes.GetBufferViewWriteInfo();
+ ++BuffViewIt;
+ ++ArrElem;
+ }
+ break;
+
+ 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);
+ ++DescrImgIt;
+ ++ArrElem;
+ }
+ break;
+
+ 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)
+ {
+ WriteDescrSetIt->pImageInfo = &(*DescrImgIt);
+ while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end())
+ {
+ const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
+ *DescrImgIt = CachedRes.GetSamplerDescriptorWriteInfo();
+ ++DescrImgIt;
+ ++ArrElem;
+ }
+ }
+ else
+ {
+ ArrElem = Res.ArraySize;
+ WriteDescrSetIt->dstArrayElement = Res.ArraySize;
+ }
+ break;
+
+ case DescriptorType::AccelerationStructure:
+ WriteDescrSetIt->pNext = &(*AccelStructIt);
+ while (ArrElem < Res.ArraySize && AccelStructIt != DescrAccelStructArr.end())
+ {
+ const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
+ *AccelStructIt = CachedRes.GetAccelerationStructureWriteInfo();
+ ++AccelStructIt;
+ ++ArrElem;
+ }
+ break;
+
+ default:
+ UNEXPECTED("Unexpected resource type");
+ }
+
+ WriteDescrSetIt->descriptorCount = ArrElem - WriteDescrSetIt->dstArrayElement;
+ if (ArrElem == Res.ArraySize)
+ {
+ ArrElem = 0;
+ ++ResNum;
+ }
+ // descriptorCount == 0 for immutable separate samplers
+ if (WriteDescrSetIt->descriptorCount > 0)
+ ++WriteDescrSetIt;
+
+ // If we ran out of space in any of the arrays or if we processed all resources,
+ // flush pending updates and reset iterators
+ if (DescrImgIt == DescrImgInfoArr.end() ||
+ DescrBuffIt == DescrBuffInfoArr.end() ||
+ BuffViewIt == DescrBuffViewArr.end() ||
+ AccelStructIt == DescrAccelStructArr.end() ||
+ WriteDescrSetIt == WriteDescrSetArr.end())
+ {
+ auto DescrWriteCount = static_cast<Uint32>(std::distance(WriteDescrSetArr.begin(), WriteDescrSetIt));
+ if (DescrWriteCount > 0)
+ LogicalDevice.UpdateDescriptorSets(DescrWriteCount, WriteDescrSetArr.data(), 0, nullptr);
+
+ DescrImgIt = DescrImgInfoArr.begin();
+ DescrBuffIt = DescrBuffInfoArr.begin();
+ BuffViewIt = DescrBuffViewArr.begin();
+ AccelStructIt = DescrAccelStructArr.begin();
+ WriteDescrSetIt = WriteDescrSetArr.begin();
+ }
+ }
+
+ auto DescrWriteCount = static_cast<Uint32>(std::distance(WriteDescrSetArr.begin(), WriteDescrSetIt));
+ if (DescrWriteCount > 0)
+ LogicalDevice.UpdateDescriptorSets(DescrWriteCount, WriteDescrSetArr.data(), 0, nullptr);
+}
+
+String PipelineResourceSignatureVkImpl::GetPrintName(const PipelineResourceDesc& ResDesc, Uint32 ArrayInd)
+{
+ VERIFY_EXPR(ArrayInd < ResDesc.ArraySize);
+
+ if (ResDesc.ArraySize > 1)
+ {
+ std::stringstream ss;
+ ss << ResDesc.Name << '[' << ArrayInd << ']';
+ return ss.str();
+ }
+ else
+ return ResDesc.Name;
+}
+
+namespace
+{
+struct BindResourceHelper
+{
+ // AZ TODO: cache DstRes.Type and ResDesc.VarType for better performace ???
+ ShaderResourceCacheVk::Resource& DstRes;
+ const PipelineResourceDesc& ResDesc;
+ const PipelineResourceSignatureVkImpl::ResourceAttribs& Attribs;
+ const Uint32 ArrayIndex;
+ const VkDescriptorSet vkDescrSet;
+ PipelineResourceSignatureVkImpl const& Signature;
+ ShaderResourceCacheVk& ResourceCache;
+
+ void BindResource(IDeviceObject* pObj) const;
+
+ String GetPrintName(Uint32 ArrayInd) const;
+
+ RESOURCE_DIMENSION GetResourceDimension() const;
+
+ bool IsMultisample() const;
+
+private:
+ void CacheUniformBuffer(IDeviceObject* pBuffer,
+ Uint16& DynamicBuffersCounter) const;
+
+ void CacheStorageBuffer(IDeviceObject* pBufferView,
+ Uint16& DynamicBuffersCounter) const;
+
+ void CacheTexelBuffer(IDeviceObject* pBufferView,
+ Uint16& DynamicBuffersCounter) 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;
+
+ bool IsImmutableSamplerAssigned() const { return Attribs.ImmutableSamplerAssigned; }
+
+ // Updates resource descriptor in the descriptor set
+ inline void UpdateDescriptorHandle(const VkDescriptorImageInfo* pImageInfo,
+ const VkDescriptorBufferInfo* pBufferInfo,
+ const VkBufferView* pTexelBufferView,
+ const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const;
+};
+
+void BindResourceHelper::BindResource(IDeviceObject* pObj) const
+{
+#ifdef DILIGENT_DEBUG
+ if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
+ {
+ if (ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
+ {
+ VERIFY(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 (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
+ {
+ 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
+
+ if (pObj)
+ {
+ static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type");
+ switch (DstRes.Type)
+ {
+ case DescriptorType::UniformBuffer:
+ case DescriptorType::UniformBufferDynamic:
+ CacheUniformBuffer(pObj, ResourceCache.GetDynamicBuffersCounter());
+ break;
+
+ case DescriptorType::StorageBuffer:
+ case DescriptorType::StorageBuffer_ReadOnly:
+ case DescriptorType::StorageBufferDynamic:
+ case DescriptorType::StorageBufferDynamic_ReadOnly:
+ CacheStorageBuffer(pObj, ResourceCache.GetDynamicBuffersCounter());
+ break;
+
+ case DescriptorType::UniformTexelBuffer:
+ case DescriptorType::StorageTexelBuffer:
+ case DescriptorType::StorageTexelBuffer_ReadOnly:
+ CacheTexelBuffer(pObj, ResourceCache.GetDynamicBuffersCounter());
+ break;
+
+ case DescriptorType::StorageImage:
+ case DescriptorType::StorageImage_ReadOnly:
+ case DescriptorType::SeparateImage:
+ case DescriptorType::CombinedImageSampler:
+ CacheImage(pObj);
+ break;
+
+ case DescriptorType::Sampler:
+ if (!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)
+ LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", ResDesc.Name, '\'');
+ }
+ break;
+
+ case DescriptorType::InputAttachment:
+ CacheInputAttachment(pObj);
+ break;
+
+ case DescriptorType::AccelerationStructure:
+ CacheAccelerationStructure(pObj);
+ break;
+
+ default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(DstRes.Type));
+ }
+ }
+ else
+ {
+ if (DstRes.pObject && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ LOG_ERROR_MESSAGE("Shader variable '", 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.");
+ }
+
+ DstRes.pObject.Release();
+ }
+}
+
+template <typename ObjectType, typename TPreUpdateObject>
+bool BindResourceHelper::UpdateCachedResource(RefCntAutoPtr<ObjectType>&& pObject,
+ TPreUpdateObject PreUpdateObject) const
+{
+ // We cannot use ValidatedCast<> here as the resource retrieved from the
+ // resource mapping can be of wrong type
+ if (pObject)
+ {
+ if (ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && 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(DstRes.pObject.template RawPtr<const ObjectType>(), pObject.template RawPtr<const ObjectType>());
+ DstRes.pObject.Attach(pObject.Detach());
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void BindResourceHelper::CacheUniformBuffer(IDeviceObject* pBuffer,
+ Uint16& DynamicBuffersCounter) const
+{
+ // clang-format off
+ VERIFY(DstRes.Type == DescriptorType::UniformBuffer ||
+ DstRes.Type == DescriptorType::UniformBufferDynamic,
+ "Uniform buffer resource is expected");
+ // clang-format on
+ RefCntAutoPtr<BufferVkImpl> pBufferVk{pBuffer, IID_BufferVk};
+#ifdef DILIGENT_DEVELOPMENT
+ VerifyConstantBufferBinding(*this, ResDesc.VarType, ArrayIndex, pBuffer, pBufferVk.RawPtr(), DstRes.pObject.RawPtr());
+
+ // AZ TODO
+ /*if (pBufferVk->GetDesc().uiSizeInBytes < BufferStaticSize)
+ {
+ // It is OK if robustBufferAccess feature is enabled, otherwise access outside of buffer range may lead to crash or undefined behavior.
+ LOG_WARNING_MESSAGE("Error binding uniform buffer '", pBufferVk->GetDesc().Name, "' to shader variable '",
+ GetDesc().Name, "': buffer size in the shader (",
+ BufferStaticSize, ") is incompatible with the actual buffer size (", pBufferVk->GetDesc().uiSizeInBytes, ").");
+ }*/
+#endif
+
+ auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferVkImpl* pOldBuffer, const BufferVkImpl* pNewBuffer) {
+ 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;
+ };
+ 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 (vkDescrSet != VK_NULL_HANDLE && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorBufferInfo DescrBuffInfo = DstRes.GetUniformBufferDescriptorWriteInfo();
+ UpdateDescriptorHandle(nullptr, &DescrBuffInfo, nullptr);
+ }
+ }
+}
+
+void BindResourceHelper::CacheStorageBuffer(IDeviceObject* pBufferView,
+ Uint16& DynamicBuffersCounter) const
+{
+ // clang-format off
+ VERIFY(DstRes.Type == DescriptorType::StorageBuffer ||
+ DstRes.Type == DescriptorType::StorageBuffer_ReadOnly ||
+ DstRes.Type == DescriptorType::StorageBufferDynamic ||
+ DstRes.Type == DescriptorType::StorageBufferDynamic_ReadOnly,
+ "Storage buffer resource is expected");
+ // clang-format on
+
+ RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk};
+#ifdef DILIGENT_DEVELOPMENT
+ {
+ // HLSL buffer SRVs are mapped to storge buffers in GLSL
+ auto RequiredViewType = DescriptorTypeToBufferView(DstRes.Type);
+ VerifyResourceViewBinding(*this, ResDesc.VarType, ArrayIndex, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, 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 '",
+ ResDesc.Name, "': structured buffer view is expected.");
+ }
+
+ // AZ TODO
+ /*if (BufferStride == 0 && ViewDesc.ByteWidth < BufferStaticSize)
+ {
+ // It is OK if robustBufferAccess feature is enabled, otherwise access outside of buffer range may lead to crash or undefined behavior.
+ LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
+ Name, "': buffer size in the shader (",
+ BufferStaticSize, ") is incompatible with the actual buffer view size (", ViewDesc.ByteWidth, ").");
+ }
+
+ if (BufferStride > 0 && (ViewDesc.ByteWidth < BufferStaticSize || (ViewDesc.ByteWidth - BufferStaticSize) % BufferStride != 0))
+ {
+ // For buffers with dynamic arrays we know only static part size and array element stride.
+ // Element stride in the shader may be differ than in the code. Here we check that the buffer size is exactly the same as the array with N elements.
+ LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
+ Name, "': static buffer size in the shader (",
+ BufferStaticSize, ") and array element stride (", BufferStride, ") are incompatible with the actual buffer view size (", ViewDesc.ByteWidth, "),",
+ " this may be the result of the array element size mismatch.");
+ }*/
+ }
+ }
+#endif
+
+ auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {
+ 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;
+ };
+
+ 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 (vkDescrSet != VK_NULL_HANDLE && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorBufferInfo DescrBuffInfo = DstRes.GetStorageBufferDescriptorWriteInfo();
+ UpdateDescriptorHandle(nullptr, &DescrBuffInfo, nullptr);
+ }
+ }
+}
+
+void BindResourceHelper::CacheTexelBuffer(IDeviceObject* pBufferView,
+ Uint16& DynamicBuffersCounter) const
+{
+ // clang-format off
+ VERIFY(DstRes.Type == DescriptorType::UniformTexelBuffer ||
+ DstRes.Type == DescriptorType::StorageTexelBuffer ||
+ DstRes.Type == DescriptorType::StorageTexelBuffer_ReadOnly,
+ "Uniform or storage buffer resource is expected");
+ // clang-format on
+
+ RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk};
+#ifdef DILIGENT_DEVELOPMENT
+ {
+ // HLSL buffer SRVs are mapped to storge buffers in GLSL
+ auto RequiredViewType = DescriptorTypeToBufferView(DstRes.Type);
+ VerifyResourceViewBinding(*this, ResDesc.VarType, ArrayIndex, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, 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) || BuffDesc.Mode == BUFFER_MODE_RAW))
+ {
+ LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
+ ResDesc.Name, "': formatted buffer view is expected.");
+ }
+ }
+ }
+#endif
+
+ auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {
+ 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;
+ };
+
+ if (UpdateCachedResource(std::move(pBufferViewVk), UpdateDynamicBuffersCounter))
+ {
+ // 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 (vkDescrSet != VK_NULL_HANDLE && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkBufferView BuffView = DstRes.pObject.RawPtr<BufferViewVkImpl>()->GetVkBufferView();
+ UpdateDescriptorHandle(nullptr, nullptr, &BuffView);
+ }
+ }
+}
+
+void BindResourceHelper::CacheImage(IDeviceObject* pTexView) const
+{
+ // clang-format off
+ VERIFY(DstRes.Type == DescriptorType::StorageImage ||
+ DstRes.Type == DescriptorType::StorageImage_ReadOnly ||
+ DstRes.Type == DescriptorType::SeparateImage ||
+ DstRes.Type == DescriptorType::CombinedImageSampler,
+ "Storage image, separate image or sampled image resource is expected");
+ // clang-format on
+ RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
+#ifdef DILIGENT_DEVELOPMENT
+ {
+ // HLSL buffer SRVs are mapped to storge buffers in GLSL
+ auto RequiredViewType = DescriptorTypeToTextureView(DstRes.Type);
+ VerifyResourceViewBinding(*this, ResDesc.VarType, ArrayIndex, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, 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 = DstRes.pObject.RawPtr<TextureViewVkImpl>();
+#ifdef DILIGENT_DEVELOPMENT
+ if (DstRes.Type == DescriptorType::CombinedImageSampler && !IsImmutableSamplerAssigned())
+ {
+ if (pTexViewVk->GetSampler() == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", GetPrintName(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 (vkDescrSet != VK_NULL_HANDLE && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorImageInfo DescrImgInfo = DstRes.GetImageDescriptorWriteInfo(IsImmutableSamplerAssigned());
+ UpdateDescriptorHandle(&DescrImgInfo, nullptr, nullptr);
+ }
+
+ if (Attribs.SamplerInd != PipelineResourceSignatureVkImpl::InvalidSamplerInd)
+ {
+ VERIFY(DstRes.Type == DescriptorType::SeparateImage,
+ "Only separate images can be assigned separate samplers when using HLSL-style combined samplers.");
+ VERIFY(!IsImmutableSamplerAssigned(), "Separate image can't be assigned an immutable sampler.");
+
+ auto& SamplerResDesc = Signature.GetResource(Attribs.SamplerInd);
+ auto& SamplerAttribs = Signature.GetAttribs(Attribs.SamplerInd);
+ VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
+
+ if (!SamplerAttribs.ImmutableSamplerAssigned)
+ {
+ auto* pSampler = pTexViewVk->GetSampler();
+ if (pSampler != nullptr)
+ {
+ VERIFY_EXPR(DstRes.Type == DescriptorType::SeparateImage);
+ DEV_CHECK_ERR(SamplerResDesc.ArraySize == 1 || SamplerResDesc.ArraySize == ResDesc.ArraySize,
+ "Array size (", SamplerResDesc.ArraySize,
+ ") of separate sampler variable '",
+ SamplerResDesc.Name,
+ "' must be one or the same as the array size (", ResDesc.ArraySize,
+ ") of separate image variable '", ResDesc.Name, "' it is assigned to");
+
+ auto& DstDescrSet = ResourceCache.GetDescriptorSet(SamplerAttribs.DescrSet);
+ const auto SamplerArrInd = SamplerResDesc.ArraySize == 1 ? 0 : ArrayIndex;
+ auto& SampleDstRes = DstDescrSet.GetResource(SamplerAttribs.CacheOffset + SamplerArrInd);
+
+ BindResourceHelper SeparateSampler{
+ SampleDstRes,
+ SamplerResDesc,
+ SamplerAttribs,
+ SamplerArrInd,
+ DstDescrSet.GetVkDescriptorSet(),
+ Signature,
+ ResourceCache};
+ SeparateSampler.BindResource(pSampler);
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerResDesc.Name,
+ "' assigned to separate image '", GetPrintName(ArrayIndex),
+ "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\'');
+ }
+ }
+ }
+ }
+}
+
+void BindResourceHelper::CacheSeparateSampler(IDeviceObject* pSampler) const
+{
+ VERIFY(DstRes.Type == DescriptorType::Sampler, "Separate sampler resource is expected");
+ VERIFY(!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 '", GetPrintName(ArrayIndex),
+ "'. Unexpected object type: sampler is expected");
+ }
+ if (ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr && DstRes.pObject != pSamplerVk)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(ResDesc.VarType);
+ LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetPrintName(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 (vkDescrSet != VK_NULL_HANDLE && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorImageInfo DescrImgInfo = DstRes.GetSamplerDescriptorWriteInfo();
+ UpdateDescriptorHandle(&DescrImgInfo, nullptr, nullptr);
+ }
+ }
+}
+
+void BindResourceHelper::CacheInputAttachment(IDeviceObject* pTexView) const
+{
+ VERIFY(DstRes.Type == DescriptorType::InputAttachment, "Input attachment resource is expected");
+ RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
+#ifdef DILIGENT_DEVELOPMENT
+ VerifyResourceViewBinding(*this, ResDesc.VarType, ArrayIndex, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, 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 (vkDescrSet != VK_NULL_HANDLE && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorImageInfo DescrImgInfo = DstRes.GetInputAttachmentDescriptorWriteInfo();
+ UpdateDescriptorHandle(&DescrImgInfo, nullptr, nullptr);
+ }
+ //
+ }
+}
+
+void BindResourceHelper::CacheAccelerationStructure(IDeviceObject* pTLAS) const
+{
+ VERIFY(DstRes.Type == DescriptorType::AccelerationStructure, "Acceleration Structure resource is expected");
+ RefCntAutoPtr<TopLevelASVkImpl> pTLASVk{pTLAS, IID_TopLevelASVk};
+#ifdef DILIGENT_DEVELOPMENT
+ VerifyTLASResourceBinding(*this, ResDesc.VarType, ArrayIndex, pTLASVk.RawPtr(), 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 (vkDescrSet != VK_NULL_HANDLE && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkWriteDescriptorSetAccelerationStructureKHR DescrASInfo = 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(vkDescrSet != VK_NULL_HANDLE);
+
+ VkWriteDescriptorSet WriteDescrSet;
+ WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ WriteDescrSet.pNext = pAccelStructInfo;
+ WriteDescrSet.dstSet = vkDescrSet;
+ WriteDescrSet.dstBinding = Attribs.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 = GetVkDescriptorType(DstRes.Type);
+ WriteDescrSet.pImageInfo = pImageInfo;
+ WriteDescrSet.pBufferInfo = pBufferInfo;
+ WriteDescrSet.pTexelBufferView = pTexelBufferView;
+
+ Signature.GetDevice()->GetLogicalDevice().UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr);
+}
+
+String BindResourceHelper::GetPrintName(Uint32 ArrayInd) const
+{
+ return PipelineResourceSignatureVkImpl::GetPrintName(ResDesc, ArrayInd);
+}
+
+RESOURCE_DIMENSION BindResourceHelper::GetResourceDimension() const
+{
+ return RESOURCE_DIM_UNDEFINED; // AZ TODO
+}
+
+bool BindResourceHelper::IsMultisample() const
+{
+ return false; // AZ TODO
+}
+
+} // namespace
+
+void PipelineResourceSignatureVkImpl::BindResource(IDeviceObject* pObj,
+ Uint32 ArrayIndex,
+ 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);
+
+ VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize);
+ VERIFY(DstRes.Type == Attribs.Type, "Inconsistent types");
+
+ BindResourceHelper Helper{
+ DstRes,
+ ResDesc,
+ Attribs,
+ ArrayIndex,
+ DstDescrSet.GetVkDescriptorSet(),
+ *this,
+ ResourceCache};
+
+ Helper.BindResource(pObj);
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
index 225e3f82..736154a5 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
@@ -502,6 +502,98 @@ std::vector<VkRayTracingShaderGroupCreateInfoKHR> BuildRTShaderGroupDescription(
return ShaderGroups;
}
+void GetShaderResourceTypeAndFlags(SPIRVShaderResourceAttribs::ResourceType Type,
+ SHADER_RESOURCE_TYPE& OutType,
+ PIPELINE_RESOURCE_FLAGS& OutFlags)
+{
+ static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please handle the new resource type below");
+ OutFlags = PIPELINE_RESOURCE_FLAG_UNKNOWN;
+ switch (Type)
+ {
+ case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer:
+ OutType = SHADER_RESOURCE_TYPE_CONSTANT_BUFFER;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer:
+ // Read-only storage buffers map to buffer SRV
+ // https://github.com/KhronosGroup/SPIRV-Cross/wiki/Reflection-API-user-guide#read-write-vs-read-only-resources-for-hlsl
+ OutType = SHADER_RESOURCE_TYPE_BUFFER_SRV;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer:
+ OutType = SHADER_RESOURCE_TYPE_BUFFER_UAV;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer:
+ OutType = SHADER_RESOURCE_TYPE_BUFFER_SRV;
+ OutFlags = PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer:
+ OutType = SHADER_RESOURCE_TYPE_BUFFER_UAV;
+ OutFlags = PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::StorageImage:
+ OutType = SHADER_RESOURCE_TYPE_TEXTURE_UAV;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::SampledImage:
+ OutType = SHADER_RESOURCE_TYPE_TEXTURE_SRV;
+ OutFlags = PIPELINE_RESOURCE_FLAG_COMBINED_IMAGE;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter:
+ LOG_WARNING_MESSAGE("There is no appropriate shader resource type for atomic counter");
+ OutType = SHADER_RESOURCE_TYPE_BUFFER_UAV;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::SeparateImage:
+ OutType = SHADER_RESOURCE_TYPE_TEXTURE_SRV;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler:
+ OutType = SHADER_RESOURCE_TYPE_SAMPLER;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::InputAttachment:
+ OutType = SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT;
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure:
+ OutType = SHADER_RESOURCE_TYPE_ACCEL_STRUCT;
+ break;
+
+ default:
+ UNEXPECTED("Unknown SPIRV resource type");
+ OutType = SHADER_RESOURCE_TYPE_UNKNOWN;
+ break;
+ }
+}
+
+void VerifyResourceMerge(const SPIRVShaderResourceAttribs& ExistingRes,
+ const SPIRVShaderResourceAttribs& NewResAttribs)
+{
+ DEV_CHECK_ERR(ExistingRes.Type == NewResAttribs.Type,
+ "Shader variable '", NewResAttribs.Name,
+ "' exists in multiple shaders from the same shader stage, but its type is not consistent between "
+ "shaders. All variables with the same name from the same shader stage must have the same type.");
+
+ DEV_CHECK_ERR(ExistingRes.ResourceDim == NewResAttribs.ResourceDim,
+ "Shader variable '", NewResAttribs.Name,
+ "' exists in multiple shaders from the same shader stage, but its resource dimension is not consistent between "
+ "shaders. All variables with the same name from the same shader stage must have the same resource dimension.");
+
+ DEV_CHECK_ERR(ExistingRes.ArraySize == NewResAttribs.ArraySize,
+ "Shader variable '", NewResAttribs.Name,
+ "' exists in multiple shaders from the same shader stage, but its array size is not consistent between "
+ "shaders. All variables with the same name from the same shader stage must have the same array size.");
+
+ DEV_CHECK_ERR(ExistingRes.IsMS == NewResAttribs.IsMS,
+ "Shader variable '", NewResAttribs.Name,
+ "' exists in multiple shaders from the same shader stage, but its multisample flag is not consistent between "
+ "shaders. All variables with the same name from the same shader stage must either be multisample or non-multisample.");
+}
} // namespace
@@ -509,8 +601,7 @@ PipelineStateVkImpl::ShaderStageInfo::ShaderStageInfo(const ShaderVkImpl* pShade
Type{pShader->GetDesc().ShaderType},
Shaders{pShader},
SPIRVs{pShader->GetSPIRV()}
-{
-}
+{}
void PipelineStateVkImpl::ShaderStageInfo::Append(const ShaderVkImpl* pShader)
{
@@ -640,56 +731,105 @@ void PipelineStateVkImpl::InitPipelineLayout(const PipelineStateCreateInfo& Crea
if (SignatureCount == 0 || CreateInfo.ppResourceSignatures == nullptr)
{
- using ResourceNameToIndex_t = std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>;
+ struct UniqueResource
+ {
+ SPIRVShaderResourceAttribs const* Attribs = nullptr;
+ Uint32 DescIndex = ~0u;
+ };
+ using ResourceNameToIndex_t = std::unordered_map<HashMapStringKey, UniqueResource, HashMapStringKey::Hasher>;
std::vector<PipelineResourceDesc> Resources;
ResourceNameToIndex_t UniqueNames;
- const PipelineResourceLayoutDesc& LayoutDesc = CreateInfo.PSODesc.ResourceLayout;
+ const char* pCombinedSamplerSuffix = nullptr;
+ const auto& LayoutDesc = CreateInfo.PSODesc.ResourceLayout;
for (auto& Stage : ShaderStages)
{
UniqueNames.clear();
for (auto* pShader : Stage.Shaders)
{
- pShader->GetShaderResources().ProcessResources(
+ const auto DefaultVarType = LayoutDesc.DefaultVariableType;
+ auto& ShaderResources = pShader->GetShaderResources();
+
+ ShaderResources.ProcessResources(
[&](const SPIRVShaderResourceAttribs& Res, Uint32) //
{
- bool IsNewResource = UniqueNames.emplace(HashMapStringKey{Res.Name}, static_cast<Uint32>(Resources.size())).second;
- if (IsNewResource)
+ auto IterAndAssigned = UniqueNames.emplace(HashMapStringKey{Res.Name}, UniqueResource{&Res, static_cast<Uint32>(Resources.size())});
+ if (IterAndAssigned.second)
{
- Resources.emplace_back(Res.Name, Res.ArraySize, Res.GetShaderResourceType(Res.Type), Stage.Type, CreateInfo.PSODesc.ResourceLayout.DefaultVariableType);
+ SHADER_RESOURCE_TYPE Type;
+ PIPELINE_RESOURCE_FLAGS Flags;
+ GetShaderResourceTypeAndFlags(Res.Type, Type, Flags);
+
+ Resources.emplace_back(Res.Name, Res.ArraySize, Type, Stage.Type, DefaultVarType, Flags);
+ }
+ else
+ {
+ VerifyResourceMerge(*IterAndAssigned.first->second.Attribs, Res);
}
});
+ // merge combined sampler suffixes
+ if (ShaderResources.IsUsingCombinedSamplers() && ShaderResources.GetNumSepSmplrs() > 0)
+ {
+ if (pCombinedSamplerSuffix != nullptr)
+ {
+ if (strcmp(pCombinedSamplerSuffix, ShaderResources.GetCombinedSamplerSuffix()) != 0)
+ LOG_ERROR_AND_THROW("AZ TODO");
+ }
+ else
+ {
+ pCombinedSamplerSuffix = ShaderResources.GetCombinedSamplerSuffix();
+ }
+ }
+
for (Uint32 i = 0; i < LayoutDesc.NumVariables; ++i)
{
const auto& Var = LayoutDesc.Variables[i];
if (Var.ShaderStages & Stage.Type)
{
auto Iter = UniqueNames.find(HashMapStringKey{Var.Name});
- if (Iter != UniqueNames.end() && Iter->second < Resources.size())
- Resources[Iter->second].VarType = Var.Type;
+ if (Iter != UniqueNames.end())
+ {
+ auto& Res = Resources[Iter->second.DescIndex];
+ Res.VarType = Var.Type;
+
+ // apply new variable type to sampler too
+ if (ShaderResources.IsUsingCombinedSamplers() && Res.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV)
+ {
+ String SampName = String{Var.Name} + ShaderResources.GetCombinedSamplerSuffix();
+ auto SampIter = UniqueNames.find(HashMapStringKey{SampName.c_str()});
+ if (SampIter != UniqueNames.end())
+ Resources[SampIter->second.DescIndex].VarType = Var.Type;
+ }
+ }
}
}
}
}
- PipelineResourceSignatureDesc ResSignDesc;
- ResSignDesc.Resources = Resources.data();
- ResSignDesc.NumResources = static_cast<Uint32>(Resources.size());
- ResSignDesc.ImmutableSamplers = LayoutDesc.ImmutableSamplers;
- ResSignDesc.NumImmutableSamplers = LayoutDesc.NumImmutableSamplers;
- ResSignDesc.BindingIndex = 0;
-
- GetDevice()->CreatePipelineResourceSignature(ResSignDesc, &TempSignature);
- if (TempSignature == nullptr)
- LOG_ERROR_AND_THROW("");
-
- Signatures[0] = TempSignature;
- SignatureCount = 1;
+ 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;
+
+ GetDevice()->CreatePipelineResourceSignature(ResSignDesc, &TempSignature, true);
+
+ if (TempSignature == nullptr)
+ LOG_ERROR_AND_THROW("AZ TODO");
+
+ Signatures[0] = TempSignature;
+ SignatureCount = 1;
+ }
}
- m_PipelineLayout = GetDevice()->GetPipelineLayoutCache().GetLayout(Signatures.data(), SignatureCount);
+ m_PipelineLayout.Create(GetDevice(), Signatures.data(), SignatureCount);
// verify that pipeline layout is compatible with shader resources and
// remap resource bindings
@@ -710,10 +850,10 @@ void PipelineStateVkImpl::InitPipelineLayout(const PipelineStateCreateInfo& Crea
[&](const SPIRVShaderResourceAttribs& Res, Uint32) //
{
PipelineLayoutVk::ResourceInfo Info;
- if (!m_PipelineLayout->GetResourceInfo(Res.Name, ShaderType, Info))
+ if (!m_PipelineLayout.GetResourceInfo(Res.Name, ShaderType, Info))
{
LOG_ERROR_AND_THROW("Shader '", pShader->GetDesc().Name, "' contains resource with name '", Res.Name,
- "' that is not presented in any pipeline resource signature that used to create pipeline state '",
+ "' that is not presented in any pipeline resource signature that is used to create pipeline state '",
m_Desc.Name, "'.");
}
SPIRV[Res.BindingDecorationOffset] = Info.BindingIndex;
@@ -744,11 +884,6 @@ PipelineStateVkImpl::TShaderStages PipelineStateVkImpl::InitInternalObjects(
InitializePipelineDesc(CreateInfo, MemPool);
- // It is important to construct all objects before initializing them because if an exception is thrown,
- // destructors will be called for all objects
-
- //InitResourceLayouts(CreateInfo, ShaderStages);
-
// Create shader modules and initialize shader stages
InitPipelineShaderStages(LogicalDevice, ShaderStages, ShaderModules, vkShaderStages);
@@ -767,7 +902,7 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, Rende
InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
- CreateGraphicsPipeline(pDeviceVk, vkShaderStages, *m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass);
+ CreateGraphicsPipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass);
}
catch (...)
{
@@ -786,7 +921,7 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, Rende
InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
- CreateComputePipeline(pDeviceVk, vkShaderStages, *m_PipelineLayout, m_Desc, m_Pipeline);
+ CreateComputePipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline);
}
catch (...)
{
@@ -809,7 +944,7 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, Rende
const auto vkShaderGroups = BuildRTShaderGroupDescription(CreateInfo, m_pRayTracingPipelineData->NameToGroupIndex, ShaderStages);
- CreateRayTracingPipeline(pDeviceVk, vkShaderStages, vkShaderGroups, *m_PipelineLayout, m_Desc, GetRayTracingPipelineDesc(), m_Pipeline);
+ CreateRayTracingPipeline(pDeviceVk, vkShaderStages, vkShaderGroups, m_PipelineLayout, m_Desc, GetRayTracingPipelineDesc(), m_Pipeline);
VERIFY(m_pRayTracingPipelineData->NameToGroupIndex.size() == vkShaderGroups.size(),
"The size of NameToGroupIndex map does not match the actual number of groups in the pipeline. This is a bug.");
@@ -835,6 +970,7 @@ void PipelineStateVkImpl::Destruct()
TPipelineStateBase::Destruct();
m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask);
+ m_PipelineLayout.Release(m_pDevice, m_Desc.CommandQueueMask);
auto& RawAllocator = GetRawAllocator();
if (m_pRawMem)
@@ -842,33 +978,23 @@ void PipelineStateVkImpl::Destruct()
RawAllocator.Free(m_pRawMem);
m_pRawMem = nullptr;
}
-
- // AZ TODO:
- /*
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
- {
- if (m_StaticVarsMgrs != nullptr)
- {
- m_StaticVarsMgrs[s].DestroyVariables(GetRawAllocator());
- m_StaticVarsMgrs[s].~ShaderVariableManagerVk();
- }
-
- if (m_StaticResCaches != nullptr)
- {
- m_StaticResCaches[s].~ShaderResourceCacheVk();
- }
- }
- */
}
bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const
{
- return m_PipelineLayout == ValidatedCast<const PipelineStateVkImpl>(pPSO)->m_PipelineLayout;
-}
+ const auto& lhs = m_PipelineLayout;
+ const auto& rhs = ValidatedCast<const PipelineStateVkImpl>(pPSO)->m_PipelineLayout;
-void PipelineStateVkImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags)
-{
- //m_StaticVarsMgr.BindResources(ShaderFlags, pResourceMapping, Flags);
+ if (lhs.GetSignatureCount() != rhs.GetSignatureCount())
+ return false;
+
+ if (lhs.GetSignatureCount() == 0)
+ return true;
+
+ if (lhs.GetSignatureCount() == 1)
+ return lhs.GetSignature(0)->IsCompatibleWith(*rhs.GetSignature(0));
+
+ return false;
}
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
index cc1a444c..edfcb670 100644
--- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
@@ -91,7 +91,6 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
m_LogicalVkDevice {std::move(LogicalDevice) },
m_EngineAttribs {EngineCI },
m_FramebufferCache {*this },
- m_PipelineLayoutCache {*this },
m_ImplicitRenderPassCache{*this },
m_DescriptorSetAllocator
{
@@ -105,8 +104,8 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.MainDescriptorPoolSize.NumStorageImageDescriptors},
{VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformTexelBufferDescriptors},
{VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageTexelBufferDescriptors},
- //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors},
- //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors},
{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors},
@@ -127,8 +126,8 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumStorageImageDescriptors},
{VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformTexelBufferDescriptors},
{VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageTexelBufferDescriptors},
- //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors},
- //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors},
{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors},
@@ -171,8 +170,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
m_PhysicalDevice->GetExtProperties().MeshShader.maxDrawMeshTasksCount,
m_PhysicalDevice->GetExtProperties().RayTracingPipeline.maxRayRecursionDepth,
m_PhysicalDevice->GetExtProperties().RayTracingPipeline.maxRayDispatchInvocationCount
- },
- m_PipelineLayoutAllocator{GetRawAllocator(), sizeof(PipelineLayoutVk), 128}
+ }
// clang-format on
{
static_assert(sizeof(VulkanDescriptorPoolSize) == sizeof(Uint32) * 11, "Please add new descriptors to m_DescriptorSetAllocator and m_DynamicDescriptorPool constructors");
@@ -278,10 +276,16 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
SamCaps.BorderSamplingModeSupported = True;
SamCaps.AnisotropicFilteringSupported = vkEnabledFeatures.samplerAnisotropy;
SamCaps.LODBiasSupported = True;
+
+ PipelineResourceSignatureDesc Desc;
+ Desc.Name = "Empty resource signature";
+ CreatePipelineResourceSignature(Desc, &m_pEmptySignature, true);
}
RenderDeviceVkImpl::~RenderDeviceVkImpl()
{
+ m_pEmptySignature.Release();
+
// Explicitly destroy dynamic heap. This will move resources owned by
// the heap into release queues
m_DynamicMemoryManager.Destroy();
@@ -834,19 +838,20 @@ void RenderDeviceVkImpl::CreateSBT(const ShaderBindingTableDesc& Desc,
void RenderDeviceVkImpl::CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc,
IPipelineResourceSignature** ppSignature)
{
+ CreatePipelineResourceSignature(Desc, ppSignature, false);
+}
+
+void RenderDeviceVkImpl::CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc,
+ IPipelineResourceSignature** ppSignature,
+ bool IsDeviceInternal)
+{
CreateDeviceObject("PipelineResourceSignature", Desc, ppSignature,
[&]() //
{
- PipelineResourceSignatureVkImpl* pPRSVk(NEW_RC_OBJ(m_PipeResSignAllocator, "PipelineResourceSignatureVkImpl instance", PipelineResourceSignatureVkImpl)(this, Desc));
+ PipelineResourceSignatureVkImpl* pPRSVk(NEW_RC_OBJ(m_PipeResSignAllocator, "PipelineResourceSignatureVkImpl instance", PipelineResourceSignatureVkImpl)(this, Desc, IsDeviceInternal));
pPRSVk->QueryInterface(IID_PipelineResourceSignature, reinterpret_cast<IObject**>(ppSignature));
OnCreateDeviceObject(pPRSVk);
});
}
-void RenderDeviceVkImpl::CreatePipelineLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount, PipelineLayoutVk** ppPipelineLayout)
-{
- PipelineLayoutVk* pPLVk(NEW_RC_OBJ(m_PipelineLayoutAllocator, "PipelineLayoutVk instance", PipelineLayoutVk)(this, ppSignatures, SignatureCount));
- *ppPipelineLayout = pPLVk;
-}
-
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
index 3672853f..a4932563 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
@@ -73,22 +73,23 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters*
auto& ResourceCacheDataAllocator = SRBMemAllocator.GetResourceCacheDataAllocator(0);
pPRS->InitResourceCache(m_ShaderResourceCache, ResourceCacheDataAllocator, pPRS->GetDesc().Name);
+ // Use resource signature to initialize resource memory in the cache
+ pPRS->InitializeResourceMemoryInCache(m_ShaderResourceCache);
+
for (Uint32 s = 0; s < m_NumShaders; ++s)
{
- auto ShaderInd = GetShaderTypePipelineIndex(pPRS->GetShaderStageType(s), pPRS->GetPipelineType());
+ const auto ShaderType = pPRS->GetShaderStageType(s);
+ const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPRS->GetPipelineType());
m_ShaderVarIndex[ShaderInd] = static_cast<Int8>(s);
auto& VarDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s);
- // Use source layout to initialize resource memory in the cache
- pPRS->InitializeResourceMemoryInCache(m_ShaderResourceCache);
-
// Create shader variable manager in place
// Initialize vars manager to reference mutable and dynamic variables
// Note that the cache has space for all variable types
const SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
- m_pShaderVarMgrs[s].Initialize(*pPRS, VarDataAllocator, VarTypes, _countof(VarTypes));
+ m_pShaderVarMgrs[s].Initialize(*pPRS, VarDataAllocator, VarTypes, _countof(VarTypes), ShaderType);
}
#ifdef DILIGENT_DEBUG
m_ShaderResourceCache.DbgVerifyResourceInitialization();
@@ -124,7 +125,20 @@ void ShaderResourceBindingVkImpl::Destruct()
void ShaderResourceBindingVkImpl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags)
{
- // AZ TODO
+ const auto PipelineType = GetPipelineType();
+ for (Uint32 ShaderInd = 0; ShaderInd < m_ShaderVarIndex.size(); ++ShaderInd)
+ {
+ const auto VarMngrInd = m_ShaderVarIndex[ShaderInd];
+ if (VarMngrInd >= 0)
+ {
+ // ShaderInd is the shader type pipeline index here
+ const auto ShaderType = GetShaderTypeFromPipelineIndex(ShaderInd, PipelineType);
+ if (ShaderFlags & ShaderType)
+ {
+ m_pShaderVarMgrs[VarMngrInd].BindResources(pResMapping, Flags);
+ }
+ }
+ }
}
Uint32 ShaderResourceBindingVkImpl::GetVariableCount(SHADER_TYPE ShaderType) const
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
index 820d1e9a..28adf43a 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
@@ -65,8 +65,13 @@ void ShaderResourceCacheVk::InitializeSets(IMemoryAllocator& MemAllocator, Uint3
VERIFY(NumSets < std::numeric_limits<decltype(m_NumSets)>::max(), "NumSets (", NumSets, ") exceed maximum representable value");
m_NumSets = static_cast<Uint16>(NumSets);
m_TotalResources = 0;
+
for (Uint32 t = 0; t < NumSets; ++t)
+ {
+ VERIFY_EXPR(SetSizes[t] > 0);
m_TotalResources += SetSizes[t];
+ }
+
auto MemorySize = NumSets * sizeof(DescriptorSet) + m_TotalResources * sizeof(Resource);
VERIFY_EXPR(MemorySize == GetRequiredMemorySize(NumSets, SetSizes));
#ifdef DILIGENT_DEBUG
@@ -89,7 +94,7 @@ void ShaderResourceCacheVk::InitializeSets(IMemoryAllocator& MemAllocator, Uint3
}
}
-void ShaderResourceCacheVk::InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, VkDescriptorType Type)
+void ShaderResourceCacheVk::InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type)
{
auto& DescrSet = GetDescriptorSet(Set);
for (Uint32 res = 0; res < ArraySize; ++res)
@@ -117,19 +122,27 @@ void ShaderResourceCacheVk::DbgVerifyDynamicBuffersCounter() const
for (Uint32 res = 0; res < m_TotalResources; ++res)
{
const auto& Res = pResources[res];
- if (Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
- Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)
- {
- if (Res.pObject && Res.pObject.RawPtr<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
- ++NumDynamicBuffers;
- }
- else if (Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
- Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC ||
- Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
- Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
+ switch (Res.Type)
{
- if (Res.pObject && Res.pObject.RawPtr<const BufferViewVkImpl>()->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
- ++NumDynamicBuffers;
+ case DescriptorType::UniformBuffer:
+ case DescriptorType::UniformBufferDynamic:
+ {
+ if (Res.pObject && Res.pObject.RawPtr<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
+ ++NumDynamicBuffers;
+ break;
+ }
+ case DescriptorType::StorageBuffer:
+ case DescriptorType::StorageBufferDynamic:
+ case DescriptorType::StorageBuffer_ReadOnly:
+ case DescriptorType::StorageBufferDynamic_ReadOnly:
+ case DescriptorType::UniformTexelBuffer:
+ case DescriptorType::StorageTexelBuffer:
+ case DescriptorType::StorageTexelBuffer_ReadOnly:
+ {
+ if (Res.pObject && Res.pObject.RawPtr<const BufferViewVkImpl>()->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
+ ++NumDynamicBuffers;
+ break;
+ }
}
}
VERIFY(NumDynamicBuffers == m_NumDynamicBuffers, "The number of dynamic buffers (", m_NumDynamicBuffers, ") does not match the actual number (", NumDynamicBuffers, ")");
@@ -159,8 +172,8 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
auto& Res = pResources[res];
switch (Res.Type)
{
- case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
- case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case DescriptorType::UniformBuffer:
+ case DescriptorType::UniformBufferDynamic:
{
auto* pBufferVk = Res.pObject.RawPtr<BufferVkImpl>();
if (pBufferVk != nullptr && pBufferVk->IsInKnownState())
@@ -192,19 +205,19 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
- case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
- case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
- case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
- case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case DescriptorType::StorageBuffer:
+ case DescriptorType::StorageBufferDynamic:
+ case DescriptorType::StorageBuffer_ReadOnly:
+ case DescriptorType::StorageBufferDynamic_ReadOnly:
+ case DescriptorType::UniformTexelBuffer:
+ case DescriptorType::StorageTexelBuffer:
+ case DescriptorType::StorageTexelBuffer_ReadOnly:
{
auto* pBuffViewVk = Res.pObject.RawPtr<BufferViewVkImpl>();
auto* pBufferVk = pBuffViewVk != nullptr ? ValidatedCast<BufferVkImpl>(pBuffViewVk->GetBuffer()) : nullptr;
if (pBufferVk != nullptr && pBufferVk->IsInKnownState())
{
- const RESOURCE_STATE RequiredState =
- Res.Type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ? // AZ TODO: read-only buffer ???
- RESOURCE_STATE_UNORDERED_ACCESS :
- RESOURCE_STATE_SHADER_RESOURCE;
+ const RESOURCE_STATE RequiredState = DescriptorTypeToResourceState(Res.Type);
#ifdef DILIGENT_DEBUG
const VkAccessFlags RequiredAccessFlags = (RequiredState == RESOURCE_STATE_SHADER_RESOURCE) ?
VK_ACCESS_SHADER_READ_BIT :
@@ -239,9 +252,10 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
- case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
- case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
- case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ 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;
@@ -253,7 +267,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
// VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
// or VK_IMAGE_LAYOUT_GENERAL layout in order to access its data in a shader (13.1.3, 13.1.4).
RESOURCE_STATE RequiredState;
- if (Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
+ if (Res.Type == DescriptorType::StorageImage)
{
RequiredState = RESOURCE_STATE_UNORDERED_ACCESS;
VERIFY_EXPR(ResourceStateToVkImageLayout(RequiredState) == VK_IMAGE_LAYOUT_GENERAL);
@@ -302,13 +316,13 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
- case VK_DESCRIPTOR_TYPE_SAMPLER:
+ case DescriptorType::Sampler:
{
// Nothing to do with samplers
}
break;
- case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ case DescriptorType::InputAttachment:
{
// Nothing to do with input attachments - they are transitioned by the render pass.
// There is nothing we can validate here - a texture may be in different state at
@@ -316,7 +330,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
- case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
+ case DescriptorType::AccelerationStructure:
{
auto* pTLASVk = Res.pObject.RawPtr<TopLevelASVkImpl>();
if (pTLASVk != nullptr && pTLASVk->IsInKnownState())
@@ -362,8 +376,8 @@ template void ShaderResourceCacheVk::TransitionResources<true>(DeviceContextVkIm
VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetUniformBufferDescriptorWriteInfo() const
{
// clang-format off
- VERIFY(Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
- Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ VERIFY(Type == DescriptorType::UniformBuffer ||
+ Type == DescriptorType::UniformBufferDynamic,
"Uniform buffer resource is expected");
// clang-format on
DEV_CHECK_ERR(pObject != nullptr, "Unable to get uniform buffer write info: cached object is null");
@@ -385,10 +399,10 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetUniformBufferDescript
VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescriptorWriteInfo() const
{
// clang-format off
- VERIFY(Type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
- Type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER ||
- Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
- Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
+ VERIFY(Type == DescriptorType::StorageBuffer ||
+ Type == DescriptorType::StorageBufferDynamic ||
+ Type == DescriptorType::StorageBuffer_ReadOnly ||
+ Type == DescriptorType::StorageBufferDynamic_ReadOnly,
"Storage buffer resource is expected");
// clang-format on
DEV_CHECK_ERR(pObject != nullptr, "Unable to get storage buffer write info: cached object is null");
@@ -399,7 +413,7 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript
// 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)
- /*if (Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer) // AZ TODO
+ if (Type == DescriptorType::StorageBuffer_ReadOnly || Type == DescriptorType::StorageBufferDynamic_ReadOnly)
{
// HLSL buffer SRVs are mapped to read-only storge buffers in SPIR-V
VERIFY(ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE, "Attempting to bind buffer view '", ViewDesc.Name,
@@ -407,7 +421,7 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript
GetBufferViewTypeLiteralName(ViewDesc.ViewType));
VERIFY((pBuffVk->GetDesc().BindFlags & BIND_SHADER_RESOURCE) != 0, "Buffer '", pBuffVk->GetDesc().Name, "' being set as read-only storage buffer was not created with BIND_SHADER_RESOURCE flag");
}
- else if (Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
+ else if (Type == DescriptorType::StorageBuffer || Type == DescriptorType::StorageBufferDynamic)
{
VERIFY(ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS, "Attempting to bind buffer view '", ViewDesc.Name,
"' as writable storage buffer. Expected view type is BUFFER_VIEW_UNORDERED_ACCESS. Actual type: ",
@@ -417,7 +431,7 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript
else
{
UNEXPECTED("Unexpected resource type");
- }*/
+ }
VkDescriptorBufferInfo DescrBuffInfo;
DescrBuffInfo.buffer = pBuffVk->GetVkBuffer();
@@ -431,23 +445,24 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript
VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteInfo(bool IsImmutableSampler) const
{
// clang-format off
- VERIFY(Type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
- Type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
- Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ VERIFY(Type == DescriptorType::StorageImage ||
+ Type == DescriptorType::StorageImage_ReadOnly ||
+ Type == DescriptorType::SeparateImage ||
+ Type == DescriptorType::CombinedImageSampler,
"Storage image, separate image or sampled image resource is expected");
// clang-format on
DEV_CHECK_ERR(pObject != nullptr, "Unable to get image descriptor write info: cached object is null");
- bool IsStorageImage = Type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ bool IsStorageImage = (Type == DescriptorType::StorageImage);
auto* pTexViewVk = pObject.RawPtr<const TextureViewVkImpl>();
VERIFY_EXPR(pTexViewVk->GetDesc().ViewType == (IsStorageImage ? TEXTURE_VIEW_UNORDERED_ACCESS : TEXTURE_VIEW_SHADER_RESOURCE));
VkDescriptorImageInfo DescrImgInfo;
DescrImgInfo.sampler = VK_NULL_HANDLE;
- VERIFY(Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || !IsImmutableSampler,
+ VERIFY(Type == DescriptorType::CombinedImageSampler || !IsImmutableSampler,
"Immutable sampler can't be assigned to separarate image or storage image");
- if (Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && !IsImmutableSampler)
+ if (Type == DescriptorType::CombinedImageSampler && !IsImmutableSampler)
{
// 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)
@@ -488,8 +503,9 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteIn
VkBufferView ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo() const
{
// clang-format off
- VERIFY(Type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
- Type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
+ VERIFY(Type == DescriptorType::UniformTexelBuffer ||
+ Type == DescriptorType::StorageTexelBuffer ||
+ Type == DescriptorType::StorageTexelBuffer_ReadOnly,
"Uniform or storage buffer resource is expected");
// clang-format on
DEV_CHECK_ERR(pObject != nullptr, "Unable to get buffer view write info: cached object is null");
@@ -503,7 +519,7 @@ VkBufferView ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo() const
VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWriteInfo() const
{
- VERIFY(Type == VK_DESCRIPTOR_TYPE_SAMPLER, "Separate sampler resource is expected");
+ VERIFY(Type == DescriptorType::Sampler, "Separate sampler resource is expected");
DEV_CHECK_ERR(pObject != nullptr, "Unable to get separate sampler descriptor write info: cached object is null");
auto* pSamplerVk = pObject.RawPtr<const SamplerVkImpl>();
@@ -518,7 +534,7 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWrite
VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetInputAttachmentDescriptorWriteInfo() const
{
- VERIFY(Type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "Input attachment resource is expected");
+ VERIFY(Type == DescriptorType::InputAttachment, "Input attachment resource is expected");
DEV_CHECK_ERR(pObject != nullptr, "Unable to get input attachment write info: cached object is null");
auto* pTexViewVk = pObject.RawPtr<const TextureViewVkImpl>();
@@ -534,7 +550,7 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetInputAttachmentDescrip
VkWriteDescriptorSetAccelerationStructureKHR ShaderResourceCacheVk::Resource::GetAccelerationStructureWriteInfo() const
{
- VERIFY(Type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, "Acceleration structure resource is expected");
+ VERIFY(Type == DescriptorType::AccelerationStructure, "Acceleration structure resource is expected");
DEV_CHECK_ERR(pObject != nullptr, "Unable to get acceleration structure write info: cached object is null");
auto* pTLASVk = pObject.RawPtr<const TopLevelASVkImpl>();
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp
index a93c4482..4eaf49bd 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp
@@ -30,9 +30,6 @@
#include "ShaderVariableVk.hpp"
#include "ShaderResourceVariableBase.hpp"
#include "PipelineResourceSignatureVkImpl.hpp"
-#include "SamplerVkImpl.hpp"
-#include "TextureViewVkImpl.hpp"
-#include "TopLevelASVkImpl.hpp"
namespace Diligent
{
@@ -40,28 +37,30 @@ namespace Diligent
size_t ShaderVariableManagerVk::GetRequiredMemorySize(const PipelineResourceSignatureVkImpl& Layout,
const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
Uint32 NumAllowedTypes,
+ SHADER_TYPE ShaderStages,
Uint32& NumVariables)
{
NumVariables = 0;
const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
- const bool UsingSeparateSamplers = true; //Layout.IsUsingSeparateSamplers();
- const auto& Desc = Layout.GetDesc();
+ const bool UsingSeparateSamplers = Layout.IsUsingSeparateSamplers();
- for (Uint32 r = 0; r < Desc.NumResources; ++r)
+ for (Uint32 r = 0, Count = Layout.GetTotalResourceCount(); r < Count; ++r)
{
- const auto& SrcRes = Desc.Resources[r];
+ const auto& Res = Layout.GetResource(r);
+ const auto& Attr = Layout.GetAttribs(r);
- if (!IsAllowedType(SrcRes.VarType, AllowedTypeBits))
+ if (!IsAllowedType(Res.VarType, AllowedTypeBits))
+ continue;
+
+ if (!(Res.ShaderStages & ShaderStages))
continue;
- // AZ TODO
- /*
// When using HLSL-style combined image samplers, we need to skip separate samplers.
// Also always skip immutable separate samplers.
- if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && // AZ TODO
- (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()))
+ if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER &&
+ (!UsingSeparateSamplers || Attr.ImmutableSamplerAssigned))
continue;
- */
+
++NumVariables;
}
@@ -72,7 +71,8 @@ size_t ShaderVariableManagerVk::GetRequiredMemorySize(const PipelineResourceSign
void ShaderVariableManagerVk::Initialize(const PipelineResourceSignatureVkImpl& SrcLayout,
IMemoryAllocator& Allocator,
const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes)
+ Uint32 NumAllowedTypes,
+ SHADER_TYPE ShaderType)
{
#ifdef DILIGENT_DEBUG
m_pDbgAllocator = &Allocator;
@@ -82,7 +82,7 @@ void ShaderVariableManagerVk::Initialize(const PipelineResourceSignatureVkImpl&
const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
VERIFY_EXPR(m_NumVariables == 0);
- auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, m_NumVariables);
+ auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, ShaderType, m_NumVariables);
if (m_NumVariables == 0)
return;
@@ -90,25 +90,26 @@ void ShaderVariableManagerVk::Initialize(const PipelineResourceSignatureVkImpl&
auto* pRawMem = ALLOCATE_RAW(Allocator, "Raw memory buffer for shader variables", MemSize);
m_pVariables = reinterpret_cast<ShaderVariableVkImpl*>(pRawMem);
- Uint32 VarInd = 0;
- const bool UsingSeparateSamplers = false; //SrcLayout.IsUsingSeparateSamplers();
- const auto& Desc = SrcLayout.GetDesc();
+ Uint32 VarInd = 0;
+ const bool UsingSeparateSamplers = SrcLayout.IsUsingSeparateSamplers();
- for (Uint32 r = 0; r < Desc.NumResources; ++r)
+ for (Uint32 r = 0, Count = SrcLayout.GetTotalResourceCount(); r < Count; ++r)
{
- const auto& SrcRes = Desc.Resources[r];
+ const auto& Res = SrcLayout.GetResource(r);
+ const auto& Attr = SrcLayout.GetAttribs(r);
- if (!IsAllowedType(SrcRes.VarType, AllowedTypeBits))
+ if (!IsAllowedType(Res.VarType, AllowedTypeBits))
+ continue;
+
+ if (!(Res.ShaderStages & ShaderType))
continue;
- // AZ TODO
- /*
// Skip separate samplers when using combined HLSL-style image samplers. Also always skip immutable separate samplers.
- if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
- (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()))
+ if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER &&
+ (!UsingSeparateSamplers || Attr.ImmutableSamplerAssigned))
continue;
- */
- ::new (m_pVariables + VarInd) ShaderVariableVkImpl(*this);
+
+ ::new (m_pVariables + VarInd) ShaderVariableVkImpl(*this, r);
++VarInd;
}
VERIFY_EXPR(VarInd == m_NumVariables);
@@ -192,22 +193,23 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping,
if ((Flags & BIND_SHADER_RESOURCES_UPDATE_ALL) == 0)
Flags |= BIND_SHADER_RESOURCES_UPDATE_ALL;
- /*
+
for (Uint32 v = 0; v < m_NumVariables; ++v)
{
- auto& Var = m_pVariables[v];
- const auto& Res = Var.m_Resource;
+ auto& Var = m_pVariables[v];
+ const auto& Res = Var.GetDesc();
+ const auto& Attr = Var.GetAttribs();
// There should be no immutable separate samplers
- VERIFY(Res.Type != SPIRVShaderResourceAttribs::ResourceType::SeparateSampler || !Res.IsImmutableSamplerAssigned(),
+ VERIFY(Attr.Type != DescriptorType::Sampler || !Attr.ImmutableSamplerAssigned,
"There must be no shader resource variables for immutable separate samplers");
- if ((Flags & (1 << Res.GetVariableType())) == 0)
+ if ((Flags & (1u << Res.VarType)) == 0)
continue;
for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd)
{
- if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Res.IsBound(ArrInd, m_ResourceCache))
+ if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Var.IsBound(ArrInd))
continue;
const auto* VarName = Res.Name;
@@ -215,19 +217,20 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping,
pResourceMapping->GetResource(VarName, &pObj, ArrInd);
if (pObj)
{
- Res.BindResource(pObj, ArrInd, m_ResourceCache);
+ Var.BindResource(pObj, ArrInd);
}
else
{
- if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Res.IsBound(ArrInd, m_ResourceCache))
+ if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Var.IsBound(ArrInd))
{
- LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", Res.GetPrintName(ArrInd),
+ LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '",
+ PipelineResourceSignatureVkImpl::GetPrintName(Res, ArrInd),
"': resource is not found in the resource mapping. "
"Do not use BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED flag to suppress the message if this is not an issue.");
}
}
}
- }*/
+ }
}
void ShaderVariableVkImpl::Set(IDeviceObject* pObject)
@@ -250,14 +253,14 @@ bool ShaderVariableVkImpl::IsBound(Uint32 ArrayIndex) const
{
auto& ResourceCache = m_ParentManager.m_ResourceCache;
const auto& ResDesc = GetDesc();
- const auto& Binding = GetBinding();
- Uint32 CacheOffset = GetIndex();
+ const auto& Attribs = GetAttribs();
+ Uint32 CacheOffset = Attribs.CacheOffset;
VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize);
- if (Binding.DescSet < ResourceCache.GetNumDescriptorSets())
+ if (Attribs.DescrSet < ResourceCache.GetNumDescriptorSets())
{
- const auto& Set = ResourceCache.GetDescriptorSet(Binding.DescSet);
+ const auto& Set = ResourceCache.GetDescriptorSet(Attribs.DescrSet);
if (CacheOffset + ArrayIndex < Set.GetSize())
{
const auto& CachedRes = Set.GetResource(CacheOffset + ArrayIndex);
@@ -270,511 +273,10 @@ bool ShaderVariableVkImpl::IsBound(Uint32 ArrayIndex) const
void ShaderVariableVkImpl::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const
{
- auto CacheOffset = GetIndex();
- auto& ResDesc = GetDesc();
- auto& Bindings = GetBinding();
+ auto* pSign = m_ParentManager.m_pSignature;
auto& ResourceCache = m_ParentManager.m_ResourceCache;
- auto& DstDescrSet = ResourceCache.GetDescriptorSet(Bindings.DescSet);
-
- VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize);
-
- UpdateInfo Info{
- DstDescrSet.GetResource(CacheOffset + ArrayIndex),
- DstDescrSet.GetVkDescriptorSet(),
- ArrayIndex,
- ResDesc.VarType,
- Bindings.Binding,
- Bindings.SamplerInd,
- ResDesc.Name};
-
-#ifdef DILIGENT_DEBUG
- if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
- {
- if (Info.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || Info.VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
- {
- VERIFY(Info.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 (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
- {
- VERIFY(Info.vkDescrSet == VK_NULL_HANDLE, "Static shader resource cache should not have vulkan descriptor set allocation");
- }
- else
- {
- UNEXPECTED("Unexpected shader resource cache content type");
- }
-#endif
-
- VERIFY(Info.DstRes.Type == PipelineResourceSignatureVkImpl::GetVkDescriptorType(ResDesc), "Inconsistent types");
-
- if (pObj)
- {
- switch (Info.DstRes.Type)
- {
- case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
- case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
- CacheUniformBuffer(pObj, Info, ResourceCache.GetDynamicBuffersCounter());
- break;
-
- case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
- case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
- CacheStorageBuffer(pObj, Info, ResourceCache.GetDynamicBuffersCounter());
- break;
-
- case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
- case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
- CacheTexelBuffer(pObj, Info, ResourceCache.GetDynamicBuffersCounter());
- break;
-
- case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
- case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
- case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
- CacheImage(pObj, Info,
- [&](const ShaderVariableVkImpl& SeparateSampler, ISampler* pSampler) {
- VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.GetDesc().Name, "' is assigned an immutable sampler");
- VERIFY_EXPR(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
- DEV_CHECK_ERR(SeparateSampler.GetDesc().ArraySize == 1 || SeparateSampler.GetDesc().ArraySize == ResDesc.ArraySize,
- "Array size (", SeparateSampler.GetDesc().ArraySize,
- ") of separate sampler variable '",
- SeparateSampler.GetDesc().Name,
- "' must be one or the same as the array size (", ResDesc.ArraySize,
- ") of separate image variable '", ResDesc.Name, "' it is assigned to");
- Uint32 SamplerArrInd = SeparateSampler.GetDesc().ArraySize == 1 ? 0 : ArrayIndex;
- SeparateSampler.BindResource(pSampler, SamplerArrInd);
- });
- break;
-
- case VK_DESCRIPTOR_TYPE_SAMPLER:
- if (!IsImmutableSamplerAssigned())
- {
- CacheSeparateSampler(pObj, Info);
- }
- 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)
- LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", ResDesc.Name, '\'');
- }
- break;
-
- case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
- CacheInputAttachment(pObj, Info);
- break;
-
- case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
- CacheAccelerationStructure(pObj, Info);
- break;
-
- default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(Info.DstRes.Type));
- }
- }
- else
- {
- if (Info.DstRes.pObject && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- LOG_ERROR_MESSAGE("Shader variable '", 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.");
- }
-
- Info.DstRes.pObject.Release();
- }
-}
-
-template <typename ObjectType, typename TPreUpdateObject>
-bool ShaderVariableVkImpl::UpdateCachedResource(UpdateInfo& Info,
- RefCntAutoPtr<ObjectType>&& pObject,
- TPreUpdateObject PreUpdateObject) const
-{
- // We cannot use ValidatedCast<> here as the resource retrieved from the
- // resource mapping can be of wrong type
- if (pObject)
- {
- if (Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && Info.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(Info.DstRes.pObject.template RawPtr<const ObjectType>(), pObject.template RawPtr<const ObjectType>());
- Info.DstRes.pObject.Attach(pObject.Detach());
- return true;
- }
- else
- {
- return false;
- }
-}
-
-void ShaderVariableVkImpl::CacheUniformBuffer(IDeviceObject* pBuffer,
- UpdateInfo& Info,
- Uint16& DynamicBuffersCounter) const
-{
- // clang-format off
- VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
- Info.DstRes.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
- "Uniform buffer resource is expected");
- // clang-format on
- RefCntAutoPtr<BufferVkImpl> pBufferVk{pBuffer, IID_BufferVk};
-#ifdef DILIGENT_DEVELOPMENT
- VerifyConstantBufferBinding(*this, Info.VarType, Info.ArrayIndex, pBuffer, pBufferVk.RawPtr(), Info.DstRes.pObject.RawPtr());
-
- /*if (pBufferVk->GetDesc().uiSizeInBytes < BufferStaticSize)
- {
- // It is OK if robustBufferAccess feature is enabled, otherwise access outside of buffer range may lead to crash or undefined behavior.
- LOG_WARNING_MESSAGE("Error binding uniform buffer '", pBufferVk->GetDesc().Name, "' to shader variable '",
- GetDesc().Name, "': buffer size in the shader (",
- BufferStaticSize, ") is incompatible with the actual buffer size (", pBufferVk->GetDesc().uiSizeInBytes, ").");
- }*/
-#endif
-
- auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferVkImpl* pOldBuffer, const BufferVkImpl* pNewBuffer) {
- 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;
- };
- if (UpdateCachedResource(Info, 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 (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorBufferInfo DescrBuffInfo = Info.DstRes.GetUniformBufferDescriptorWriteInfo();
- UpdateDescriptorHandle(Info, nullptr, &DescrBuffInfo, nullptr);
- }
- }
-}
-
-void ShaderVariableVkImpl::CacheStorageBuffer(IDeviceObject* pBufferView,
- UpdateInfo& Info,
- Uint16& DynamicBuffersCounter) const
-{
- // clang-format off
- VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
- Info.DstRes.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
- "Storage buffer resource is expected");
- // clang-format on
-
- RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk};
-#ifdef DILIGENT_DEVELOPMENT
- {
- // HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = BUFFER_VIEW_UNORDERED_ACCESS; // AZ TODO
- VerifyResourceViewBinding(*this, Info.VarType, Info.ArrayIndex, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, Info.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 '",
- GetDesc().Name, "': structured buffer view is expected.");
- }
-
- /*if (BufferStride == 0 && ViewDesc.ByteWidth < BufferStaticSize)
- {
- // It is OK if robustBufferAccess feature is enabled, otherwise access outside of buffer range may lead to crash or undefined behavior.
- LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- Name, "': buffer size in the shader (",
- BufferStaticSize, ") is incompatible with the actual buffer view size (", ViewDesc.ByteWidth, ").");
- }
-
- if (BufferStride > 0 && (ViewDesc.ByteWidth < BufferStaticSize || (ViewDesc.ByteWidth - BufferStaticSize) % BufferStride != 0))
- {
- // For buffers with dynamic arrays we know only static part size and array element stride.
- // Element stride in the shader may be differ than in the code. Here we check that the buffer size is exactly the same as the array with N elements.
- LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- Name, "': static buffer size in the shader (",
- BufferStaticSize, ") and array element stride (", BufferStride, ") are incompatible with the actual buffer view size (", ViewDesc.ByteWidth, "),",
- " this may be the result of the array element size mismatch.");
- }*/
- }
- }
-#endif
-
- auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {
- 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;
- };
-
- if (UpdateCachedResource(Info, 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 (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorBufferInfo DescrBuffInfo = Info.DstRes.GetStorageBufferDescriptorWriteInfo();
- UpdateDescriptorHandle(Info, nullptr, &DescrBuffInfo, nullptr);
- }
- }
-}
-
-void ShaderVariableVkImpl::CacheTexelBuffer(IDeviceObject* pBufferView,
- UpdateInfo& Info,
- Uint16& DynamicBuffersCounter) const
-{
- // clang-format off
- VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
- Info.DstRes.Type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
- "Uniform or storage buffer resource is expected");
- // clang-format on
-
- RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk};
-#ifdef DILIGENT_DEVELOPMENT
- {
- // HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = BUFFER_VIEW_UNORDERED_ACCESS; // AZ TODO
- VerifyResourceViewBinding(*this, Info.VarType, Info.ArrayIndex, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, Info.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) || BuffDesc.Mode == BUFFER_MODE_RAW))
- {
- LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- GetDesc().Name, "': formatted buffer view is expected.");
- }
- }
- }
-#endif
-
- auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {
- 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;
- };
-
- if (UpdateCachedResource(Info, std::move(pBufferViewVk), UpdateDynamicBuffersCounter))
- {
- // 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 (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkBufferView BuffView = Info.DstRes.pObject.RawPtr<BufferViewVkImpl>()->GetVkBufferView();
- UpdateDescriptorHandle(Info, nullptr, nullptr, &BuffView);
- }
- }
-}
-
-template <typename TCacheSampler>
-void ShaderVariableVkImpl::CacheImage(IDeviceObject* pTexView,
- UpdateInfo& Info,
- TCacheSampler CacheSampler) const
-{
- // clang-format off
- VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
- Info.DstRes.Type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
- Info.DstRes.Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- "Storage image, separate image or sampled image resource is expected");
- // clang-format on
- RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
-#ifdef DILIGENT_DEVELOPMENT
- {
- // HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = TEXTURE_VIEW_UNORDERED_ACCESS; // AZ TODO: read only
- VerifyResourceViewBinding(*this, Info.VarType, Info.ArrayIndex, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, Info.DstRes.pObject.RawPtr());
- }
-#endif
- if (UpdateCachedResource(Info, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {}))
- {
- // We can do RawPtr here safely since UpdateCachedResource() returned true
- auto* pTexViewVk = Info.DstRes.pObject.RawPtr<TextureViewVkImpl>();
-#ifdef DILIGENT_DEVELOPMENT
- if (Info.DstRes.Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && !IsImmutableSamplerAssigned())
- {
- if (pTexViewVk->GetSampler() == nullptr)
- {
- LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", GetPrintName(Info.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 (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorImageInfo DescrImgInfo = Info.DstRes.GetImageDescriptorWriteInfo(IsImmutableSamplerAssigned());
- UpdateDescriptorHandle(Info, &DescrImgInfo, nullptr, nullptr);
- }
- if (Info.SamplerInd != InvalidSamplerInd)
- {
- VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
- "Only separate images can be assigned separate samplers when using HLSL-style combined samplers.");
- VERIFY(!IsImmutableSamplerAssigned(), "Separate image can't be assigned an immutable sampler.");
- const auto& SamplerAttribs = *m_ParentManager.GetVariable(Info.SamplerInd);
- VERIFY_EXPR(SamplerAttribs.GetDesc().ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
- if (!SamplerAttribs.IsImmutableSamplerAssigned())
- {
- auto* pSampler = pTexViewVk->GetSampler();
- if (pSampler != nullptr)
- {
- CacheSampler(SamplerAttribs, pSampler);
- }
- else
- {
- LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerAttribs.GetDesc().Name,
- "' assigned to separate image '", GetPrintName(Info.ArrayIndex),
- "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\'');
- }
- }
- }
- }
-}
-
-void ShaderVariableVkImpl::CacheSeparateSampler(IDeviceObject* pSampler,
- UpdateInfo& Info) const
-{
- VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_SAMPLER, "Separate sampler resource is expected");
- VERIFY(!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 '", GetPrintName(Info.ArrayIndex),
- "'. Unexpected object type: sampler is expected");
- }
- if (Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && Info.DstRes.pObject != nullptr && Info.DstRes.pObject != pSamplerVk)
- {
- auto VarTypeStr = GetShaderVariableTypeLiteralName(Info.VarType);
- LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetPrintName(Info.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(Info, 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 (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorImageInfo DescrImgInfo = Info.DstRes.GetSamplerDescriptorWriteInfo();
- UpdateDescriptorHandle(Info, &DescrImgInfo, nullptr, nullptr);
- }
- }
-}
-
-void ShaderVariableVkImpl::CacheInputAttachment(IDeviceObject* pTexView,
- UpdateInfo& Info) const
-{
- VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "Input attachment resource is expected");
- RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
-#ifdef DILIGENT_DEVELOPMENT
- VerifyResourceViewBinding(*this, Info.VarType, Info.ArrayIndex, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, Info.DstRes.pObject.RawPtr());
-#endif
- if (UpdateCachedResource(Info, 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 (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorImageInfo DescrImgInfo = Info.DstRes.GetInputAttachmentDescriptorWriteInfo();
- UpdateDescriptorHandle(Info, &DescrImgInfo, nullptr, nullptr);
- }
- //
- }
-}
-
-void ShaderVariableVkImpl::CacheAccelerationStructure(IDeviceObject* pTLAS,
- UpdateInfo& Info) const
-{
- //VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration Structure resource is expected");
- RefCntAutoPtr<TopLevelASVkImpl> pTLASVk{pTLAS, IID_TopLevelASVk};
-#ifdef DILIGENT_DEVELOPMENT
- VerifyTLASResourceBinding(*this, Info.VarType, Info.ArrayIndex, pTLASVk.RawPtr(), Info.DstRes.pObject.RawPtr());
-#endif
- if (UpdateCachedResource(Info, 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 (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkWriteDescriptorSetAccelerationStructureKHR DescrASInfo = Info.DstRes.GetAccelerationStructureWriteInfo();
- UpdateDescriptorHandle(Info, nullptr, nullptr, nullptr, &DescrASInfo);
- }
- //
- }
-}
-
-bool ShaderVariableVkImpl::IsImmutableSamplerAssigned() const
-{
- return true; // AZ TODO
-}
-
-void ShaderVariableVkImpl::UpdateDescriptorHandle(UpdateInfo& Info,
- const VkDescriptorImageInfo* pImageInfo,
- const VkDescriptorBufferInfo* pBufferInfo,
- const VkBufferView* pTexelBufferView,
- const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo) const
-{
- VERIFY_EXPR(Info.vkDescrSet != VK_NULL_HANDLE);
-
- VkWriteDescriptorSet WriteDescrSet;
- WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- WriteDescrSet.pNext = pAccelStructInfo;
- WriteDescrSet.dstSet = Info.vkDescrSet;
- WriteDescrSet.dstBinding = GetBinding().Binding;
- WriteDescrSet.dstArrayElement = Info.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 = PipelineResourceSignatureVkImpl::GetVkDescriptorType(GetDesc());
- WriteDescrSet.pImageInfo = pImageInfo;
- WriteDescrSet.pBufferInfo = pBufferInfo;
- WriteDescrSet.pTexelBufferView = pTexelBufferView;
-
- m_ParentManager.m_pSignature->GetDevice()->GetLogicalDevice().UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr);
-}
-
-String ShaderVariableVkImpl::GetPrintName(Uint32 ArrayInd) const
-{
- auto& ResDesc = GetDesc();
- VERIFY_EXPR(ArrayInd < ResDesc.ArraySize);
-
- if (ResDesc.ArraySize > 1)
- {
- std::stringstream ss;
- ss << ResDesc.Name << '[' << ArrayInd << ']';
- return ss.str();
- }
- else
- return ResDesc.Name;
-}
-
-RESOURCE_DIMENSION ShaderVariableVkImpl::GetResourceDimension() const
-{
- return GetDesc().ResourceDim;
-}
-
-bool ShaderVariableVkImpl::IsMultisample() const
-{
- return false; // AZ TODO
+ pSign->BindResource(pObj, ArrayIndex, m_ResIndex, ResourceCache);
}
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
index 264d49a5..c2ac34a3 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
@@ -32,6 +32,7 @@
#include "VulkanTypeConversions.hpp"
#include "PlatformMisc.hpp"
#include "Align.hpp"
+#include "BasicMath.hpp"
namespace Diligent
{
@@ -1194,9 +1195,8 @@ VkPipelineStageFlags ResourceStateFlagsToVkPipelineStageFlags(RESOURCE_STATE Sta
VkPipelineStageFlags vkPipelineStages = 0;
while (StateFlags != RESOURCE_STATE_UNKNOWN)
{
- auto StateBit = static_cast<RESOURCE_STATE>(1 << PlatformMisc::GetLSB(Uint32{StateFlags}));
+ auto StateBit = ExtractBit(StateFlags);
vkPipelineStages |= ResourceStateFlagToVkPipelineStage(StateBit, vkShaderStages);
- StateFlags &= ~StateBit;
}
return vkPipelineStages;
}
@@ -1299,7 +1299,7 @@ VkAccessFlags AccelStructStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags)
Uint32 Bits = StateFlags;
while (Bits != 0)
{
- auto Bit = static_cast<RESOURCE_STATE>(1 << PlatformMisc::GetLSB(Bits));
+ auto Bit = ExtractBit(Bits);
switch (Bit)
{
// clang-format off
@@ -1309,7 +1309,6 @@ VkAccessFlags AccelStructStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags)
default: UNEXPECTED("Unexpected resource state flag");
// clang-format on
}
- Bits &= ~Bit;
}
return AccessFlags;
}
@@ -1637,9 +1636,8 @@ VkShaderStageFlags ShaderTypesToVkShaderStageFlags(SHADER_TYPE ShaderTypes)
VkShaderStageFlags Result = 0;
while (ShaderTypes != SHADER_TYPE_UNKNOWN)
{
- auto Type = static_cast<SHADER_TYPE>(1u << PlatformMisc::GetLSB(Uint32{ShaderTypes}));
+ auto Type = ExtractBit(ShaderTypes);
Result |= ShaderTypeToVkShaderStageFlagBit(Type);
- ShaderTypes = ShaderTypes & ~Type;
}
return Result;
}
@@ -1652,7 +1650,7 @@ VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureF
VkBuildAccelerationStructureFlagsKHR Result = 0;
while (Flags != RAYTRACING_BUILD_AS_NONE)
{
- auto FlagBit = static_cast<RAYTRACING_BUILD_AS_FLAGS>(1u << PlatformMisc::GetLSB(Uint32{Flags}));
+ auto FlagBit = ExtractBit(Flags);
switch (FlagBit)
{
// clang-format off
@@ -1664,7 +1662,6 @@ VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureF
// clang-format on
default: UNEXPECTED("unknown build AS flag");
}
- Flags = Flags & ~FlagBit;
}
return Result;
}
@@ -1677,16 +1674,15 @@ VkGeometryFlagsKHR GeometryFlagsToVkGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flag
VkGeometryFlagsKHR Result = 0;
while (Flags != RAYTRACING_GEOMETRY_FLAG_NONE)
{
- auto FlagBit = static_cast<RAYTRACING_GEOMETRY_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags}));
+ auto FlagBit = ExtractBit(Flags);
switch (FlagBit)
{
// clang-format off
- case RAYTRACING_GEOMETRY_FLAG_OPAQUE: Result |= VK_GEOMETRY_OPAQUE_BIT_KHR; break;
+ case RAYTRACING_GEOMETRY_FLAG_OPAQUE: Result |= VK_GEOMETRY_OPAQUE_BIT_KHR; break;
case RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANY_HIT_INVOCATION: Result |= VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; break;
// clang-format on
default: UNEXPECTED("unknown geometry flag");
}
- Flags = Flags & ~FlagBit;
}
return Result;
}
@@ -1699,18 +1695,17 @@ VkGeometryInstanceFlagsKHR InstanceFlagsToVkGeometryInstanceFlags(RAYTRACING_INS
VkGeometryInstanceFlagsKHR Result = 0;
while (Flags != RAYTRACING_INSTANCE_NONE)
{
- auto FlagBit = static_cast<RAYTRACING_INSTANCE_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags}));
+ auto FlagBit = ExtractBit(Flags);
switch (FlagBit)
{
// clang-format off
- case RAYTRACING_INSTANCE_TRIANGLE_FACING_CULL_DISABLE: Result |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; break;
+ case RAYTRACING_INSTANCE_TRIANGLE_FACING_CULL_DISABLE: Result |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; break;
case RAYTRACING_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE: Result |= VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR; break;
- case RAYTRACING_INSTANCE_FORCE_OPAQUE: Result |= VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR; break;
- case RAYTRACING_INSTANCE_FORCE_NO_OPAQUE: Result |= VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR; break;
+ case RAYTRACING_INSTANCE_FORCE_OPAQUE: Result |= VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR; break;
+ case RAYTRACING_INSTANCE_FORCE_NO_OPAQUE: Result |= VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR; break;
// clang-format on
default: UNEXPECTED("unknown instance flag");
}
- Flags = Flags & ~FlagBit;
}
return Result;
}