git.s-ol.nu ~forks/DiligentCore / cf7b750
pipeline resource signature for vulkan azhirnov 8 months ago
32 changed file(s) with 2376 addition(s) and 1718 deletion(s). Raw diff Collapse all Expand all
21882188 return x | (y << 1u);
21892189 }
21902190
2191 template <typename T>
2192 inline T ExtractBit(T& bits)
2193 {
2194 static_assert(std::is_enum<T>::value || std::is_integral<T>::value, "T must be enum or integer type");
2195
2196 using U = std::conditional_t<(sizeof(T) > sizeof(Uint32)), Uint64, Uint32>;
2197 VERIFY_EXPR(static_cast<U>(bits) > 0);
2198
2199 const U result = static_cast<U>(bits) & ~(static_cast<U>(bits) - U{1});
2200 bits = static_cast<T>(static_cast<U>(bits) & ~result);
2201
2202 return static_cast<T>(result);
2203 }
2204
21912205 } // namespace Diligent
21922206
21932207
135135
136136 void AddSpaceForString(const Char* str) noexcept
137137 {
138 VERIFY_EXPR(str != nullptr);
139 AddSpace(strlen(str) + 1, 1);
138 if (str != nullptr)
139 AddSpace<Char>(strlen(str) + 1);
140140 }
141141
142142 void AddSpaceForString(const String& str) noexcept
143143 {
144 AddSpaceForString(str.c_str());
144 if (!str.empty())
145 AddSpace<String::value_type>(str.length() + 1);
145146 }
146147
147148 void Reserve(size_t size)
3030 #include "../../Platforms/interface/Atomics.hpp"
3131 #include "ValidatedCast.hpp"
3232 #include "RefCountedObjectImpl.hpp"
33 #include "CompilerDefinitions.h"
3433
3534 namespace Diligent
3635 {
135134 m_pObject = pObj;
136135 }
137136
138 NODISCARD T* Detach() noexcept
137 T* Detach() noexcept
139138 {
140139 T* pObj = m_pObject;
141140 m_pObject = nullptr;
6262 bool bIsDeviceInternal = false) :
6363 TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}
6464 {
65 this->m_Desc.Resources = nullptr;
66 this->m_Desc.ImmutableSamplers = nullptr;
65 this->m_Desc.Resources = nullptr;
66 this->m_Desc.ImmutableSamplers = nullptr;
67 this->m_Desc.CombinedSamplerSuffix = nullptr;
6768 }
6869
6970 ~PipelineResourceSignatureBase()
7374
7475 IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineResourceSignature, TDeviceObjectBase)
7576
76 Uint32 GetVariableCount(SHADER_TYPE ShaderType) const
77 {
78 // AZ TODO: optimize
79 Uint32 Count = 0;
80 for (Uint32 i = 0; i < this->m_Desc.NumResources; ++i)
81 {
82 auto& Res = this->m_Desc.Resources[i];
83 if (Res.VarType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC && (Res.ShaderStages & ShaderType))
84 ++Count;
85 }
86 return Count;
87 }
88
89 Uint32 GetVariableGlobalIndexByName(SHADER_TYPE ShaderType, const char* Name) const
90 {
91 // AZ TODO: optimize
92 for (Uint32 i = 0; i < this->m_Desc.NumResources; ++i)
93 {
94 auto& Res = this->m_Desc.Resources[i];
95 if (Res.VarType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC && (Res.ShaderStages & ShaderType))
96 {
97 if (strcmp(Name, Res.Name) == 0)
98 return i;
99 }
100 }
101 return ~0u;
102 }
103
104 Uint32 GetVariableGlobalIndexByIndex(SHADER_TYPE ShaderType, Uint32 Index) const
105 {
106 // AZ TODO: optimize
107 Uint32 Count = 0;
108 for (Uint32 i = 0; i < this->m_Desc.NumResources; ++i)
109 {
110 auto& Res = this->m_Desc.Resources[i];
111 if (Res.VarType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC && (Res.ShaderStages & ShaderType))
112 {
113 if (Index == Count)
114 return i;
115
116 ++Count;
117 }
118 }
119 return ~0u;
120 }
121
122 Uint32 GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE VarType) const
123 {
124 // AZ TODO: optimize
125 Uint32 Count = 0;
126 for (Uint32 i = 0; i < this->m_Desc.NumResources; ++i)
127 {
128 auto& Res = this->m_Desc.Resources[i];
129 if (Res.VarType == VarType)
130 Count += Res.ArraySize;
131 }
132 return Count;
133 }
134
135 PipelineResourceDesc GetResource(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 Index) const
136 {
137 return {};
138 }
139
14077 size_t GetHash() const { return m_Hash; }
14178
14279 PIPELINE_TYPE GetPipelineType() const { return m_PipelineType; }
80
81 const char* GetCombinedSamplerSuffix() const { return this->m_Desc.CombinedSamplerSuffix; }
82
83 bool IsUsingCombinedSamplers() const { return this->m_Desc.CombinedSamplerSuffix != nullptr; }
84 bool IsUsingSeparateSamplers() const { return !IsUsingCombinedSamplers(); }
14385
14486 protected:
14587 #define LOG_PRS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a pipeline resource signature '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
14688
147 void ReserveSpaceForDescription(FixedLinearAllocator& Allocator, const PipelineResourceSignatureDesc& Desc) noexcept(false)
148 {
149 if (Desc.NumResources == 0)
150 LOG_PRS_ERROR_AND_THROW("AZ TODO");
151
89 void ReserveSpaceForDescription(FixedLinearAllocator& Allocator, const PipelineResourceSignatureDesc& Desc) const noexcept(false)
90 {
15291 Allocator.AddSpace<PipelineResourceDesc>(Desc.NumResources);
15392 Allocator.AddSpace<ImmutableSamplerDesc>(Desc.NumImmutableSamplers);
15493
175114
176115 Allocator.AddSpaceForString(Desc.ImmutableSamplers[i].SamplerOrTextureName);
177116 }
117
118 Allocator.AddSpaceForString(Desc.CombinedSamplerSuffix);
178119 }
179120
180121 void CopyDescription(FixedLinearAllocator& Allocator, const PipelineResourceSignatureDesc& Desc) noexcept(false)
182123 PipelineResourceDesc* pResources = Allocator.Allocate<PipelineResourceDesc>(this->m_Desc.NumResources);
183124 ImmutableSamplerDesc* pSamplers = Allocator.Allocate<ImmutableSamplerDesc>(this->m_Desc.NumImmutableSamplers);
184125
185 m_Hash = ComputeHash(Desc.NumResources, Desc.NumImmutableSamplers);
126 m_Hash = ComputeHash(Desc.NumResources, Desc.NumImmutableSamplers, Desc.BindingIndex);
186127
187128 for (Uint32 i = 0; i < Desc.NumResources; ++i)
188129 {
190131 Dst = Desc.Resources[i];
191132 Dst.Name = Allocator.CopyString(Desc.Resources[i].Name);
192133
193 HashCombine(m_Hash, CStringHash<char>{}(Dst.Name), Dst.ArraySize, Dst.ResourceType, Dst.ShaderStages, Dst.VarType, Dst.Flags);
134 HashCombine(m_Hash, Dst.ArraySize, Dst.ResourceType, Dst.ShaderStages, Dst.VarType, Dst.Flags);
194135 }
195136
196137 for (Uint32 i = 0; i < Desc.NumImmutableSamplers; ++i)
199140 Dst = Desc.ImmutableSamplers[i];
200141 Dst.SamplerOrTextureName = Allocator.CopyString(Desc.ImmutableSamplers[i].SamplerOrTextureName);
201142
202 //HashCombine(m_Hash, CStringHash<char>{}(Dst.Name), Dst.ShaderStages, Dst.Desc); // AZ TODO
203 }
204
205 this->m_Desc.Resources = pResources;
206 this->m_Desc.ImmutableSamplers = pSamplers;
143 HashCombine(m_Hash, Dst.ShaderStages, Dst.Desc);
144 }
145
146 this->m_Desc.Resources = pResources;
147 this->m_Desc.ImmutableSamplers = pSamplers;
148 this->m_Desc.CombinedSamplerSuffix = Allocator.CopyString(Desc.CombinedSamplerSuffix);
207149 }
208150
209151 void Destruct()
210152 {
211153 VERIFY(!m_IsDestructed, "This object has already been destructed");
212154
213 this->m_Desc.Resources = nullptr;
214 this->m_Desc.ImmutableSamplers = nullptr;
155 this->m_Desc.Resources = nullptr;
156 this->m_Desc.ImmutableSamplers = nullptr;
157 this->m_Desc.CombinedSamplerSuffix = nullptr;
215158
216159 #if DILIGENT_DEBUG
217160 m_IsDestructed = true;
230173 }
231174
232175 const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_PipelineType);
233 const auto LayoutInd = StaticVarIndex[ShaderTypeInd];
234 if (LayoutInd < 0)
176 const auto VarMngrInd = StaticVarIndex[ShaderTypeInd];
177 if (VarMngrInd < 0)
235178 {
236179 LOG_WARNING_MESSAGE("Unable to get the number of static variables in shader stage ", GetShaderTypeLiteralName(ShaderType),
237180 " as the stage is inactive in PSO '", this->m_Desc.Name, "'.");
238181 }
239182
240 return LayoutInd;
183 return VarMngrInd;
241184 }
242185
243186 Int8 GetStaticVariableByNameHelper(SHADER_TYPE ShaderType, const Char* Name, const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& StaticVarIndex) const
250193 }
251194
252195 const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_PipelineType);
253 const auto LayoutInd = StaticVarIndex[ShaderTypeInd];
254 if (LayoutInd < 0)
196 const auto VarMngrInd = StaticVarIndex[ShaderTypeInd];
197 if (VarMngrInd < 0)
255198 {
256199 LOG_WARNING_MESSAGE("Unable to find static variable '", Name, "' in shader stage ", GetShaderTypeLiteralName(ShaderType),
257200 " as the stage is inactive in PSO '", this->m_Desc.Name, "'.");
258201 }
259202
260 return LayoutInd;
203 return VarMngrInd;
261204 }
262205
263206 Int8 GetStaticVariableByIndexHelper(SHADER_TYPE ShaderType, Uint32 Index, const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& StaticVarIndex) const
270213 }
271214
272215 const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_PipelineType);
273 const auto LayoutInd = StaticVarIndex[ShaderTypeInd];
274 if (LayoutInd < 0)
216 const auto VarMngrInd = StaticVarIndex[ShaderTypeInd];
217 if (VarMngrInd < 0)
275218 {
276219 LOG_WARNING_MESSAGE("Unable to get static variable at index ", Index, " in shader stage ", GetShaderTypeLiteralName(ShaderType),
277220 " as the stage is inactive in PSO '", this->m_Desc.Name, "'.");
278221 }
279222
280 return LayoutInd;
223 return VarMngrInd;
281224 }
282225
283226 protected:
215215 return m_BufferSlotsUsed;
216216 }
217217
218 SHADER_TYPE GetShaderStageType(Uint32 Stage) const { return m_ShaderStageTypes[Stage]; }
219 Uint32 GetNumShaderStages() const { return m_NumShaderStages; }
220
221 // This function only compares shader resource layout hashes, so
222 // it can potentially give false negatives
223 bool IsIncompatibleWith(const IPipelineState* pPSO) const
224 {
225 return false;
226 //return m_ShaderResourceLayoutHash != ValidatedCast<const PipelineStateBase>(pPSO)->m_ShaderResourceLayoutHash;
227 }
218 //SHADER_TYPE GetShaderStageType(Uint32 Stage) const { return m_ShaderStageTypes[Stage]; }
219 //Uint32 GetNumShaderStages() const { return m_NumShaderStages; }
228220
229221 virtual const GraphicsPipelineDesc& DILIGENT_CALL_TYPE GetGraphicsPipelineDesc() const override final
230222 {
243235 virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding,
244236 bool InitStaticResources) override final
245237 {
246 auto* pSign = GetResourceSignature(0);
247 if (pSign)
248 return pSign->CreateShaderResourceBinding(ppShaderResourceBinding, InitStaticResources);
238 *ppShaderResourceBinding = nullptr;
239
240 if (GetResourceSignatureCount() != 1)
241 return;
242
243 return GetResourceSignature(0)->CreateShaderResourceBinding(ppShaderResourceBinding, InitStaticResources);
249244 }
250245
251246 virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByName(SHADER_TYPE ShaderType,
252247 const Char* Name) override final
253248 {
254 VERIFY_EXPR(GetResourceSignatureCount() == 1);
255
256 auto* pSign = GetResourceSignature(0);
257 if (pSign)
258 return pSign->GetStaticVariableByName(ShaderType, Name);
259
260 return nullptr;
249 if (GetResourceSignatureCount() != 1)
250 return nullptr;
251
252 return GetResourceSignature(0)->GetStaticVariableByName(ShaderType, Name);
261253 }
262254
263255 virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByIndex(SHADER_TYPE ShaderType,
264256 Uint32 Index) override final
265257 {
266 VERIFY_EXPR(GetResourceSignatureCount() == 1);
267
268 auto* pSign = GetResourceSignature(0);
269 if (pSign)
270 return pSign->GetStaticVariableByIndex(ShaderType, Index);
271
272 return nullptr;
258 if (GetResourceSignatureCount() != 1)
259 return nullptr;
260
261 return GetResourceSignature(0)->GetStaticVariableByIndex(ShaderType, Index);
273262 }
274263
275264 virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final
276265 {
277 VERIFY_EXPR(GetResourceSignatureCount() == 1);
278
279 auto* pSign = GetResourceSignature(0);
280 if (pSign)
281 return pSign->GetStaticVariableCount(ShaderType);
282
283 return 0;
266 if (GetResourceSignatureCount() != 1)
267 return 0;
268
269 return GetResourceSignature(0)->GetStaticVariableCount(ShaderType);
270 }
271
272 virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) override final
273 {
274 if (GetResourceSignatureCount() != 1)
275 return;
276
277 return GetResourceSignature(0)->BindStaticResources(ShaderFlags, pResourceMapping, Flags);
284278 }
285279
286280 inline void CopyShaderHandle(const char* Name, void* pData, size_t DataSize) const
728722 }
729723
730724 protected:
725 //size_t m_ShaderResourceLayoutHash = 0;
726
731727 Uint32* m_pStrides = nullptr;
732728 Uint8 m_BufferSlotsUsed = 0;
733729
734730 Uint8 m_NumShaderStages = 0; ///< Number of shader stages in this PSO
735731
736732 /// Array of shader types for every shader stage used by this PSO
737 std::array<SHADER_TYPE, MAX_SHADERS_IN_PIPELINE> m_ShaderStageTypes = {};
733 std::array<SHADER_TYPE, MAX_SHADERS_IN_PIPELINE> m_ShaderStageTypes = {}; // AZ TODO: remove ?
738734
739735 RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object
740736
6565 {}
6666
6767 IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderResourceBinding, TObjectBase)
68
69 /// Implementation of IShaderResourceBinding::GetPipelineState().
70 //virtual IPipelineState* DILIGENT_CALL_TYPE GetPipelineState() override final
71 //{
72 // return m_pPSO;
73 //}
74
75 //template <typename PSOType>
76 //PSOType* GetPipelineState()
77 //{
78 // return ValidatedCast<PSOType>(m_pPSO);
79 //}
80
81 //template <typename PSOType>
82 //PSOType* GetPipelineState() const
83 //{
84 // return ValidatedCast<PSOType>(m_pPSO);
85 //}
8668
8769 Uint32 GetBindingIndex() const
8870 {
105105
106106 /// AZ TODO: comment
107107 PIPELINE_RESOURCE_FLAGS Flags DEFAULT_INITIALIZER(PIPELINE_RESOURCE_FLAG_UNKNOWN);
108
109 /// AZ TODO: comment
110 RESOURCE_DIMENSION ResourceDim DEFAULT_INITIALIZER(RESOURCE_DIM_UNDEFINED);
111108
112109 #if DILIGENT_CPP_INTERFACE
113110 PipelineResourceDesc()noexcept{}
117114 SHADER_RESOURCE_TYPE _ResourceType,
118115 SHADER_TYPE _ShaderStages,
119116 SHADER_RESOURCE_VARIABLE_TYPE _VarType,
120 RESOURCE_DIMENSION _Dim = RESOURCE_DIM_UNDEFINED,
121117 PIPELINE_RESOURCE_FLAGS _Flags = PIPELINE_RESOURCE_FLAG_UNKNOWN)noexcept :
122118 Name {_Name },
123119 ArraySize {_ArraySize },
124120 ResourceType{_ResourceType},
125121 ShaderStages{_ShaderStages},
126122 VarType {_VarType },
127 Flags {_Flags },
128 ResourceDim {_Dim }
123 Flags {_Flags }
129124 {}
130125 #endif
131126 };
152147
153148 /// AZ TODO: comment
154149 Uint16 BindingOffsets [SHADER_RESOURCE_TYPE_LAST + 1] DEFAULT_INITIALIZER({});
150
151 /// If UseCombinedTextureSamplers is true, defines the suffix added to the
152 /// texture variable name to get corresponding sampler name. For example,
153 /// for default value "_sampler", a texture named "tex" will be combined
154 /// with sampler named "tex_sampler".
155 /// If UseCombinedTextureSamplers is false, this member is ignored.
156 const Char* CombinedSamplerSuffix DEFAULT_INITIALIZER("_sampler");
155157
156158 /// Shader resource binding allocation granularity
157159
194196 IShaderResourceBinding** ppShaderResourceBinding,
195197 bool InitStaticResources DEFAULT_VALUE(false)) PURE;
196198
199
200 /// Binds resources for all shaders in the pipeline resource signature
201
202 /// \param [in] ShaderFlags - Flags that specify shader stages, for which resources will be bound.
203 /// Any combination of Diligent::SHADER_TYPE may be used.
204 /// \param [in] pResourceMapping - Pointer to the resource mapping interface.
205 /// \param [in] Flags - Additional flags. See Diligent::BIND_SHADER_RESOURCES_FLAGS.
206 VIRTUAL void METHOD(BindStaticResources)(THIS_
207 Uint32 ShaderFlags,
208 IResourceMapping* pResourceMapping,
209 Uint32 Flags) PURE;
210
197211
198212 /// Returns static shader resource variable. If the variable is not found,
199213 /// returns nullptr.
230244 /// Mutable and dynamic variables are accessed through Shader Resource Binding object.
231245 VIRTUAL Uint32 METHOD(GetStaticVariableCount)(THIS_
232246 SHADER_TYPE ShaderType) CONST PURE;
247
248 /// AZ TODO: comment
249 VIRTUAL bool METHOD(IsCompatibleWith)(THIS_
250 const struct IPipelineResourceSignature* pPRS) CONST PURE;
233251 };
234252 DILIGENT_END_INTERFACE
235253
242260 # define IPipelineResourceSignature_GetDesc(This) (const struct PipelineResourceSignatureDesc*)IDeviceObject_GetDesc(This)
243261
244262 # define IPipelineResourceSignature_CreateShaderResourceBinding(This, ...) CALL_IFACE_METHOD(PipelineResourceSignature, CreateShaderResourceBinding, This, __VA_ARGS__)
263 # define IPipelineResourceSignature_BindStaticResources(This, ...) CALL_IFACE_METHOD(PipelineResourceSignature, BindStaticResources, This, __VA_ARGS__)
245264 # define IPipelineResourceSignature_GetStaticVariableByName(This, ...) CALL_IFACE_METHOD(PipelineResourceSignature, GetStaticVariableByName, This, __VA_ARGS__)
246265 # define IPipelineResourceSignature_GetStaticVariableByIndex(This, ...) CALL_IFACE_METHOD(PipelineResourceSignature, GetStaticVariableByIndex, This, __VA_ARGS__)
247266 # define IPipelineResourceSignature_GetStaticVariableCount(This, ...) CALL_IFACE_METHOD(PipelineResourceSignature, GetStaticVariableCount, This, __VA_ARGS__)
267 # define IPipelineResourceSignature_IsCompatibleWith(This, ...) CALL_IFACE_METHOD(PipelineResourceSignature, IsCompatibleWith, This, __VA_ARGS__)
248268
249269 // clang-format on
250270
315315
316316 /// This member defines allocation granularity for internal resources required by the shader resource
317317 /// binding object instances.
318 /// Has no effect if used pipeline resource signature.
318319 Uint32 SRBAllocationGranularity DEFAULT_INITIALIZER(1);
319320
320321 /// Defines which command queues this pipeline state can be used with
366367 /// Pipeline state creation flags, see Diligent::PSO_CREATE_FLAGS.
367368 PSO_CREATE_FLAGS Flags DEFAULT_INITIALIZER(PSO_CREATE_FLAG_NONE);
368369
369 /// AZ TODO
370 /// AZ TODO: comment
370371 IPipelineResourceSignature** ppResourceSignatures DEFAULT_INITIALIZER(nullptr);
371372
372 /// AZ TODO
373 /// AZ TODO: comment
373374 Uint32 ResourceSignaturesCount DEFAULT_INITIALIZER(0);
374375 };
375376 typedef struct PipelineStateCreateInfo PipelineStateCreateInfo;
566567
567568
568569 /// Checks if this pipeline state object is compatible with another PSO
570 // Deprecated: use IsCompatibleWith() for pipeline resource signature.
569571
570572 /// If two pipeline state objects are compatible, they can use shader resource binding
571573 /// objects interchangebly, i.e. SRBs created by one PSO can be committed
284284 /// the sampler assigned to the shader resource view is automatically set when
285285 /// the view is bound. Otherwise samplers need to be explicitly set similar to other
286286 /// shader variables.
287 /// Has no effect if used pipeline resource signature.
287288 bool UseCombinedTextureSamplers DEFAULT_INITIALIZER(false);
288289
289290 /// If UseCombinedTextureSamplers is true, defines the suffix added to the
291292 /// for default value "_sampler", a texture named "tex" will be combined
292293 /// with sampler named "tex_sampler".
293294 /// If UseCombinedTextureSamplers is false, this member is ignored.
295 /// Has no effect if used pipeline resource signature.
294296 const Char* CombinedSamplerSuffix DEFAULT_INITIALIZER("_sampler");
295297
296298 /// Shader description. See Diligent::ShaderDesc.
1616 include/GenerateMipsVkHelper.hpp
1717 include/pch.h
1818 include/PipelineLayoutVk.hpp
19 include/PipelineLayoutCacheVk.hpp
2019 include/PipelineStateVkImpl.hpp
2120 include/QueryManagerVk.hpp
2221 include/QueryVkImpl.hpp
9291 src/VulkanDynamicHeap.cpp
9392 src/FramebufferCache.cpp
9493 src/GenerateMipsVkHelper.cpp
95 src/PipelineLayoutCacheVk.cpp
9694 src/PipelineLayoutVk.cpp
9795 src/PipelineStateVkImpl.cpp
9896 src/QueryManagerVk.cpp
396396 void CommitVkVertexBuffers();
397397 void CommitViewports();
398398 void CommitScissorRects();
399 void BindShaderResources(PipelineStateVkImpl* pPipelineStateVk);
400399
401400 __forceinline void TransitionOrVerifyBufferState(BufferVkImpl& Buffer,
402401 RESOURCE_STATE_TRANSITION_MODE TransitionMode,
476475 Uint32 NumCommands = 0;
477476 } m_State;
478477
478 // graphics, compute, ray tracing
479 static constexpr Uint32 PIPELINE_BIND_POINTS = 3;
480
481 // static and dynamic descriptor sets
482 static constexpr Uint32 MAX_DESCR_SET_PER_SIGNATURE = 2;
483
484 struct DescriptorSetBindInfo
485 {
486 using ShaderResourceArray = std::array<RefCntAutoPtr<ShaderResourceBindingVkImpl>, MAX_RESOURCE_SIGNATURES>;
487 using VkDescSetArray = std::array<VkDescriptorSet, MAX_RESOURCE_SIGNATURES * MAX_DESCR_SET_PER_SIGNATURE>;
488 using BoolArray = std::bitset<MAX_RESOURCE_SIGNATURES>;
489
490 ShaderResourceArray Resources;
491 VkDescSetArray vkSets = {};
492 BoolArray PendingVkSet = {0}; // 'true' if new descriptor set must be bound
493 BoolArray PendingDynamicDescriptors = {0}; // 'true' if dynamic descriptor set must be bound
494 BoolArray DynamicBuffersPresent = {0};
495
496 DescriptorSetBindInfo()
497 {}
498
499 void Reset()
500 {
501 PendingVkSet.reset();
502 DynamicBuffersPresent.reset();
503 PendingDynamicDescriptors.reset();
504 Resources.fill({});
505
506 #ifdef DILIGENT_DEBUG
507 vkSets.fill(VK_NULL_HANDLE);
508 #endif
509 }
510
511 __forceinline bool RequireUpdate(bool Intact = false) const
512 {
513 return PendingVkSet.any() || PendingDynamicDescriptors.any() || (DynamicBuffersPresent.any() && !Intact);
514 }
515 };
516
517 void BindShaderResources(PipelineStateVkImpl* pPipelineStateVk);
518 void BindDescriptorSetsWithDynamicOffsets(DescriptorSetBindInfo& DescrSetBindInfo);
519 void ValidateShaderResources();
479520
480521 /// AZ TODO: comment
481 using DescSetBindingInfoArray = std::array<PipelineLayoutVk::DescriptorSetBindInfo, 3>;
482 DescSetBindingInfoArray m_DescrSetBindInfo;
522 std::array<DescriptorSetBindInfo, PIPELINE_BIND_POINTS> m_DescrSetBindInfo;
483523
484524 /// AZ TODO: comment
485 using ShaderResourcePerPipelineType = std::array<std::array<RefCntAutoPtr<ShaderResourceBindingVkImpl>, MAX_RESOURCE_SIGNATURES>, 3>;
486 ShaderResourcePerPipelineType m_ShaderResources;
525 std::vector<Uint32> m_DynamicBufferOffsets;
487526
488527 /// Render pass that matches currently bound render targets.
489528 /// This render pass may or may not be currently set in the command buffer
+0
-82
Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp less more
0 /*
1 * Copyright 2019-2021 Diligent Graphics LLC
2 * Copyright 2015-2019 Egor Yusov
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * In no event and under no legal theory, whether in tort (including negligence),
17 * contract, or otherwise, unless required by applicable law (such as deliberate
18 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
19 * liable for any damages, including any direct, indirect, special, incidental,
20 * or consequential damages of any character arising as a result of this License or
21 * out of the use or inability to use the software (including but not limited to damages
22 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23 * all other commercial damages or losses), even if such Contributor has been advised
24 * of the possibility of such damages.
25 */
26
27 #pragma once
28
29 /// \file
30 /// Declaration of Diligent::PipelineLayoutCacheVk class
31
32 #include <unordered_set>
33 #include <mutex>
34 #include "VulkanUtilities/VulkanObjectWrappers.hpp"
35 #include "PipelineLayoutVk.hpp"
36
37 namespace Diligent
38 {
39
40 class PipelineLayoutCacheVk
41 {
42 public:
43 PipelineLayoutCacheVk(RenderDeviceVkImpl& DeviceVKImpl) :
44 m_DeviceVk{DeviceVKImpl}
45 {}
46
47 // clang-format off
48 PipelineLayoutCacheVk (const PipelineLayoutCacheVk&) = delete;
49 PipelineLayoutCacheVk (PipelineLayoutCacheVk&&) = delete;
50 PipelineLayoutCacheVk& operator = (const PipelineLayoutCacheVk&) = delete;
51 PipelineLayoutCacheVk& operator = (PipelineLayoutCacheVk&&) = delete;
52 // clang-format on
53
54 ~PipelineLayoutCacheVk();
55
56 RefCntAutoPtr<PipelineLayoutVk> GetLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
57
58 void OnDestroyLayout(PipelineLayoutVk* pLayout);
59
60 private:
61 struct PipelineLayoutHash
62 {
63 std::size_t operator()(const PipelineLayoutVk* Key) const noexcept
64 {
65 return Key->GetHash();
66 }
67 };
68
69 struct PipelineLayoutCompare
70 {
71 bool operator()(const PipelineLayoutVk* lhs, const PipelineLayoutVk* rhs) const noexcept;
72 };
73
74 RenderDeviceVkImpl& m_DeviceVk;
75
76 std::mutex m_Mutex;
77
78 std::unordered_set<PipelineLayoutVk*, PipelineLayoutHash, PipelineLayoutCompare> m_Cache;
79 };
80
81 } // namespace Diligent
4242 class ShaderResourceCacheVk;
4343
4444 /// Implementation of the Diligent::PipelineLayoutVk class
45 class PipelineLayoutVk final : public ObjectBase<IObject>
45 class PipelineLayoutVk
4646 {
4747 public:
48 PipelineLayoutVk(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
49 ~PipelineLayoutVk();
48 PipelineLayoutVk();
5049
51 using ObjectBase<IObject>::Release;
52
53 void Finalize();
50 void Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
51 void Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask);
5452
5553 size_t GetHash() const;
5654
5755 VkPipelineLayout GetVkPipelineLayout() const { return m_VkPipelineLayout; }
58 PIPELINE_TYPE GetPipelineType() const { return m_PipelineType; }
5956 Uint32 GetSignatureCount() const { return m_SignatureCount; }
6057 Uint32 GetDescriptorSetCount() const { return m_DescrSetCount; }
6158 Uint32 GetDynamicOffsetCount() const { return m_DynamicOffsetCount; }
6259
63 IPipelineResourceSignature* GetSignature(Uint32 index) const
60 PipelineResourceSignatureVkImpl* GetSignature(Uint32 index) const
6461 {
6562 VERIFY_EXPR(index < m_SignatureCount);
66 return m_Signatures[index].RawPtr<IPipelineResourceSignature>();
63 return m_Signatures[index].RawPtr<PipelineResourceSignatureVkImpl>();
6764 }
6865
69 bool HasSignature(IPipelineResourceSignature* pPRS) const
70 {
71 Uint32 Index = pPRS->GetDesc().BindingIndex;
72 return Index < m_SignatureCount && m_Signatures[Index].RawPtr() == pPRS;
73 }
74
75 Uint32 GetDescrSetIndex(IPipelineResourceSignature* pPRS) const
66 Uint32 GetDescrSetIndex(const IPipelineResourceSignature* pPRS) const
7667 {
7768 Uint32 Index = pPRS->GetDesc().BindingIndex;
7869 return Index < m_SignatureCount ? m_DescSetOffset[Index] : ~0u;
7970 }
8071
81 Uint32 GetDynamicBufferOffset(IPipelineResourceSignature* pPRS) const
72 Uint32 GetDynamicBufferOffset(const IPipelineResourceSignature* pPRS) const
8273 {
8374 Uint32 Index = pPRS->GetDesc().BindingIndex;
8475 return Index < m_SignatureCount ? m_DynBufOffset[Index] : 0;
9283 };
9384 bool GetResourceInfo(const char* Name, SHADER_TYPE Stage, ResourceInfo& Info) const;
9485
95 using DescriptorSetBindInfo = PipelineResourceSignatureVkImpl::DescriptorSetBindInfo;
96
97 // Computes dynamic offsets and binds descriptor sets
98 __forceinline void BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
99 Uint32 CtxId,
100 DeviceContextVkImpl* pCtxVkImpl,
101 DescriptorSetBindInfo& BindInfo) const;
102
10386 private:
10487 VulkanUtilities::PipelineLayoutWrapper m_VkPipelineLayout;
10588
106 RenderDeviceVkImpl* m_pDeviceVk;
89 Uint32 m_DynamicOffsetCount : 25;
10790
108 // AZ TODO: pack bits
109 Uint16 m_DynamicOffsetCount = 0;
110 Uint8 m_SignatureCount = 0;
111 Uint8 m_DescrSetCount = 0;
91 Uint32 m_SignatureCount : 3;
92 static_assert(MAX_RESOURCE_SIGNATURES == (1 << 3), "update m_SignatureCount bits count");
11293
113 PIPELINE_TYPE m_PipelineType = PIPELINE_TYPE(0xFF);
94 Uint32 m_DescrSetCount : 4;
95 static_assert(MAX_RESOURCE_SIGNATURES * 2 == (1 << 4), "update m_DescrSetCount bits count");
11496
11597 using SignatureArray = std::array<RefCntAutoPtr<PipelineResourceSignatureVkImpl>, MAX_RESOURCE_SIGNATURES>;
11698 using DescSetOffsetArray = std::array<Uint8, MAX_RESOURCE_SIGNATURES>;
121103 DynBufOffsetArray m_DynBufOffset = {};
122104 };
123105
124
125 __forceinline void PipelineLayoutVk::BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
126 Uint32 CtxId,
127 DeviceContextVkImpl* pCtxVkImpl,
128 DescriptorSetBindInfo& BindInfo) const
129 {
130 /*
131 VERIFY(BindInfo.pDbgPipelineLayout != nullptr, "Pipeline layout is not initialized, which most likely means that CommitShaderResources() has never been called");
132 VERIFY(BindInfo.pDbgPipelineLayout->IsSameAs(*this), "Inconsistent pipeline layout");
133 VERIFY(BindInfo.DynamicOffsetCount > 0, "This function should only be called for pipelines that contain dynamic descriptors");
134 VERIFY_EXPR(BindInfo.pResourceCache != nullptr);
135
136 #ifdef DILIGENT_DEBUG
137 Uint32 TotalDynamicDescriptors = 0;
138 for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
139 VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC;
140 VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
141 {
142 const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType);
143 TotalDynamicDescriptors += Set.NumDynamicDescriptors;
144 }
145 VERIFY(BindInfo.DynamicOffsetCount == TotalDynamicDescriptors, "Incosistent dynamic buffer size");
146 VERIFY_EXPR(BindInfo.DynamicOffsets.size() >= BindInfo.DynamicOffsetCount);
147 #endif
148
149 auto NumOffsetsWritten = BindInfo.pResourceCache->GetDynamicBufferOffsets(CtxId, pCtxVkImpl, BindInfo.DynamicOffsets);
150 VERIFY_EXPR(NumOffsetsWritten == BindInfo.DynamicOffsetCount);
151 (void)NumOffsetsWritten;
152
153 // Note that there is one global dynamic buffer from which all dynamic resources are suballocated in Vulkan back-end,
154 // and this buffer is not resizable, so the buffer handle can never change.
155
156 // vkCmdBindDescriptorSets causes the sets numbered [firstSet .. firstSet+descriptorSetCount-1] to use the
157 // bindings stored in pDescriptorSets[0 .. descriptorSetCount-1] for subsequent rendering commands
158 // (either compute or graphics, according to the pipelineBindPoint). Any bindings that were previously
159 // applied via these sets are no longer valid (13.2.5)
160 CmdBuffer.BindDescriptorSets(BindInfo.BindPoint,
161 m_LayoutMgr.GetVkPipelineLayout(),
162 0, // First set
163 BindInfo.SetCout,
164 BindInfo.vkSets.data(), // BindInfo.vkSets is never empty
165 // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound (13.2.5)
166 BindInfo.DynamicOffsetCount,
167 BindInfo.DynamicOffsets.data());
168
169 BindInfo.DynamicDescriptorsBound = true;
170 */
171 }
172
173106 } // namespace Diligent
2929 /// \file
3030 /// Declaration of Diligent::PipelineResourceSignatureVkImpl class
3131 #include <array>
32 #include <bitset>
3233
3334 #include "PipelineResourceSignatureBase.hpp"
3435 #include "VulkanUtilities/VulkanObjectWrappers.hpp"
4344 class ShaderVariableManagerVk;
4445 class DeviceContextVkImpl;
4546
47 enum class DescriptorType : Uint8
48 {
49 Sampler,
50 CombinedImageSampler,
51 SeparateImage,
52 StorageImage,
53 StorageImage_ReadOnly,
54 UniformTexelBuffer,
55 StorageTexelBuffer,
56 StorageTexelBuffer_ReadOnly,
57 UniformBuffer,
58 StorageBuffer,
59 StorageBuffer_ReadOnly,
60 UniformBufferDynamic,
61 StorageBufferDynamic,
62 StorageBufferDynamic_ReadOnly,
63 InputAttachment,
64 AccelerationStructure,
65 Count,
66 Unknown = 0xFF,
67 };
68
69 RESOURCE_STATE DescriptorTypeToResourceState(DescriptorType Type);
70
71
4672 /// Implementation of the Diligent::PipelineResourceSignatureVkImpl class
4773 class PipelineResourceSignatureVkImpl final : public PipelineResourceSignatureBase<IPipelineResourceSignature, RenderDeviceVkImpl>
4874 {
5581 bool bIsDeviceInternal = false);
5682 ~PipelineResourceSignatureVkImpl();
5783
58 Uint32 GetDynamicBufferCount() const { return m_DynamicBufferCount; }
59 Uint8 GetNumShaderStages() const { return m_NumShaders; }
60 Uint32 GetTotalResourceCount() const { return m_Desc.NumResources; }
61
62 static constexpr Uint8 InvalidSamplerInd = 0xFF;
63
64 struct PackedBindingIndex
65 {
66 Uint16 Binding;
67 Uint8 DescSet : 1; // 0 - static, 1 - dynamic
68 Uint8 SamplerInd = InvalidSamplerInd;
84 Uint32 GetDynamicBufferCount() const { return m_DynamicBufferCount; }
85 Uint8 GetNumShaderStages() const { return m_NumShaders; }
86 SHADER_TYPE GetShaderStageType(Uint32 StageIndex) const;
87 Uint32 GetTotalResourceCount() const { return m_Desc.NumResources; }
88 Uint32 GetNumDescriptorSets() const;
89
90 static constexpr Uint32 InvalidSamplerInd = ~0u;
91
92 struct ResourceAttribs
93 {
94 DescriptorType Type;
95 Uint32 CacheOffset; // for ShaderResourceCacheVk
96 Uint16 BindingIndex;
97 Uint8 DescrSet : 1;
98 Uint8 ImmutableSamplerAssigned : 1;
99 Uint32 SamplerInd;
100
101 ResourceAttribs() :
102 CacheOffset{~0u}, BindingIndex{0xFFFF}, DescrSet{0}, SamplerInd{InvalidSamplerInd}, ImmutableSamplerAssigned{0}
103 {}
69104 };
70105
71 const PackedBindingIndex& GetBinding(Uint32 ResIndex) const
106 const ResourceAttribs& GetAttribs(Uint32 ResIndex) const
72107 {
73108 VERIFY_EXPR(ResIndex < m_Desc.NumResources);
74 return m_pBindingIndices[ResIndex];
109 return m_pResourceAttribs[ResIndex];
75110 }
76111
77112 const PipelineResourceDesc& GetResource(Uint32 ResIndex) const
83118 VkDescriptorSetLayout GetStaticVkDescriptorSetLayout() const { return m_VkDescSetLayouts[0]; }
84119 VkDescriptorSetLayout GetDynamicVkDescriptorSetLayout() const { return m_VkDescSetLayouts[1]; }
85120
121 bool HasStaticDescrSet() const { return GetStaticVkDescriptorSetLayout() != VK_NULL_HANDLE; }
122 bool HasDynamicDescrSet() const { return GetDynamicVkDescriptorSetLayout() != VK_NULL_HANDLE; }
123
86124 virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding,
87125 bool InitStaticResources) override final;
88126
92130
93131 virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final;
94132
95 using VkDescSetArray = std::array<VkDescriptorSet, MAX_RESOURCE_SIGNATURES * 2>;
96
97 struct DescriptorSetBindInfo
98 {
99 VkDescSetArray vkSets;
100 std::vector<uint32_t> DynamicOffsets;
101 const ShaderResourceCacheVk* pResourceCache = nullptr;
102 Uint32 SetCout = 0;
103 Uint32 DynamicOffsetCount = 0;
104 bool DynamicBuffersPresent = false;
105 bool DynamicDescriptorsBound = false;
106 #ifdef DILIGENT_DEBUG
107 //const PipelineLayoutVk* pDbgPipelineLayout = nullptr;
108 #endif
109 DescriptorSetBindInfo() :
110 DynamicOffsets(64)
111 {
112 }
113
114 void Reset()
115 {
116 pResourceCache = nullptr;
117 SetCout = 0;
118 DynamicOffsetCount = 0;
119 DynamicBuffersPresent = false;
120 DynamicDescriptorsBound = false;
121
122 #ifdef DILIGENT_DEBUG
123 // In release mode, do not clear vectors as this causes unnecessary work
124 DynamicOffsets.clear();
125
126 //pDbgPipelineLayout = nullptr;
127 #endif
128 }
129 };
130
131 void PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
132 VkPipelineBindPoint BindPoint,
133 const ShaderResourceCacheVk& ResourceCache,
134 DescriptorSetBindInfo& BindInfo,
135 VkDescriptorSet VkDynamicDescrSet) const;
136
137 static VkDescriptorType GetVkDescriptorType(const PipelineResourceDesc& Res);
138
139 SHADER_TYPE GetShaderStageType(Uint32 StageIndex) const;
133 virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags,
134 IResourceMapping* pResourceMapping,
135 Uint32 Flags) override final;
136
137 virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineResourceSignature* pPRS) const override final
138 {
139 return IsCompatibleWith(*ValidatedCast<const PipelineResourceSignatureVkImpl>(pPRS));
140 }
140141
141142 SRBMemoryAllocator& GetSRBMemoryAllocator()
142143 {
152153
153154 void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const;
154155
156 static String GetPrintName(const PipelineResourceDesc& ResDesc, Uint32 ArrayInd);
157
158 void BindResource(IDeviceObject* pObj,
159 Uint32 ArrayIndex,
160 Uint32 ResIndex,
161 ShaderResourceCacheVk& ResourceCache) const;
162
163 void CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache,
164 VkDescriptorSet vkDynamicDescriptorSet) const;
165
166 bool IsCompatibleWith(const PipelineResourceSignatureVkImpl& Other) const;
167
168 bool IsIncompatibleWith(const PipelineResourceSignatureVkImpl& Other) const
169 {
170 return GetHash() != Other.GetHash();
171 }
172
155173 private:
156174 void Destruct();
157175
176 void ReserveSpaceForStaticVarsMgrs(const PipelineResourceSignatureDesc& Desc,
177 FixedLinearAllocator& MemPool,
178 Int8& StaticVarStageCount,
179 Uint32& StaticVarCount,
180 Uint8 DSMapping[2]);
181
182 void CreateLayout(Uint32 StaticVarCount, const Uint8 DSMapping[2]);
183
184 Uint32 FindAssignedSampler(const PipelineResourceDesc& SepImg) const;
185
186 // returns descriptor set index in resource cache
187 Uint32 GetStaticDescrSetIndex() const;
188 Uint32 GetDynamicDescrSetIndex() const;
189
190 using ImmutableSamplerPtrType = RefCntAutoPtr<ISampler>;
191
192 private:
158193 VulkanUtilities::DescriptorSetLayoutWrapper m_VkDescSetLayouts[2];
159194
160 PackedBindingIndex* m_pBindingIndices = nullptr; // [m_Desc.NumResources]
195 ResourceAttribs* m_pResourceAttribs = nullptr; // [m_Desc.NumResources]
161196
162197 SHADER_TYPE m_ShaderStages = SHADER_TYPE_UNKNOWN;
163198
164 Uint16 m_DynamicBufferCount = 0;
165 Uint8 m_NumShaders = 0;
199 Uint32 m_DynamicBufferCount : 29; // buffers with dynamic offsets
200 Uint32 m_NumShaders : 3;
166201
167202 std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_StaticVarIndex = {-1, -1, -1, -1, -1, -1};
168203 static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above");
169204
170205 ShaderResourceCacheVk* m_pResourceCache = nullptr;
171 ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; // [0..MAX_SHADERS_IN_PIPELINE]
172
173 SRBMemoryAllocator m_SRBMemAllocator;
206 ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; // [m_NumShaders]
207
208 ImmutableSamplerPtrType* m_ImmutableSamplers = nullptr; // [m_Desc.NumImmutableSamplers]
209 SRBMemoryAllocator m_SRBMemAllocator;
174210 };
175211
176212
7171 /// Implementation of IPipelineStateVk::GetVkPipeline().
7272 virtual VkPipeline DILIGENT_CALL_TYPE GetVkPipeline() const override final { return m_Pipeline; }
7373
74 /// Implementation of IPipelineState::BindStaticResources() in Vulkan backend.
75 virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) override final;
76
7774 /// Implementation of IPipelineState::GetResourceSignatureCount() in Vulkan backend.
78 virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_PipelineLayout->GetSignatureCount(); }
75 virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_PipelineLayout.GetSignatureCount(); }
7976
8077 /// Implementation of IPipelineState::GetResourceSignature() in Vulkan backend.
81 virtual IPipelineResourceSignature* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final { return m_PipelineLayout->GetSignature(Index); }
78 virtual IPipelineResourceSignature* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final { return m_PipelineLayout.GetSignature(Index); }
8279
83 __forceinline void BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
84 Uint32 CtxId,
85 DeviceContextVkImpl* pCtxVkImpl,
86 PipelineLayoutVk::DescriptorSetBindInfo& BindInfo)
87 {
88 m_PipelineLayout->BindDescriptorSetsWithDynamicOffsets(CmdBuffer, CtxId, pCtxVkImpl, BindInfo);
89 }
90
91 const PipelineLayoutVk& GetPipelineLayout() const { return *m_PipelineLayout; }
80 const PipelineLayoutVk& GetPipelineLayout() const { return m_PipelineLayout; }
9281
9382 static RenderPassDesc GetImplicitRenderPassDesc(Uint32 NumRenderTargets,
9483 const TEXTURE_FORMAT RTVFormats[],
10089
10190
10291 void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const;
103
104 bool IsIncompatibleWith(IPipelineResourceSignature* pPRS) const
105 {
106 return !m_PipelineLayout->HasSignature(pPRS);
107 }
10892
10993 struct ShaderStageInfo
11094 {
136120
137121 void Destruct();
138122
139 void* m_pRawMem = nullptr; // AZ TODO: remove
123 void* m_pRawMem = nullptr; // AZ TODO: move to base class
140124
141125 VulkanUtilities::PipelineWrapper m_Pipeline;
142 RefCntAutoPtr<PipelineLayoutVk> m_PipelineLayout;
143
144 bool m_HasStaticResources = false;
145 bool m_HasNonStaticResources = false;
126 PipelineLayoutVk m_PipelineLayout;
146127 };
147128
148129 } // namespace Diligent
4646 #include "VulkanUploadHeap.hpp"
4747 #include "FramebufferCache.hpp"
4848 #include "RenderPassCache.hpp"
49 #include "PipelineLayoutCacheVk.hpp"
5049 #include "CommandPoolManager.hpp"
5150 #include "DXCompiler.hpp"
5251
134133 virtual void DILIGENT_CALL_TYPE CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc,
135134 IPipelineResourceSignature** ppSignature) override final;
136135
136 void CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc,
137 IPipelineResourceSignature** ppSignature,
138 bool IsDeviceInternal);
139
137140 /// Implementation of IRenderDeviceVk::GetVkDevice().
138141 virtual VkDevice DILIGENT_CALL_TYPE GetVkDevice() override final { return m_LogicalVkDevice->GetVkDevice(); }
139142
193196
194197 FramebufferCache& GetFramebufferCache() { return m_FramebufferCache; }
195198 RenderPassCache& GetImplicitRenderPassCache() { return m_ImplicitRenderPassCache; }
196
197 PipelineLayoutCacheVk& GetPipelineLayoutCache() { return m_PipelineLayoutCache; }
198199
199200 VulkanUtilities::VulkanMemoryAllocation AllocateMemory(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProperties, VkMemoryAllocateFlags AllocateFlags = 0)
200201 {
230231 return m_Properties;
231232 }
232233
233 void CreatePipelineLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount, PipelineLayoutVk** ppPipelineLayout);
234 IPipelineResourceSignature* GetEmptySignature() const { return m_pEmptySignature.RawPtr<IPipelineResourceSignature>(); }
234235
235236 private:
236237 template <typename PSOCreateInfoType>
252253 EngineVkCreateInfo m_EngineAttribs;
253254
254255 FramebufferCache m_FramebufferCache;
255 PipelineLayoutCacheVk m_PipelineLayoutCache;
256256 RenderPassCache m_ImplicitRenderPassCache;
257257 DescriptorSetAllocator m_DescriptorSetAllocator;
258258 DescriptorPoolManager m_DynamicDescriptorPool;
270270
271271 Properties m_Properties;
272272
273 FixedBlockMemoryAllocator m_PipelineLayoutAllocator;
273 RefCntAutoPtr<IPipelineResourceSignature> m_pEmptySignature;
274274 };
275275
276276 } // namespace Diligent
5656 #include "DescriptorPoolManager.hpp"
5757 #include "SPIRVShaderResources.hpp"
5858 #include "BufferVkImpl.hpp"
59 #include "PipelineResourceSignatureVkImpl.hpp"
5960
6061 namespace Diligent
6162 {
9293 static size_t GetRequiredMemorySize(Uint32 NumSets, const Uint32* SetSizes);
9394
9495 void InitializeSets(IMemoryAllocator& MemAllocator, Uint32 NumSets, const Uint32* SetSizes);
95 void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, VkDescriptorType Type);
96 void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type);
9697
9798 // sizeof(Resource) == 16 (x64, msvc, Release)
9899 struct Resource
99100 {
100101 // clang-format off
101 explicit Resource(VkDescriptorType _Type) noexcept :
102 explicit Resource(DescriptorType _Type) noexcept :
102103 Type{_Type}
103104 {}
104105
107108 Resource& operator = (const Resource&) = delete;
108109 Resource& operator = (Resource&&) = delete;
109110
110 /* 0 */ const VkDescriptorType Type;
111 /*4-7*/ // Unused
111 /* 0 */ const DescriptorType Type;
112 /*1-7*/ // Unused
112113 /* 8 */ RefCntAutoPtr<IDeviceObject> pObject;
113114
114115 VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo () const;
243244 for (Uint32 set = 0; set < m_NumSets; ++set)
244245 {
245246 const auto& DescrSet = GetDescriptorSet(set);
246 Uint32 res = 0;
247247
248248 // AZ TODO: optimize
249 while (res < DescrSet.GetSize())
249 for (Uint32 res = 0; res < DescrSet.GetSize(); ++res)
250250 {
251251 const auto& Res = DescrSet.GetResource(res);
252252
253 if (Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)
253 if (Res.Type == DescriptorType::UniformBufferDynamic)
254254 {
255255 const auto* pBufferVk = Res.pObject.RawPtr<const BufferVkImpl>();
256256 auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
257257 Offsets[OffsetInd++] = Offset;
258258 }
259 if (Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
259 if (Res.Type == DescriptorType::StorageBufferDynamic || Res.Type == DescriptorType::StorageBufferDynamic_ReadOnly)
260260 {
261261 const auto* pBufferVkView = Res.pObject.RawPtr<const BufferViewVkImpl>();
262262 const auto* pBufferVk = pBufferVkView != nullptr ? pBufferVkView->GetBufferVk() : 0;
263263 auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
264264 Offsets[OffsetInd++] = Offset;
265265 }
266 ++res;
267266 }
268267 }
269268 return OffsetInd;
8282 void Initialize(const PipelineResourceSignatureVkImpl& SrcLayout,
8383 IMemoryAllocator& Allocator,
8484 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
85 Uint32 NumAllowedTypes);
85 Uint32 NumAllowedTypes,
86 SHADER_TYPE ShaderType);
8687
8788 ~ShaderVariableManagerVk();
8889
9697 static size_t GetRequiredMemorySize(const PipelineResourceSignatureVkImpl& Layout,
9798 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
9899 Uint32 NumAllowedTypes,
100 SHADER_TYPE ShaderStages,
99101 Uint32& NumVariables);
100102
101103 Uint32 GetVariableCount() const { return m_NumVariables; }
102104
103105 private:
104106 friend ShaderVariableVkImpl;
105 using PackedBindingIndex = PipelineResourceSignatureVkImpl::PackedBindingIndex;
107 using ResourceAttribs = PipelineResourceSignatureVkImpl::ResourceAttribs;
106108
107109 Uint32 GetVariableIndex(const ShaderVariableVkImpl& Variable);
108110
111113 VERIFY_EXPR(m_pSignature);
112114 return m_pSignature->GetResource(Index);
113115 }
114 const PackedBindingIndex& GetBinding(Uint32 Index) const
116 const ResourceAttribs& GetAttribs(Uint32 Index) const
115117 {
116118 VERIFY_EXPR(m_pSignature);
117 return m_pSignature->GetBinding(Index);
119 return m_pSignature->GetAttribs(Index);
118120 }
119121
120122 private:
143145 class ShaderVariableVkImpl final : public IShaderResourceVariable
144146 {
145147 public:
146 explicit ShaderVariableVkImpl(ShaderVariableManagerVk& ParentManager) :
147 m_ParentManager{ParentManager}
148 ShaderVariableVkImpl(ShaderVariableManagerVk& ParentManager,
149 Uint32 ResIndex) :
150 m_ParentManager{ParentManager},
151 m_ResIndex{ResIndex}
148152 {}
149153
150154 // clang-format off
204208
205209 virtual Uint32 DILIGENT_CALL_TYPE GetIndex() const override final
206210 {
207 VERIFY_EXPR(m_ParentManager.m_pVariables);
208 return Uint32(size_t(this - m_ParentManager.m_pVariables));
211 return m_ParentManager.GetVariableIndex(*this);
209212 }
210213
211214 virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final;
212215
213 String GetPrintName(Uint32 ArrayInd) const;
214
215 RESOURCE_DIMENSION GetResourceDimension() const;
216
217 bool IsMultisample() const;
218
219216 private:
220217 friend ShaderVariableManagerVk;
221 using PackedBindingIndex = PipelineResourceSignatureVkImpl::PackedBindingIndex;
222
223 const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResource(GetIndex()); }
224 const PackedBindingIndex& GetBinding() const { return m_ParentManager.GetBinding(GetIndex()); }
218 using ResourceAttribs = PipelineResourceSignatureVkImpl::ResourceAttribs;
219
220 const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResource(m_ResIndex); }
221 const ResourceAttribs& GetAttribs() const { return m_ParentManager.GetAttribs(m_ResIndex); }
225222
226223 void BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const;
227224
228 struct UpdateInfo
229 {
230 ShaderResourceCacheVk::Resource& DstRes;
231 const VkDescriptorSet vkDescrSet;
232 const Uint32 ArrayIndex;
233 const SHADER_RESOURCE_VARIABLE_TYPE VarType;
234 const Uint16 Binding;
235 const Uint8 SamplerInd;
236 char const* const Name;
237 };
238
239 void CacheUniformBuffer(IDeviceObject* pBuffer,
240 UpdateInfo& Info,
241 Uint16& DynamicBuffersCounter) const;
242
243 void CacheStorageBuffer(IDeviceObject* pBufferView,
244 UpdateInfo& Info,
245 Uint16& DynamicBuffersCounter) const;
246
247 void CacheTexelBuffer(IDeviceObject* pBufferView,
248 UpdateInfo& Info,
249 Uint16& DynamicBuffersCounter) const;
250
251 template <typename TCacheSampler>
252 void CacheImage(IDeviceObject* pTexView,
253 UpdateInfo& Info,
254 TCacheSampler CacheSampler) const;
255
256 void CacheSeparateSampler(IDeviceObject* pSampler,
257 UpdateInfo& Info) const;
258
259 void CacheInputAttachment(IDeviceObject* pTexView,
260 UpdateInfo& Info) const;
261
262 void CacheAccelerationStructure(IDeviceObject* pTLAS,
263 UpdateInfo& Info) const;
264
265 template <typename ObjectType, typename TPreUpdateObject>
266 bool UpdateCachedResource(UpdateInfo& Info,
267 RefCntAutoPtr<ObjectType>&& pObject,
268 TPreUpdateObject PreUpdateObject) const;
269
270 bool IsImmutableSamplerAssigned() const;
271
272 // Updates resource descriptor in the descriptor set
273 inline void UpdateDescriptorHandle(UpdateInfo& Info,
274 const VkDescriptorImageInfo* pImageInfo,
275 const VkDescriptorBufferInfo* pBufferInfo,
276 const VkBufferView* pTexelBufferView,
277 const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const;
278
279 static constexpr Uint8 InvalidSamplerInd = PipelineResourceSignatureVkImpl::InvalidSamplerInd;
280
281225 private:
282226 ShaderVariableManagerVk& m_ParentManager;
227 const Uint32 m_ResIndex;
283228 };
284229
285230 } // namespace Diligent
117117
118118 m_vkClearValues.reserve(16);
119119
120 m_DynamicBufferOffsets.reserve(64);
121
120122 CreateASCompactedSizeQueryPool();
121123 }
122124
230232 void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState)
231233 {
232234 auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(pPipelineState);
233 BindShaderResources(pPipelineStateVk);
234
235235 if (PipelineStateVkImpl::IsSameObject(m_pPipelineState, pPipelineStateVk))
236236 return;
237237
307307 default:
308308 UNEXPECTED("unknown pipeline type");
309309 }
310
311 BindShaderResources(pPipelineStateVk);
310312 }
311313
312314 static Uint32 PipelineTypeToBindPointIndex(PIPELINE_TYPE Type)
337339 {
338340 VERIFY_EXPR(pPipelineStateVk != nullptr);
339341
342 const auto& Layout = pPipelineStateVk->GetPipelineLayout();
343 const auto BindIndex = PipelineTypeToBindPointIndex(pPipelineStateVk->GetDesc().PipelineType);
344 auto& BindInfo = m_DescrSetBindInfo[BindIndex];
345 auto& Resources = BindInfo.Resources;
346 const auto BindPoint = PipelineTypeToBindPoint(pPipelineStateVk->GetDesc().PipelineType);
347 const auto SignCount = Layout.GetSignatureCount();
348 Uint32 CompatSignCount = SignCount;
349
350 // Layout compatibility means that descriptor sets can be bound to a command buffer
351 // for use by any pipeline created with a compatible pipeline layout, and without having bound
352 // a particular pipeline first. It also means that descriptor sets can remain valid across
353 // a pipeline change, and the same resources will be accessible to the newly bound pipeline.
354 // (14.2.2. Pipeline Layouts, clause 'Pipeline Layout Compatibility')
355 // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#descriptorsets-compatibility
356
357 // unbind incompatible descriptor sets
358 for (Uint32 i = 0; i < SignCount; ++i)
359 {
360 auto* LayoutSign = Layout.GetSignature(i);
361 VERIFY_EXPR(LayoutSign != nullptr);
362
363 if (Resources[i] != nullptr && LayoutSign->IsIncompatibleWith(*Resources[i]->GetSignature()))
364 {
365 Resources[i] = nullptr;
366 CompatSignCount = std::min(CompatSignCount, i + 1);
367 }
368 }
369
370 // reset unused states
371 for (Uint32 i = CompatSignCount; i < MAX_RESOURCE_SIGNATURES; ++i)
372 {
373 Resources[i] = nullptr;
374
375 BindInfo.PendingVkSet[i] = false; // AZ TODO: can be optimized
376 BindInfo.PendingDynamicDescriptors[i] = false;
377 BindInfo.DynamicBuffersPresent[i] = false;
378
379 #ifdef DILIGENT_DEBUG
380 BindInfo.vkSets[i * MAX_DESCR_SET_PER_SIGNATURE + 0] = VK_NULL_HANDLE;
381 BindInfo.vkSets[i * MAX_DESCR_SET_PER_SIGNATURE + 1] = VK_NULL_HANDLE;
382 #endif
383 }
384 }
385
386 void DeviceContextVkImpl::BindDescriptorSetsWithDynamicOffsets(DescriptorSetBindInfo& BindInfo)
387 {
388 auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(m_pPipelineState.RawPtr());
340389 const auto& Layout = pPipelineStateVk->GetPipelineLayout();
341 auto& Resources = m_ShaderResources[PipelineTypeToBindPointIndex(Layout.GetPipelineType())];
342 auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(Layout.GetPipelineType())];
343
344 #ifdef DILIGENT_DEVELOPMENT
345 for (Uint32 i = 0, Count = Layout.GetSignatureCount(); i < Count; ++i)
390 const auto BindIndex = PipelineTypeToBindPointIndex(pPipelineStateVk->GetDesc().PipelineType);
391 auto& Resources = BindInfo.Resources;
392 const auto BindPoint = PipelineTypeToBindPoint(pPipelineStateVk->GetDesc().PipelineType);
393 const auto SignCount = Layout.GetSignatureCount();
394 auto& Offsets = m_DynamicBufferOffsets;
395 const auto VkLayout = Layout.GetVkPipelineLayout();
396
397 for (Uint32 i = 0; i < SignCount; ++i)
398 {
399 VERIFY_EXPR(Resources[i] != nullptr);
400
401 if ((BindInfo.PendingVkSet[i] || BindInfo.PendingDynamicDescriptors[i]) && Resources[i] != nullptr)
402 {
403 const auto* pSignature = Resources[i]->GetSignature();
404 const Uint32 DescrSetIdx = Layout.GetDescrSetIndex(pSignature);
405 const auto& ResourceCache = Resources[i]->GetResourceCache();
406 const Uint32 DSCount = ResourceCache.GetNumDescriptorSets();
407 const auto DSOffset = i * MAX_DESCR_SET_PER_SIGNATURE;
408
409 #ifdef DILIGENT_DEBUG
410 for (Uint32 s = 0; s < DSCount; ++s)
411 VERIFY_EXPR(BindInfo.vkSets[DSOffset + s] != VK_NULL_HANDLE);
412 #endif
413 if (pSignature->GetDynamicBufferCount() > 0)
414 {
415 Offsets.resize(pSignature->GetDynamicBufferCount());
416
417 auto NumOffsetsWritten = ResourceCache.GetDynamicBufferOffsets(m_ContextId, this, Offsets);
418 VERIFY_EXPR(NumOffsetsWritten == pSignature->GetDynamicBufferCount());
419
420 // Note that there is one global dynamic buffer from which all dynamic resources are suballocated in Vulkan back-end,
421 // and this buffer is not resizable, so the buffer handle can never change.
422
423 // vkCmdBindDescriptorSets causes the sets numbered [firstSet .. firstSet+descriptorSetCount-1] to use the
424 // bindings stored in pDescriptorSets[0 .. descriptorSetCount-1] for subsequent rendering commands
425 // (either compute or graphics, according to the pipelineBindPoint). Any bindings that were previously
426 // applied via these sets are no longer valid (13.2.5)
427 m_CommandBuffer.BindDescriptorSets(BindPoint, VkLayout, DescrSetIdx, DSCount, &BindInfo.vkSets[DSOffset], static_cast<Uint32>(Offsets.size()), Offsets.data());
428 BindInfo.PendingDynamicDescriptors[i] = false;
429 }
430 else
431 {
432 VERIFY_EXPR(!BindInfo.PendingDynamicDescriptors[i]);
433 m_CommandBuffer.BindDescriptorSets(BindPoint, VkLayout, DescrSetIdx, DSCount, &BindInfo.vkSets[DSOffset], 0, nullptr);
434 }
435
436 BindInfo.PendingVkSet[i] = false;
437 }
438 }
439
440 VERIFY_EXPR(!BindInfo.PendingVkSet.any());
441 VERIFY_EXPR(!BindInfo.PendingDynamicDescriptors.any());
442 }
443
444 void DeviceContextVkImpl::ValidateShaderResources()
445 {
446 #ifdef DILIGENT_DEBUG
447 auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(m_pPipelineState.RawPtr());
448 const auto& Layout = pPipelineStateVk->GetPipelineLayout();
449 const auto BindIndex = PipelineTypeToBindPointIndex(pPipelineStateVk->GetDesc().PipelineType);
450 auto& BindInfo = m_DescrSetBindInfo[BindIndex];
451 const auto SignCount = Layout.GetSignatureCount();
452
453 for (Uint32 i = 0; i < SignCount; ++i)
346454 {
347455 auto* LayoutSign = Layout.GetSignature(i);
348 auto* ResSign = Resources[i] ? Resources[i]->GetPipelineResourceSignature() : nullptr;
349
350 if (LayoutSign != ResSign)
351 {
352 LOG_ERROR_MESSAGE("Shader resource binding '", (ResSign ? ResSign->GetDesc().Name : ""),
456 if (LayoutSign == nullptr)
457 {
458 LOG_ERROR_MESSAGE("Pipeline resource signature for index (", i, ") is null, this may indicate a bug");
459 return;
460 }
461
462 if (BindInfo.Resources[i] == nullptr)
463 {
464 LOG_ERROR_MESSAGE("Shader resource binding is not bound to index (", i, ").");
465 return;
466 }
467
468 auto* ResSign = BindInfo.Resources[i]->GetSignature();
469 VERIFY_EXPR(ResSign != nullptr);
470
471 if (!LayoutSign->IsCompatibleWith(*ResSign))
472 {
473 LOG_ERROR_MESSAGE("Shader resource binding with signature '", ResSign->GetDesc().Name,
353474 "' is not compatible with pipeline layout in current pipeline '", pPipelineStateVk->GetDesc().Name, "'.");
354 Resources[i] = nullptr;
475 }
476
477 // You must call BindDescriptorSetsWithDynamicOffsets() before validation.
478 VERIFY_EXPR(!BindInfo.PendingVkSet[i]);
479 VERIFY_EXPR(!BindInfo.PendingDynamicDescriptors[i]);
480
481 const auto DSCount = LayoutSign->GetNumDescriptorSets();
482 const auto DSOffset = i * MAX_DESCR_SET_PER_SIGNATURE;
483
484 for (Uint32 s = 0; s < DSCount; ++s)
485 {
486 VERIFY(BindInfo.vkSets[DSOffset + s] != VK_NULL_HANDLE,
487 "descriptor set with index (", s, ") is not bound for resource signature '",
488 LayoutSign->GetDesc().Name, "' binding index (", i, ").");
355489 }
356490 }
357491 #endif
358
359 // the number of bound descriptor sets and dynamic offsets may be greater then actually used in pipeline layout,
360 // see https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#descriptorsets-compatibility
361 VERIFY_EXPR(Layout.GetDescriptorSetCount() <= DescrSetBindInfo.SetCout);
362 VERIFY_EXPR(Layout.GetDynamicOffsetCount() <= DescrSetBindInfo.DynamicOffsetCount);
363
364 // AZ TODO: optimize - bind DS that was changed
365 GetCommandBuffer().BindDescriptorSets(PipelineTypeToBindPoint(Layout.GetPipelineType()), Layout.GetVkPipelineLayout(), 0, Layout.GetDescriptorSetCount(), DescrSetBindInfo.vkSets.data(), Layout.GetDynamicOffsetCount(), DescrSetBindInfo.DynamicOffsets.data());
366492 }
367493
368494 void DeviceContextVkImpl::TransitionShaderResources(IPipelineState*, IShaderResourceBinding* pShaderResourceBinding)
376502
377503 if (pShaderResourceBinding == nullptr)
378504 {
379 LOG_ERROR_MESSAGE("TODO");
505 LOG_ERROR_MESSAGE("AZ TODO");
380506 return;
381507 }
382508 #endif
410536 }
411537 #endif
412538
413 Uint32 Index = PipelineTypeToBindPointIndex(pResBindingVkImpl->GetPipelineType());
414 auto& DescrSetBindInfo = m_DescrSetBindInfo[Index];
415 auto& ResourceBinding = m_ShaderResources[Index];
416
417 // AZ TODO: create dynamic descriptor set
418 (void)(DescrSetBindInfo);
419
420 ResourceBinding[pResBindingVkImpl->GetBindingIndex()] = pResBindingVkImpl;
539 const auto BindIndex = PipelineTypeToBindPointIndex(pResBindingVkImpl->GetPipelineType());
540 const auto Index = pResBindingVkImpl->GetBindingIndex();
541 auto& BindInfo = m_DescrSetBindInfo[BindIndex];
542 const auto* pSignature = pResBindingVkImpl->GetSignature();
543 const auto DSOffset = Index * MAX_DESCR_SET_PER_SIGNATURE;
544 const auto DSCount = ResourceCache.GetNumDescriptorSets();
545 Uint32 DSIndex = 0;
546
547 BindInfo.PendingVkSet[Index] = true;
548 BindInfo.PendingDynamicDescriptors[Index] = false;
549 BindInfo.DynamicBuffersPresent[Index] = ResourceCache.GetNumDynamicBuffers() > 0;
550
551 if (pSignature->HasStaticDescrSet())
552 {
553 VERIFY_EXPR(DSIndex < DSCount);
554 BindInfo.vkSets[DSOffset + DSIndex] = ResourceCache.GetDescriptorSet(DSIndex).GetVkDescriptorSet();
555 ++DSIndex;
556 }
557
558 if (auto VkLayout = pSignature->GetDynamicVkDescriptorSetLayout())
559 {
560 VERIFY_EXPR(DSIndex < DSCount);
561 VERIFY_EXPR(ResourceCache.GetDescriptorSet(DSIndex).GetVkDescriptorSet() == VK_NULL_HANDLE);
562
563 VkDescriptorSet DynamicDescrSet = VK_NULL_HANDLE;
564 const char* DynamicDescrSetName = "Dynamic Descriptor Set";
565 #ifdef DILIGENT_DEVELOPMENT
566 String _DynamicDescrSetName("AZ TODO");
567 _DynamicDescrSetName.append(" - dynamic set");
568 DynamicDescrSetName = _DynamicDescrSetName.c_str();
569 #endif
570 // Allocate vulkan descriptor set for dynamic resources
571 DynamicDescrSet = AllocateDynamicDescriptorSet(VkLayout, DynamicDescrSetName);
572
573 // Commit all dynamic resource descriptors
574 pSignature->CommitDynamicResources(ResourceCache, DynamicDescrSet);
575
576 BindInfo.vkSets[DSOffset + DSIndex] = DynamicDescrSet;
577 ++DSIndex;
578 }
579
580 if (pSignature->GetDynamicBufferCount() > 0)
581 BindInfo.PendingDynamicDescriptors[Index] = true;
582
583 VERIFY_EXPR(DSIndex == DSCount);
584
585 BindInfo.Resources[Index] = pResBindingVkImpl;
421586 }
422587
423588 void DeviceContextVkImpl::SetStencilRef(Uint32 StencilRef)
557722 }
558723 #endif
559724
560 auto& DescrSetBindInfo = m_DescrSetBindInfo[0];
561
562 if (DescrSetBindInfo.DynamicOffsetCount != 0)
563 {
564 // First time we must always bind descriptor sets with dynamic offsets.
565 // If there are no dynamic buffers bound in the resource cache, for all subsequent
566 // cals we do not need to bind the sets again.
567 if (!DescrSetBindInfo.DynamicDescriptorsBound ||
568 (DescrSetBindInfo.DynamicBuffersPresent && (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) == 0))
569 {
570 m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
571 }
725 auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(PIPELINE_TYPE_GRAPHICS)];
726
727 // First time we must always bind descriptor sets with dynamic offsets.
728 // If there are no dynamic buffers bound in the resource cache, for all subsequent
729 // cals we do not need to bind the sets again.
730 if (DescrSetBindInfo.RequireUpdate(Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT))
731 {
732 BindDescriptorSetsWithDynamicOffsets(DescrSetBindInfo);
572733 }
573734 #if 0
574735 # ifdef DILIGENT_DEBUG
593754
594755 CommitRenderPassAndFramebuffer((Flags & DRAW_FLAG_VERIFY_STATES) != 0);
595756 }
757
758 ValidateShaderResources();
596759 }
597760
598761 BufferVkImpl* DeviceContextVkImpl::PrepareIndirectDrawAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode)
712875 if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE)
713876 m_CommandBuffer.EndRenderPass();
714877
715 auto& DescrSetBindInfo = m_DescrSetBindInfo[1];
716
717 if (DescrSetBindInfo.DynamicOffsetCount != 0)
718 {
719 if (!DescrSetBindInfo.DynamicDescriptorsBound || DescrSetBindInfo.DynamicBuffersPresent)
720 {
721 m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
722 }
878 auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(PIPELINE_TYPE_COMPUTE)];
879
880 if (DescrSetBindInfo.RequireUpdate())
881 {
882 BindDescriptorSetsWithDynamicOffsets(DescrSetBindInfo);
723883 }
724884 #if 0
725885 # ifdef DILIGENT_DEBUG
730890 }
731891 # endif
732892 #endif
893
894 ValidateShaderResources();
733895 }
734896
735897 void DeviceContextVkImpl::PrepareForRayTracing()
736898 {
737899 EnsureVkCmdBuffer();
738900
739 auto& DescrSetBindInfo = m_DescrSetBindInfo[2];
740
741 if (DescrSetBindInfo.DynamicOffsetCount != 0)
742 {
743 if (!DescrSetBindInfo.DynamicDescriptorsBound || DescrSetBindInfo.DynamicBuffersPresent)
744 {
745 m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
746 }
747 }
901 auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(PIPELINE_TYPE_RAY_TRACING)];
902
903 if (DescrSetBindInfo.RequireUpdate())
904 {
905 BindDescriptorSetsWithDynamicOffsets(DescrSetBindInfo);
906 }
907
908 ValidateShaderResources();
748909 }
749910
750911 void DeviceContextVkImpl::DispatchCompute(const DispatchComputeAttribs& Attribs)
11281289 for (auto& BindInfo : m_DescrSetBindInfo)
11291290 BindInfo.Reset();
11301291
1131 for (auto& ResourcesPerBindPoint : m_ShaderResources)
1132 ResourcesPerBindPoint.fill({});
1133
11341292 m_State = ContextState{};
11351293 m_CommandBuffer.Reset();
11361294 m_pPipelineState = nullptr;
11701328
11711329 for (auto& BindInfo : m_DescrSetBindInfo)
11721330 BindInfo.Reset();
1173
1174 for (auto& ResourcesPerBindPoint : m_ShaderResources)
1175 ResourcesPerBindPoint.fill({});
11761331
11771332 VERIFY(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE, "Invalidating context with unifinished render pass");
11781333 m_CommandBuffer.Reset();
+0
-80
Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp less more
0 /*
1 * Copyright 2019-2021 Diligent Graphics LLC
2 * Copyright 2015-2019 Egor Yusov
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * In no event and under no legal theory, whether in tort (including negligence),
17 * contract, or otherwise, unless required by applicable law (such as deliberate
18 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
19 * liable for any damages, including any direct, indirect, special, incidental,
20 * or consequential damages of any character arising as a result of this License or
21 * out of the use or inability to use the software (including but not limited to damages
22 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23 * all other commercial damages or losses), even if such Contributor has been advised
24 * of the possibility of such damages.
25 */
26
27 #include "PipelineLayoutCacheVk.hpp"
28 #include "RenderDeviceVkImpl.hpp"
29
30 namespace Diligent
31 {
32
33 bool PipelineLayoutCacheVk::PipelineLayoutCompare::operator()(const PipelineLayoutVk* lhs, const PipelineLayoutVk* rhs) const noexcept
34 {
35 if (lhs->GetSignatureCount() != rhs->GetSignatureCount())
36 return false;
37
38 for (Uint32 i = 0, Cnt = lhs->GetSignatureCount(); i < Cnt; ++i)
39 {
40 if (lhs->GetSignature(i) != rhs->GetSignature(i))
41 return false;
42 }
43 return true;
44 }
45
46 PipelineLayoutCacheVk::~PipelineLayoutCacheVk()
47 {
48 std::lock_guard<std::mutex> Lock{m_Mutex};
49 VERIFY(m_Cache.empty(), "All pipeline layouts must be released");
50 }
51
52 RefCntAutoPtr<PipelineLayoutVk> PipelineLayoutCacheVk::GetLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount)
53 {
54 RefCntAutoPtr<PipelineLayoutVk> pNewLayout;
55 m_DeviceVk.CreatePipelineLayout(ppSignatures, SignatureCount, &pNewLayout);
56
57 if (pNewLayout == nullptr)
58 return {};
59
60 std::lock_guard<std::mutex> Lock{m_Mutex};
61
62 PipelineLayoutVk* pResult = *m_Cache.insert(pNewLayout).first;
63
64 if (pNewLayout == pResult)
65 {
66 pNewLayout->Finalize();
67 void(pNewLayout.Detach());
68 }
69 return RefCntAutoPtr<PipelineLayoutVk>{pResult};
70 }
71
72 void PipelineLayoutCacheVk::OnDestroyLayout(PipelineLayoutVk* pLayout)
73 {
74 std::lock_guard<std::mutex> Lock{m_Mutex};
75
76 m_Cache.erase(pLayout);
77 }
78
79 } // namespace Diligent
3838 namespace Diligent
3939 {
4040
41 PipelineLayoutVk::PipelineLayoutVk(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount) :
42 ObjectBase<IObject>{pRefCounters},
43 m_pDeviceVk{pDeviceVk},
44 m_SignatureCount{0}
41 PipelineLayoutVk::PipelineLayoutVk() :
42 m_DynamicOffsetCount{0},
43 m_SignatureCount{0},
44 m_DescrSetCount{0}
4545 {
46 }
47
48 void PipelineLayoutVk::Release(RenderDeviceVkImpl* pDeviceVk, Uint64 CommandQueueMask)
49 {
50 pDeviceVk->SafeReleaseDeviceObject(std::move(m_VkPipelineLayout), CommandQueueMask);
51 }
52
53 void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount)
54 {
55 VERIFY(m_DynamicOffsetCount == 0 && m_SignatureCount == 0 && m_DescrSetCount == 0,
56 "pipeline layout is already initialized");
57
4658 for (Uint32 i = 0; i < SignatureCount; ++i)
4759 {
48 auto* pSign = ValidatedCast<PipelineResourceSignatureVkImpl>(ppSignatures[i]);
49 if (pSign)
50 {
51 const Uint8 Index = pSign->GetDesc().BindingIndex;
60 auto* pSignature = ValidatedCast<PipelineResourceSignatureVkImpl>(ppSignatures[i]);
61 if (!pSignature)
62 LOG_ERROR_AND_THROW("pipeline resource signature (", i, ") must not be null");
5263
53 if (Index >= m_Signatures.size())
54 LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' index (", Uint32{Index}, ") must be less than (", m_Signatures.size(), ").");
64 const Uint32 Index = pSignature->GetDesc().BindingIndex;
5565
56 if (m_Signatures[Index] != nullptr)
57 LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' with index (", Uint32{Index}, ") overrides another resource signature '", m_Signatures[Index]->GetDesc().Name, "'.");
66 if (Index >= m_Signatures.size())
67 LOG_ERROR_AND_THROW("Pipeline resource signature '", pSignature->GetDesc().Name, "' index (", Uint32{Index}, ") must be less than (", m_Signatures.size(), ").");
5868
59 m_SignatureCount = std::max(m_SignatureCount, Uint8(Index + 1));
60 m_Signatures[Index] = pSign;
69 if (m_Signatures[Index] != nullptr)
70 LOG_ERROR_AND_THROW("Pipeline resource signature '", pSignature->GetDesc().Name, "' with index (", Uint32{Index}, ") overrides another resource signature '", m_Signatures[Index]->GetDesc().Name, "'.");
6171
62 if (m_PipelineType <= PIPELINE_TYPE_LAST)
63 {
64 if (m_PipelineType != pSign->GetPipelineType())
65 {
66 LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' with index (", Uint32{Index}, ") has different pipeline type (",
67 GetPipelineTypeString(pSign->GetPipelineType()), ") than other (", GetPipelineTypeString(m_PipelineType), ").");
68 }
69 }
70 else
71 m_PipelineType = pSign->GetPipelineType();
72 }
72 m_SignatureCount = std::max(m_SignatureCount, Index + 1);
73 m_Signatures[Index] = pSignature;
7374 }
74 }
7575
76 PipelineLayoutVk::~PipelineLayoutVk()
77 {
78 m_pDeviceVk->GetPipelineLayoutCache().OnDestroyLayout(this);
79 m_pDeviceVk->SafeReleaseDeviceObject(std::move(m_VkPipelineLayout), ~0ull);
80 }
81
82 void PipelineLayoutVk::Finalize()
83 {
84 std::array<VkDescriptorSetLayout, MAX_RESOURCE_SIGNATURES * 2> DescSetLayouts;
85
86 Uint32 DescSetLayoutCount = 0;
87 Uint32 DynamicBufferCount = 0;
76 auto* pEmptySign = ValidatedCast<PipelineResourceSignatureVkImpl>(pDeviceVk->GetEmptySignature());
8877
8978 for (Uint32 i = 0; i < m_SignatureCount; ++i)
9079 {
9180 if (m_Signatures[i] == nullptr)
92 continue;
81 m_Signatures[i] = pEmptySign;
82 }
83
84 std::array<VkDescriptorSetLayout, MAX_RESOURCE_SIGNATURES * 2> DescSetLayouts;
85
86 Uint32 DescSetLayoutCount = 0;
87 Uint32 DynamicOffsetCount = 0;
88 #ifdef DILIGENT_DEBUG
89 Uint32 DynamicUniformBufferCount = 0;
90 Uint32 DynamicStorageBufferCount = 0;
91 #endif
92
93 for (Uint32 i = 0; i < m_SignatureCount; ++i)
94 {
95 const auto& pSignature = m_Signatures[i];
96 VERIFY_EXPR(pSignature != nullptr);
9397
9498 m_DescSetOffset[i] = static_cast<Uint8>(DescSetLayoutCount);
95 m_DynBufOffset[i] = static_cast<Uint16>(DynamicBufferCount);
99 m_DynBufOffset[i] = static_cast<Uint16>(DynamicOffsetCount);
96100
97 auto StaticDSLayout = m_Signatures[i]->GetStaticVkDescriptorSetLayout();
98 auto DynamicDSLayout = m_Signatures[i]->GetDynamicVkDescriptorSetLayout();
101 auto StaticDSLayout = pSignature->GetStaticVkDescriptorSetLayout();
102 auto DynamicDSLayout = pSignature->GetDynamicVkDescriptorSetLayout();
99103
100104 if (StaticDSLayout) DescSetLayouts[DescSetLayoutCount++] = StaticDSLayout;
101105 if (DynamicDSLayout) DescSetLayouts[DescSetLayoutCount++] = DynamicDSLayout;
102106
103 DynamicBufferCount += m_Signatures[i]->GetDynamicBufferCount();
107 DynamicOffsetCount += pSignature->GetDynamicBufferCount();
108
109 #ifdef DILIGENT_DEBUG
110 for (Uint32 r = 0, ResCount = pSignature->GetTotalResourceCount(); r < ResCount; ++r)
111 {
112 const auto& Attr = pSignature->GetAttribs(r);
113
114 if (Attr.Type == DescriptorType::UniformBufferDynamic)
115 {
116 ++DynamicUniformBufferCount;
117 }
118 else if (Attr.Type == DescriptorType::StorageBufferDynamic ||
119 Attr.Type == DescriptorType::StorageBufferDynamic_ReadOnly)
120 {
121 ++DynamicStorageBufferCount;
122 }
123 }
124 #endif
104125 }
105126
106127 VkPipelineLayoutCreateInfo PipelineLayoutCI = {};
112133 PipelineLayoutCI.pSetLayouts = DescSetLayoutCount ? DescSetLayouts.data() : nullptr;
113134 PipelineLayoutCI.pushConstantRangeCount = 0;
114135 PipelineLayoutCI.pPushConstantRanges = nullptr;
115 m_VkPipelineLayout = m_pDeviceVk->GetLogicalDevice().CreatePipelineLayout(PipelineLayoutCI);
136 m_VkPipelineLayout = pDeviceVk->GetLogicalDevice().CreatePipelineLayout(PipelineLayoutCI);
116137
117 const auto& Limits = m_pDeviceVk->GetPhysicalDevice().GetProperties().limits;
138 const auto& Limits = pDeviceVk->GetPhysicalDevice().GetProperties().limits;
118139 VERIFY_EXPR(DescSetLayoutCount <= Limits.maxBoundDescriptorSets);
119 VERIFY_EXPR(DynamicBufferCount <= (Limits.maxDescriptorSetUniformBuffersDynamic + Limits.maxDescriptorSetStorageBuffersDynamic)); // AZ TODO
140 VERIFY_EXPR(DescSetLayoutCount <= MAX_RESOURCE_SIGNATURES * 2);
141
142 #ifdef DILIGENT_DEBUG
143 VERIFY_EXPR(DynamicUniformBufferCount <= Limits.maxDescriptorSetUniformBuffersDynamic);
144 VERIFY_EXPR(DynamicStorageBufferCount <= Limits.maxDescriptorSetStorageBuffersDynamic);
145 #endif
120146
121147 m_DescrSetCount = static_cast<Uint8>(DescSetLayoutCount);
122 m_DynamicOffsetCount = static_cast<Uint16>(DynamicBufferCount);
148 m_DynamicOffsetCount = DynamicOffsetCount;
123149 }
124150
125151 size_t PipelineLayoutVk::GetHash() const
128154 HashCombine(hash, m_SignatureCount);
129155 for (Uint32 i = 0; i < m_SignatureCount; ++i)
130156 {
131 if (m_Signatures[i] != nullptr)
132 HashCombine(hash, m_Signatures[i]->GetHash());
133 else
134 HashCombine(hash, 0);
157 VERIFY_EXPR(m_Signatures[i] != nullptr);
158 HashCombine(hash, m_Signatures[i]->GetHash());
135159 }
136160 return hash;
137161 }
139163 bool PipelineLayoutVk::GetResourceInfo(const char* Name, SHADER_TYPE Stage, ResourceInfo& Info) const
140164 {
141165 // AZ TODO: optimize
142 for (Uint32 i = 0, Count = GetSignatureCount(); i < Count; ++i)
166 for (Uint32 i = 0, DSCount = GetSignatureCount(); i < DSCount; ++i)
143167 {
144 auto* pSign = GetSignature(i);
145 if (pSign)
168 auto* pSignature = GetSignature(i);
169 VERIFY_EXPR(pSignature != nullptr);
170
171 for (Uint32 r = 0, ResCount = pSignature->GetTotalResourceCount(); r < ResCount; ++r)
146172 {
147 auto& Desc = pSign->GetDesc();
148 Uint32 BindingCount[2] = {};
173 const auto& Res = pSignature->GetResource(r);
174 const auto& Attr = pSignature->GetAttribs(r);
149175
150 for (Uint32 j = 0; j < Desc.NumResources; ++j)
176 if ((Res.ShaderStages & Stage) && strcmp(Res.Name, Name) == 0)
151177 {
152 auto& Res = Desc.Resources[j];
153 Uint16 DSIndex = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0);
154
155 if ((Res.ShaderStages & Stage) && strcmp(Res.Name, Name) == 0)
156 {
157 Info.Type = Res.ResourceType;
158 Info.BindingIndex = static_cast<Uint16>(BindingCount[DSIndex]);
159 Info.DescrSetIndex = m_DescSetOffset[i] + DSIndex;
160 return true;
161 }
162 BindingCount[DSIndex] += Res.ArraySize;
178 Info.Type = Res.ResourceType;
179 Info.BindingIndex = static_cast<Uint16>(Attr.BindingIndex);
180 Info.DescrSetIndex = m_DescSetOffset[i] + Attr.DescrSet;
181 return true;
163182 }
164183 }
165184 }
2929 #include "ShaderResourceBindingVkImpl.hpp"
3030 #include "RenderDeviceVkImpl.hpp"
3131 #include "VulkanTypeConversions.hpp"
32 #include "SamplerVkImpl.hpp"
33 #include "TextureViewVkImpl.hpp"
34 #include "TopLevelASVkImpl.hpp"
35 #include "BasicMath.hpp"
36 #include "DynamicLinearAllocator.hpp"
3237
3338 namespace Diligent
3439 {
35
36 VkDescriptorType PipelineResourceSignatureVkImpl::GetVkDescriptorType(const PipelineResourceDesc& Res)
40 namespace
41 {
42 VkDescriptorType GetVkDescriptorType(DescriptorType Type)
43 {
44 static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type");
45 switch (Type)
46 {
47 // clang-format off
48 case DescriptorType::Sampler: return VK_DESCRIPTOR_TYPE_SAMPLER;
49 case DescriptorType::CombinedImageSampler: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
50 case DescriptorType::SeparateImage: return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
51 case DescriptorType::StorageImage: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
52 case DescriptorType::StorageImage_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
53 case DescriptorType::UniformTexelBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
54 case DescriptorType::StorageTexelBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
55 case DescriptorType::StorageTexelBuffer_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
56 case DescriptorType::UniformBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
57 case DescriptorType::UniformBufferDynamic: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
58 case DescriptorType::StorageBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
59 case DescriptorType::StorageBuffer_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
60 case DescriptorType::StorageBufferDynamic: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
61 case DescriptorType::StorageBufferDynamic_ReadOnly: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
62 case DescriptorType::InputAttachment: return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
63 case DescriptorType::AccelerationStructure: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
64 // clang-format on
65 default:
66 UNEXPECTED("unknown descriptor type");
67 return VK_DESCRIPTOR_TYPE_MAX_ENUM;
68 }
69 }
70
71 DescriptorType GetDescriptorType(const PipelineResourceDesc& Res)
3772 {
3873 const bool WithDynamicOffset = !(Res.Flags & PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS);
3974 const bool CombinedSampler = (Res.Flags & PIPELINE_RESOURCE_FLAG_COMBINED_IMAGE);
4075 const bool UseTexelBuffer = (Res.Flags & PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER);
4176
42 VERIFY_EXPR(WithDynamicOffset ^ UseTexelBuffer);
43 VERIFY_EXPR(CombinedSampler ? !(WithDynamicOffset | UseTexelBuffer) : true);
44
4577 static_assert(SHADER_RESOURCE_TYPE_LAST == SHADER_RESOURCE_TYPE_ACCEL_STRUCT, "Please update the switch below to handle the new shader resource type");
4678 switch (Res.ResourceType)
4779 {
80 case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER:
81 VERIFY_EXPR(!(Res.Flags & ~PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS));
82 return WithDynamicOffset ? DescriptorType::UniformBufferDynamic : DescriptorType::UniformBuffer;
83
84 case SHADER_RESOURCE_TYPE_BUFFER_UAV:
85 VERIFY_EXPR(!(Res.Flags & ~(PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS | PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER)));
86 return UseTexelBuffer ? DescriptorType::StorageTexelBuffer :
87 (WithDynamicOffset ? DescriptorType::StorageBufferDynamic : DescriptorType::StorageBuffer);
88
89 case SHADER_RESOURCE_TYPE_TEXTURE_SRV:
90 VERIFY_EXPR(!(Res.Flags & ~PIPELINE_RESOURCE_FLAG_COMBINED_IMAGE));
91 return CombinedSampler ? DescriptorType::CombinedImageSampler : DescriptorType::SeparateImage;
92
93 case SHADER_RESOURCE_TYPE_BUFFER_SRV:
94 VERIFY_EXPR(!(Res.Flags & ~(PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS | PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER)));
95 return UseTexelBuffer ? DescriptorType::UniformTexelBuffer :
96 (WithDynamicOffset ? DescriptorType::StorageBufferDynamic_ReadOnly : DescriptorType::StorageBuffer_ReadOnly);
97
98 case SHADER_RESOURCE_TYPE_TEXTURE_UAV:
99 VERIFY_EXPR(!Res.Flags);
100 return DescriptorType::StorageImage;
101
102 case SHADER_RESOURCE_TYPE_SAMPLER:
103 VERIFY_EXPR(!Res.Flags);
104 return DescriptorType::Sampler;
105
106 case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT:
107 VERIFY_EXPR(!Res.Flags);
108 return DescriptorType::InputAttachment;
109
110 case SHADER_RESOURCE_TYPE_ACCEL_STRUCT:
111 VERIFY_EXPR(!Res.Flags);
112 return DescriptorType::AccelerationStructure;
113
114 default:
115 UNEXPECTED("unknown resource type");
116 return DescriptorType::Unknown;
117 }
118 }
119
120 BUFFER_VIEW_TYPE DescriptorTypeToBufferView(DescriptorType Type)
121 {
122 static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type");
123 switch (Type)
124 {
48125 // clang-format off
49 case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER: return WithDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
50 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);
51 case SHADER_RESOURCE_TYPE_TEXTURE_SRV: return CombinedSampler ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
52 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);
53 case SHADER_RESOURCE_TYPE_TEXTURE_UAV: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
54 case SHADER_RESOURCE_TYPE_SAMPLER: return VK_DESCRIPTOR_TYPE_SAMPLER;
55 case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT: return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
56 case SHADER_RESOURCE_TYPE_ACCEL_STRUCT: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
57 default: UNEXPECTED("unknown resource type");
126 case DescriptorType::UniformTexelBuffer:
127 case DescriptorType::StorageTexelBuffer_ReadOnly:
128 case DescriptorType::StorageBuffer_ReadOnly:
129 case DescriptorType::StorageBufferDynamic_ReadOnly: return BUFFER_VIEW_SHADER_RESOURCE;
130 case DescriptorType::StorageTexelBuffer:
131 case DescriptorType::StorageBuffer:
132 case DescriptorType::StorageBufferDynamic: return BUFFER_VIEW_UNORDERED_ACCESS;
58133 // clang-format on
59 }
60 return VK_DESCRIPTOR_TYPE_MAX_ENUM;
61 }
134 default:
135 UNEXPECTED("unsupported descriptor type for buffer view");
136 return BUFFER_VIEW_UNDEFINED;
137 }
138 }
139
140 TEXTURE_VIEW_TYPE DescriptorTypeToTextureView(DescriptorType Type)
141 {
142 static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type");
143 switch (Type)
144 {
145 // clang-format off
146 case DescriptorType::StorageImage: return TEXTURE_VIEW_UNORDERED_ACCESS;
147 case DescriptorType::CombinedImageSampler:
148 case DescriptorType::SeparateImage:
149 case DescriptorType::StorageImage_ReadOnly:
150 case DescriptorType::InputAttachment: return TEXTURE_VIEW_SHADER_RESOURCE;
151 // clang-format on
152 default:
153 UNEXPECTED("unsupported descriptor type for texture view");
154 return TEXTURE_VIEW_UNDEFINED;
155 }
156 }
157
158 Int32 FindImmutableSampler(const PipelineResourceDesc& Res,
159 DescriptorType DescType,
160 const PipelineResourceSignatureDesc& Desc,
161 const char* SamplerSuffix)
162 {
163 if (DescType == DescriptorType::CombinedImageSampler)
164 {
165 SamplerSuffix = nullptr;
166 }
167 else if (DescType == DescriptorType::Sampler)
168 {
169 // Use SamplerSuffix. If HLSL-style combined images samplers are not used,
170 // SamplerSuffix will be null and we will be looking for the sampler itself.
171 }
172 else
173 {
174 UNEXPECTED("Immutable sampler can only be assigned to a sampled image or separate sampler");
175 return -1;
176 }
177
178 for (Uint32 s = 0; s < Desc.NumImmutableSamplers; ++s)
179 {
180 const auto& ImtblSam = Desc.ImmutableSamplers[s];
181 if (((ImtblSam.ShaderStages & Res.ShaderStages) != 0) && StreqSuff(Res.Name, ImtblSam.SamplerOrTextureName, SamplerSuffix))
182 {
183 VERIFY_EXPR((ImtblSam.ShaderStages & Res.ShaderStages) == Res.ShaderStages);
184 return s;
185 }
186 }
187
188 return -1;
189 }
190 } // namespace
191
192
193 RESOURCE_STATE DescriptorTypeToResourceState(DescriptorType Type)
194 {
195 static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type");
196 switch (Type)
197 {
198 // clang-format off
199 case DescriptorType::Sampler: return RESOURCE_STATE_UNKNOWN;
200 case DescriptorType::CombinedImageSampler: return RESOURCE_STATE_SHADER_RESOURCE;
201 case DescriptorType::SeparateImage: return RESOURCE_STATE_SHADER_RESOURCE;
202 case DescriptorType::StorageImage: return RESOURCE_STATE_UNORDERED_ACCESS;
203 case DescriptorType::StorageImage_ReadOnly: return RESOURCE_STATE_SHADER_RESOURCE;
204 case DescriptorType::UniformTexelBuffer: return RESOURCE_STATE_SHADER_RESOURCE;
205 case DescriptorType::StorageTexelBuffer: return RESOURCE_STATE_UNORDERED_ACCESS;
206 case DescriptorType::StorageTexelBuffer_ReadOnly: return RESOURCE_STATE_SHADER_RESOURCE;
207 case DescriptorType::UniformBuffer: return RESOURCE_STATE_CONSTANT_BUFFER;
208 case DescriptorType::UniformBufferDynamic: return RESOURCE_STATE_CONSTANT_BUFFER;
209 case DescriptorType::StorageBuffer: return RESOURCE_STATE_UNORDERED_ACCESS;
210 case DescriptorType::StorageBuffer_ReadOnly: return RESOURCE_STATE_SHADER_RESOURCE;
211 case DescriptorType::StorageBufferDynamic: return RESOURCE_STATE_UNORDERED_ACCESS;
212 case DescriptorType::StorageBufferDynamic_ReadOnly: return RESOURCE_STATE_SHADER_RESOURCE;
213 case DescriptorType::InputAttachment: return RESOURCE_STATE_SHADER_RESOURCE;
214 case DescriptorType::AccelerationStructure: return RESOURCE_STATE_SHADER_RESOURCE;
215 // clang-format on
216 default:
217 UNEXPECTED("unknown descriptor type");
218 return RESOURCE_STATE_UNKNOWN;
219 }
220 }
221
222
223 #define LOG_PRS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a pipeline resource signature '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
62224
63225 PipelineResourceSignatureVkImpl::PipelineResourceSignatureVkImpl(IReferenceCounters* pRefCounters,
64226 RenderDeviceVkImpl* pDevice,
65227 const PipelineResourceSignatureDesc& Desc,
66228 bool bIsDeviceInternal) :
67229 TPipelineResourceSignatureBase{pRefCounters, pDevice, Desc, bIsDeviceInternal},
68 m_SRBMemAllocator{GetRawAllocator()}
69 {
70 #define LOG_PRS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a pipeline resource signature '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
71
230 m_SRBMemAllocator{GetRawAllocator()},
231 m_DynamicBufferCount{0},
232 m_NumShaders{0}
233 {
72234 try
73235 {
74236 FixedLinearAllocator MemPool{GetRawAllocator()};
75237
76 MemPool.AddSpace<PackedBindingIndex>(Desc.NumResources);
238 // reserve at least 1 element because m_pResourceAttribs must hold pointer to memory
239 MemPool.AddSpace<ResourceAttribs>(std::max(1u, Desc.NumResources));
240 MemPool.AddSpace<ImmutableSamplerPtrType>(Desc.NumImmutableSamplers);
77241
78242 ReserveSpaceForDescription(MemPool, Desc);
79243
80244 Int8 StaticVarStageCount = 0;
81245 Uint32 StaticVarCount = 0;
82 {
83 // get active shader stages
84 SHADER_TYPE Stages = SHADER_TYPE_UNKNOWN;
85 SHADER_TYPE StaticResStages = SHADER_TYPE_UNKNOWN;
86
87 for (Uint32 i = 0; i < Desc.NumResources; ++i)
246 Uint8 DSMapping[2] = {};
247 ReserveSpaceForStaticVarsMgrs(Desc, MemPool, StaticVarStageCount, StaticVarCount, DSMapping);
248
249 MemPool.Reserve();
250
251 m_pResourceAttribs = MemPool.ConstructArray<ResourceAttribs>(std::max(1u, m_Desc.NumResources));
252 m_ImmutableSamplers = MemPool.ConstructArray<ImmutableSamplerPtrType>(m_Desc.NumImmutableSamplers);
253
254 // The memory is now owned by PipelineResourceSignatureVkImpl and will be freed by Destruct().
255 auto* Ptr = MemPool.ReleaseOwnership();
256 VERIFY_EXPR(Ptr == m_pResourceAttribs);
257 (void)Ptr;
258
259 CopyDescription(MemPool, Desc);
260
261 if (StaticVarStageCount > 0)
262 {
263 m_pResourceCache = MemPool.Construct<ShaderResourceCacheVk>(ShaderResourceCacheVk::StaticShaderResources);
264 m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerVk>(StaticVarStageCount);
265
266 m_pResourceCache->InitializeSets(GetRawAllocator(), 1, &StaticVarCount);
267
268 const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
269
270 for (Uint32 i = 0; i < m_StaticVarIndex.size(); ++i)
88271 {
89 const auto& Res = Desc.Resources[i];
90 Stages |= Res.ShaderStages;
91
92 if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
272 Int8 Idx = m_StaticVarIndex[i];
273 if (Idx >= 0)
93274 {
94 StaticResStages |= Res.ShaderStages;
95 StaticVarCount += Res.ArraySize;
275 VERIFY_EXPR(Idx < StaticVarStageCount);
276 const auto ShaderType = GetShaderTypeFromPipelineIndex(i, GetPipelineType());
277 new (m_StaticVarsMgrs + Idx) ShaderVariableManagerVk{*this, *m_pResourceCache};
278 m_StaticVarsMgrs[Idx].Initialize(*this, GetRawAllocator(), AllowedVarTypes, _countof(AllowedVarTypes), ShaderType);
96279 }
97280 }
98
99 m_ShaderStages = Stages;
100 m_NumShaders = static_cast<Uint8>(PlatformMisc::CountOneBits(static_cast<Uint32>(Stages)));
101
102 if (Stages == SHADER_TYPE_COMPUTE)
103 {
104 m_PipelineType = PIPELINE_TYPE_COMPUTE;
105 }
106 else if (Stages & (SHADER_TYPE_AMPLIFICATION | SHADER_TYPE_MESH))
107 {
108 m_PipelineType = PIPELINE_TYPE_MESH;
109 }
110 else if (Stages < SHADER_TYPE_COMPUTE)
111 {
112 m_PipelineType = PIPELINE_TYPE_GRAPHICS;
113 }
114 else if (Stages >= SHADER_TYPE_RAY_GEN)
115 {
116 m_PipelineType = PIPELINE_TYPE_RAY_TRACING;
117 }
118 else
119 {
120 LOG_PRS_ERROR_AND_THROW("can not deduce pipeline type - used incompatible shader stages");
121 }
122
123 m_StaticVarIndex.fill(-1);
124
125 for (; StaticResStages != SHADER_TYPE_UNKNOWN; ++StaticVarStageCount)
126 {
127 auto StageBit = static_cast<SHADER_TYPE>(1 << PlatformMisc::GetLSB(Uint32{StaticResStages}));
128 StaticResStages = StaticResStages & ~StageBit;
129
130 const auto ShaderTypeInd = GetShaderTypePipelineIndex(StageBit, m_PipelineType);
131 m_StaticVarIndex[ShaderTypeInd] = StaticVarStageCount;
132 }
133
134 if (StaticVarStageCount > 0)
135 {
136 MemPool.AddSpace<ShaderResourceCacheVk>(1);
137 MemPool.AddSpace<ShaderVariableManagerVk>(StaticVarStageCount);
138 }
139 }
140
141
142 MemPool.Reserve();
143
144
145 m_pBindingIndices = MemPool.Allocate<PackedBindingIndex>(m_Desc.NumResources);
146
147 // The memory is now owned by PipelineResourceSignatureVkImpl and will be freed by Destruct().
148 auto* Ptr = MemPool.ReleaseOwnership();
149 VERIFY_EXPR(Ptr == m_pBindingIndices);
150 (void)Ptr;
151
152 CopyDescription(MemPool, Desc);
153
154 if (StaticVarStageCount > 0)
155 {
156 m_pResourceCache = MemPool.Construct<ShaderResourceCacheVk>(ShaderResourceCacheVk::StaticShaderResources);
157 m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerVk>(StaticVarStageCount);
158
159 m_pResourceCache->InitializeSets(GetRawAllocator(), 1, &StaticVarCount);
160
161 const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
162
163 for (Int8 i = 0; i < StaticVarStageCount; ++i)
164 {
165 new (m_StaticVarsMgrs + i) ShaderVariableManagerVk{*this, *m_pResourceCache};
166 m_StaticVarsMgrs[i].Initialize(*this, GetRawAllocator(), AllowedVarTypes, _countof(AllowedVarTypes));
167 }
168 }
169
170 std::vector<VkDescriptorSetLayoutBinding> LayoutBindings[2];
171
172 for (Uint32 i = 0; i < m_Desc.NumResources; ++i)
173 {
174 const auto& Res = m_Desc.Resources[i];
175 auto& Binding = m_pBindingIndices[i];
176
177 Binding.DescSet = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0);
178 Binding.Binding = static_cast<Uint16>(LayoutBindings[Binding.DescSet].size());
179 Binding.SamplerInd = 0; // AZ TODO
180
181 LayoutBindings[Binding.DescSet].emplace_back();
182 auto& LayoutBinding = LayoutBindings[Binding.DescSet].back();
183
184 LayoutBinding.binding = Binding.Binding;
185 LayoutBinding.descriptorCount = Res.ArraySize;
186 LayoutBinding.stageFlags = ShaderTypesToVkShaderStageFlags(Res.ShaderStages);
187 LayoutBinding.pImmutableSamplers = nullptr;
188 LayoutBinding.descriptorType = GetVkDescriptorType(Res);
189
190 if (!(Res.Flags & PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS))
191 m_DynamicBufferCount += static_cast<Uint16>(Res.ArraySize);
192
193 if (m_pResourceCache && Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
194 m_pResourceCache->InitializeResources(0, Binding.Binding, Res.ArraySize, LayoutBinding.descriptorType);
195 }
196
197 if (m_Desc.SRBAllocationGranularity > 1)
198 {
199 const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
200
201 Uint32 UnusedNumVars = 0;
202 const size_t ShaderVariableDataSize = ShaderVariableManagerVk::GetRequiredMemorySize(*this, AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars);
203
204 const Uint32 NumSets = !LayoutBindings[0].empty() + !LayoutBindings[1].empty();
205 const Uint32 DescriptorSetSizes[] = {static_cast<Uint32>(LayoutBindings[0].size()), static_cast<Uint32>(LayoutBindings[1].size())};
206 const size_t CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes);
207
208 m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, 1, &ShaderVariableDataSize, 1, &CacheMemorySize);
209 }
210
211 VkDescriptorSetLayoutCreateInfo SetLayoutCI = {};
212
213 SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
214 SetLayoutCI.pNext = nullptr;
215 SetLayoutCI.flags = 0;
216
217 const auto& LogicalDevice = pDevice->GetLogicalDevice();
218
219 for (Uint32 i = 0; i < _countof(LayoutBindings); ++i)
220 {
221 auto& LayoutBinding = LayoutBindings[i];
222 if (LayoutBinding.empty())
223 continue;
224
225 SetLayoutCI.bindingCount = static_cast<Uint32>(LayoutBinding.size());
226 SetLayoutCI.pBindings = LayoutBinding.data();
227 m_VkDescSetLayouts[i] = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI);
228 }
281 }
282
283 CreateLayout(StaticVarCount, DSMapping);
229284 }
230285 catch (...)
231286 {
232287 Destruct();
233288 throw;
234289 }
290 }
291
292 void PipelineResourceSignatureVkImpl::ReserveSpaceForStaticVarsMgrs(const PipelineResourceSignatureDesc& Desc,
293 FixedLinearAllocator& MemPool,
294 Int8& StaticVarStageCount,
295 Uint32& StaticVarCount,
296 Uint8 DSMapping[2])
297 {
298 // get active shader stages
299 SHADER_TYPE Stages = SHADER_TYPE_UNKNOWN;
300 SHADER_TYPE StaticResStages = SHADER_TYPE_UNKNOWN;
301
302 bool VarExist[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES] = {};
303
304 for (Uint32 i = 0; i < Desc.NumResources; ++i)
305 {
306 const auto& Res = Desc.Resources[i];
307 Stages |= Res.ShaderStages;
308
309 if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
310 {
311 StaticResStages |= Res.ShaderStages;
312 StaticVarCount += Res.ArraySize;
313 }
314
315 VarExist[Res.VarType] = true;
316 }
317
318 // initialize descriptor set mapping table
319 {
320 Uint8 Idx = 0;
321 if (VarExist[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] || VarExist[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE])
322 DSMapping[0] = Idx++;
323 else
324 DSMapping[0] = 0xFF;
325
326 if (VarExist[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC])
327 DSMapping[1] = Idx;
328 else
329 DSMapping[1] = 0xFF;
330 }
331
332 m_ShaderStages = Stages;
333 m_NumShaders = PlatformMisc::CountOneBits(static_cast<Uint32>(Stages));
334
335 if (Stages == SHADER_TYPE_COMPUTE)
336 {
337 m_PipelineType = PIPELINE_TYPE_COMPUTE;
338 }
339 else if (Stages & (SHADER_TYPE_AMPLIFICATION | SHADER_TYPE_MESH))
340 {
341 m_PipelineType = PIPELINE_TYPE_MESH;
342 }
343 else if (Stages < SHADER_TYPE_COMPUTE)
344 {
345 m_PipelineType = PIPELINE_TYPE_GRAPHICS;
346 }
347 else if (Stages >= SHADER_TYPE_RAY_GEN)
348 {
349 m_PipelineType = PIPELINE_TYPE_RAY_TRACING;
350 }
351 else
352 {
353 LOG_PRS_ERROR_AND_THROW("can not deduce pipeline type - used incompatible shader stages");
354 }
355
356 m_StaticVarIndex.fill(-1);
357
358 for (; StaticResStages != SHADER_TYPE_UNKNOWN; ++StaticVarStageCount)
359 {
360 const auto StageBit = ExtractBit(StaticResStages);
361 const auto ShaderTypeInd = GetShaderTypePipelineIndex(StageBit, m_PipelineType);
362 m_StaticVarIndex[ShaderTypeInd] = StaticVarStageCount;
363 }
364
365 if (StaticVarStageCount > 0)
366 {
367 MemPool.AddSpace<ShaderResourceCacheVk>(1);
368 MemPool.AddSpace<ShaderVariableManagerVk>(StaticVarStageCount);
369 }
370 }
235371 #undef LOG_PRS_ERROR_AND_THROW
372
373 void PipelineResourceSignatureVkImpl::CreateLayout(Uint32 StaticVarCount, const Uint8 DSMapping[2])
374 {
375 std::vector<VkDescriptorSetLayoutBinding> LayoutBindings[2];
376 DynamicLinearAllocator TempAllocator{GetRawAllocator()};
377
378 Uint32 CacheOffsets[Uint32{SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES}] = {0, StaticVarCount, 0};
379
380 for (Uint32 i = 0; i < m_Desc.NumResources; ++i)
381 {
382 const auto& Res = m_Desc.Resources[i];
383 auto& Attribs = m_pResourceAttribs[i];
384 auto& CacheOffset = CacheOffsets[Uint32{Res.VarType}];
385 const Uint32 SetIdx = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0);
386
387 // If all resources are dynamic then signature contains only one descriptor set layout with index 0,
388 // so remap SetIdx to actual descriptor set index.
389 VERIFY_EXPR(DSMapping[SetIdx] <= 1);
390
391 Attribs.DescrSet = DSMapping[SetIdx];
392 Attribs.BindingIndex = static_cast<Uint16>(LayoutBindings[SetIdx].size());
393 Attribs.CacheOffset = CacheOffset;
394 Attribs.Type = GetDescriptorType(Res);
395
396 CacheOffset += Res.ArraySize;
397
398 LayoutBindings[SetIdx].emplace_back();
399 auto& LayoutBinding = LayoutBindings[SetIdx].back();
400
401 LayoutBinding.binding = Attribs.BindingIndex;
402 LayoutBinding.descriptorCount = Res.ArraySize;
403 LayoutBinding.stageFlags = ShaderTypesToVkShaderStageFlags(Res.ShaderStages);
404 LayoutBinding.pImmutableSamplers = nullptr;
405 LayoutBinding.descriptorType = GetVkDescriptorType(Attribs.Type);
406
407 if (Attribs.Type == DescriptorType::SeparateImage)
408 {
409 Attribs.SamplerInd = FindAssignedSampler(Res);
410 }
411
412 if (Attribs.Type == DescriptorType::CombinedImageSampler ||
413 Attribs.Type == DescriptorType::Sampler)
414 {
415 // Only search for the immutable sampler for combined image samplers and separate samplers
416 Int32 SrcImmutableSamplerInd = FindImmutableSampler(Res, Attribs.Type, m_Desc, GetCombinedSamplerSuffix());
417 if (SrcImmutableSamplerInd >= 0)
418 {
419 auto& ImmutableSampler = m_ImmutableSamplers[SrcImmutableSamplerInd];
420 const auto& ImmutableSamplerDesc = m_Desc.ImmutableSamplers[SrcImmutableSamplerInd].Desc;
421 if (!ImmutableSampler)
422 GetDevice()->CreateSampler(ImmutableSamplerDesc, &ImmutableSampler);
423
424 const VkSampler VkImmutableSampler = ImmutableSampler.RawPtr<SamplerVkImpl>()->GetVkSampler();
425 VkSampler* SamplerArray = TempAllocator.Allocate<VkSampler>(Res.ArraySize);
426 for (Uint32 a = 0; a < Res.ArraySize; ++a)
427 SamplerArray[a] = VkImmutableSampler;
428
429 LayoutBinding.pImmutableSamplers = SamplerArray;
430 Attribs.ImmutableSamplerAssigned = true;
431 }
432 }
433
434 if (Attribs.Type == DescriptorType::UniformBufferDynamic ||
435 Attribs.Type == DescriptorType::StorageBufferDynamic ||
436 Attribs.Type == DescriptorType::StorageBufferDynamic_ReadOnly)
437 {
438 m_DynamicBufferCount += Res.ArraySize;
439 }
440
441 if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
442 m_pResourceCache->InitializeResources(Attribs.DescrSet, Attribs.CacheOffset, Res.ArraySize, Attribs.Type);
443 }
444 VERIFY_EXPR(CacheOffsets[0] == StaticVarCount);
445
446 if (m_Desc.SRBAllocationGranularity > 1)
447 {
448 std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {};
449 for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
450 {
451 const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
452
453 Uint32 UnusedNumVars = 0;
454 ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(*this, AllowedVarTypes, _countof(AllowedVarTypes), GetShaderStageType(s), UnusedNumVars);
455 }
456
457 Uint32 DescriptorSetSizes[2] = {CacheOffsets[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE], CacheOffsets[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC]};
458 const Uint32 NumSets = !!DescriptorSetSizes[0] + !!DescriptorSetSizes[1];
459
460 if (DescriptorSetSizes[0] == 0)
461 DescriptorSetSizes[0] = DescriptorSetSizes[1];
462
463 const size_t CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes);
464
465 m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderVariableDataSizes.data(), 1, &CacheMemorySize);
466 }
467
468 VkDescriptorSetLayoutCreateInfo SetLayoutCI = {};
469
470 SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
471 SetLayoutCI.pNext = nullptr;
472 SetLayoutCI.flags = 0;
473
474 const auto& LogicalDevice = GetDevice()->GetLogicalDevice();
475
476 for (Uint32 i = 0; i < _countof(LayoutBindings); ++i)
477 {
478 auto& LayoutBinding = LayoutBindings[i];
479 if (LayoutBinding.empty())
480 continue;
481
482 SetLayoutCI.bindingCount = static_cast<Uint32>(LayoutBinding.size());
483 SetLayoutCI.pBindings = LayoutBinding.data();
484 m_VkDescSetLayouts[i] = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI);
485 }
486 }
487
488 Uint32 PipelineResourceSignatureVkImpl::FindAssignedSampler(const PipelineResourceDesc& SepImg) const
489 {
490 Uint32 SamplerInd = InvalidSamplerInd;
491 if (IsUsingCombinedSamplers())
492 {
493 for (Uint32 i = 0; i < m_Desc.NumResources; ++i)
494 {
495 const auto& Res = m_Desc.Resources[i];
496
497 if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER &&
498 SepImg.VarType == Res.VarType &&
499 (SepImg.ShaderStages & Res.ShaderStages) &&
500 StreqSuff(Res.Name, SepImg.Name, GetCombinedSamplerSuffix()))
501 {
502 VERIFY_EXPR((Res.ShaderStages & SepImg.ShaderStages) == SepImg.ShaderStages);
503 SamplerInd = i;
504 break;
505 }
506 }
507 }
508 return SamplerInd;
236509 }
237510
238511 PipelineResourceSignatureVkImpl::~PipelineResourceSignatureVkImpl()
250523 m_pDevice->SafeReleaseDeviceObject(std::move(Layout), ~0ull);
251524 }
252525
253 if (m_pBindingIndices == nullptr)
526 if (m_pResourceAttribs == nullptr)
254527 return; // memory is not allocated
255528
256529 auto& RawAllocator = GetRawAllocator();
257530
258 for (size_t i = 0; m_StaticVarsMgrs && i < m_StaticVarIndex.size(); ++i)
259 {
260 Int8 Idx = m_StaticVarIndex[i];
261 if (Idx >= 0)
262 {
263 m_StaticVarsMgrs[Idx].DestroyVariables(RawAllocator);
264 m_StaticVarsMgrs[Idx].~ShaderVariableManagerVk();
265 }
266 }
267 m_StaticVarsMgrs = nullptr;
531 if (m_StaticVarsMgrs != nullptr)
532 {
533 for (size_t i = 0; i < m_StaticVarIndex.size(); ++i)
534 {
535 Int8 Idx = m_StaticVarIndex[i];
536 if (Idx >= 0)
537 {
538 m_StaticVarsMgrs[Idx].DestroyVariables(RawAllocator);
539 m_StaticVarsMgrs[Idx].~ShaderVariableManagerVk();
540 }
541 }
542 m_StaticVarIndex.fill(-1);
543 m_StaticVarsMgrs = nullptr;
544 }
268545
269546 if (m_pResourceCache != nullptr)
270547 {
272549 m_pResourceCache = nullptr;
273550 }
274551
275 if (void* pRawMem = m_pBindingIndices)
552 for (Uint32 i = 0; i < m_Desc.NumImmutableSamplers; ++i)
553 {
554 m_ImmutableSamplers[i].~ImmutableSamplerPtrType();
555 }
556 m_ImmutableSamplers = nullptr;
557
558 if (void* pRawMem = m_pResourceAttribs)
276559 {
277560 RawAllocator.Free(pRawMem);
278 m_pBindingIndices = nullptr;
279 }
561 m_pResourceAttribs = nullptr;
562 }
563 }
564
565 bool PipelineResourceSignatureVkImpl::IsCompatibleWith(const PipelineResourceSignatureVkImpl& Other) const
566 {
567 if (this == &Other)
568 return true;
569
570 if (GetHash() != Other.GetHash())
571 return false;
572
573 if (GetDesc().BindingIndex != Other.GetDesc().BindingIndex)
574 return false;
575
576 const Uint32 LCount = GetTotalResourceCount();
577 const Uint32 RCount = Other.GetTotalResourceCount();
578
579 if (LCount != RCount)
580 return false;
581
582 for (Uint32 r = 0; r < LCount; ++r)
583 {
584 const auto& LAttr = GetAttribs(r);
585 const auto& RAttr = Other.GetAttribs(r);
586
587 if (LAttr.Type != RAttr.Type ||
588 LAttr.DescrSet != RAttr.DescrSet ||
589 LAttr.BindingIndex != RAttr.BindingIndex ||
590 LAttr.CacheOffset != RAttr.CacheOffset ||
591 LAttr.ImmutableSamplerAssigned != RAttr.ImmutableSamplerAssigned)
592 {
593 return false;
594 }
595 }
596
597 const Uint32 LSampCount = GetDesc().NumImmutableSamplers;
598 const Uint32 RSampCount = Other.GetDesc().NumImmutableSamplers;
599
600 if (LSampCount != RSampCount)
601 return false;
602
603 for (Uint32 s = 0; s < LSampCount; ++s)
604 {
605 const auto& LSamp = GetDesc().ImmutableSamplers[s];
606 const auto& RSamp = Other.GetDesc().ImmutableSamplers[s];
607
608 if (LSamp.ShaderStages != RSamp.ShaderStages ||
609 !(LSamp.Desc == RSamp.Desc))
610 return false;
611 }
612
613 return true;
280614 }
281615
282616 void PipelineResourceSignatureVkImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding,
289623 pResBindingVk->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
290624 }
291625
292 void PipelineResourceSignatureVkImpl::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
293 VkPipelineBindPoint BindPoint,
294 const ShaderResourceCacheVk& ResourceCache,
295 DescriptorSetBindInfo& BindInfo,
296 VkDescriptorSet VkDynamicDescrSet) const
297 {
298 /*
299 #ifdef DILIGENT_DEBUG
300 BindInfo.vkSets.clear();
301 #endif
302
303 // Do not use vector::resize for BindInfo.vkSets and BindInfo.DynamicOffsets as this
304 // causes unnecessary work to zero-initialize new elements
305
306 VERIFY(m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC).SetIndex == m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE).SetIndex,
307 "Static and mutable variables are expected to share the same descriptor set");
308 Uint32 TotalDynamicDescriptors = 0;
309
310 BindInfo.SetCout = 0;
311 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))
312 {
313 const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType);
314 if (Set.SetIndex >= 0)
315 {
316 BindInfo.SetCout = std::max(BindInfo.SetCout, static_cast<Uint32>(Set.SetIndex + 1));
317 if (BindInfo.SetCout > BindInfo.vkSets.size())
318 BindInfo.vkSets.resize(BindInfo.SetCout);
319 VERIFY_EXPR(BindInfo.vkSets[Set.SetIndex] == VK_NULL_HANDLE);
320 if (VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
321 BindInfo.vkSets[Set.SetIndex] = ResourceCache.GetDescriptorSet(Set.SetIndex).GetVkDescriptorSet();
322 else
323 {
324 VERIFY_EXPR(ResourceCache.GetDescriptorSet(Set.SetIndex).GetVkDescriptorSet() == VK_NULL_HANDLE);
325 BindInfo.vkSets[Set.SetIndex] = VkDynamicDescrSet;
326 }
327 VERIFY(BindInfo.vkSets[Set.SetIndex] != VK_NULL_HANDLE, "Descriptor set must not be null");
328 }
329 TotalDynamicDescriptors += Set.NumDynamicDescriptors;
330 }
331
332 #ifdef DILIGENT_DEBUG
333 for (const auto& set : BindInfo.vkSets)
334 VERIFY(set != VK_NULL_HANDLE, "Descriptor set must not be null");
335 #endif
336
337 BindInfo.DynamicOffsetCount = TotalDynamicDescriptors;
338 if (TotalDynamicDescriptors > BindInfo.DynamicOffsets.size())
339 BindInfo.DynamicOffsets.resize(TotalDynamicDescriptors);
340 BindInfo.BindPoint = BindPoint;
341 BindInfo.pResourceCache = &ResourceCache;
342 #ifdef DILIGENT_DEBUG
343 BindInfo.pDbgPipelineLayout = this;
344 #endif
345 BindInfo.DynamicBuffersPresent = ResourceCache.GetNumDynamicBuffers() > 0;
346
347 if (TotalDynamicDescriptors == 0)
348 {
349 // There are no dynamic descriptors, so we can bind descriptor sets right now
350 auto& CmdBuffer = pCtxVkImpl->GetCommandBuffer();
351 CmdBuffer.BindDescriptorSets(BindInfo.BindPoint,
352 m_LayoutMgr.GetVkPipelineLayout(),
353 0, // First set
354 BindInfo.SetCout,
355 BindInfo.vkSets.data(), // BindInfo.vkSets is never empty
356 0,
357 nullptr);
358 }
359
360 BindInfo.DynamicDescriptorsBound = false;
361 */
362 }
363
364626 Uint32 PipelineResourceSignatureVkImpl::GetStaticVariableCount(SHADER_TYPE ShaderType) const
365627 {
366628 const auto VarMngrInd = GetStaticVariableCountHelper(ShaderType, m_StaticVarIndex);
391653 return StaticVarMgr.GetVariable(Index);
392654 }
393655
656 void PipelineResourceSignatureVkImpl::BindStaticResources(Uint32 ShaderFlags,
657 IResourceMapping* pResMapping,
658 Uint32 Flags)
659 {
660 const auto PipelineType = GetPipelineType();
661 for (Uint32 ShaderInd = 0; ShaderInd < m_StaticVarIndex.size(); ++ShaderInd)
662 {
663 const auto VarMngrInd = m_StaticVarIndex[ShaderInd];
664 if (VarMngrInd >= 0)
665 {
666 // ShaderInd is the shader type pipeline index here
667 const auto ShaderType = GetShaderTypeFromPipelineIndex(ShaderInd, PipelineType);
668 if (ShaderFlags & ShaderType)
669 {
670 m_StaticVarsMgrs[VarMngrInd].BindResources(pResMapping, Flags);
671 }
672 }
673 }
674 }
675
394676 void PipelineResourceSignatureVkImpl::InitResourceCache(ShaderResourceCacheVk& ResourceCache,
395677 IMemoryAllocator& CacheMemAllocator,
396678 const char* DbgPipelineName) const
397679 {
398680 std::array<Uint32, 2> VarCount = {};
681 Uint32 NumSets = static_cast<Uint32>(VarCount.size());
682
399683 for (Uint32 r = 0; r < m_Desc.NumResources; ++r)
400684 {
401685 const auto& Res = GetResource(r);
402 const auto& Bind = GetBinding(r);
403 VarCount[Bind.DescSet] += Res.ArraySize;
404 }
686 const auto& Attr = GetAttribs(r);
687 VarCount[Attr.DescrSet] += Res.ArraySize;
688 }
689
690 if (VarCount[1] == 0)
691 --NumSets;
692
693 VERIFY_EXPR(NumSets > 0 && VarCount[0] > 0);
405694
406695 // This call only initializes descriptor sets (ShaderResourceCacheVk::DescriptorSet) in the resource cache
407696 // Resources are initialized by source layout when shader resource binding objects are created
408 ResourceCache.InitializeSets(CacheMemAllocator, static_cast<Uint32>(VarCount.size()), VarCount.data());
697 ResourceCache.InitializeSets(CacheMemAllocator, NumSets, VarCount.data());
409698
410699 if (auto VkLayout = GetStaticVkDescriptorSetLayout())
411700 {
416705 DescrSetName = _DescrSetName.c_str();
417706 #endif
418707 DescriptorSetAllocation SetAllocation = GetDevice()->AllocateDescriptorSet(~Uint64{0}, VkLayout, DescrSetName);
419 ResourceCache.GetDescriptorSet(0).AssignDescriptorSetAllocation(std::move(SetAllocation));
708 ResourceCache.GetDescriptorSet(GetStaticDescrSetIndex()).AssignDescriptorSetAllocation(std::move(SetAllocation));
420709 }
421710 }
422711
425714 SHADER_TYPE Stages = m_ShaderStages;
426715 for (Uint32 Index = 0; Stages != SHADER_TYPE_UNKNOWN; ++Index)
427716 {
428 auto StageBit = static_cast<SHADER_TYPE>(1 << PlatformMisc::GetLSB(Uint32{Stages}));
429 Stages = Stages & ~StageBit;
717 auto StageBit = ExtractBit(Stages);
430718
431719 if (Index == StageIndex)
432720 return StageBit;
436724 return SHADER_TYPE_UNKNOWN;
437725 }
438726
727 Uint32 PipelineResourceSignatureVkImpl::GetNumDescriptorSets() const
728 {
729 return Uint32{m_VkDescSetLayouts[0] != VK_NULL_HANDLE} + Uint32{m_VkDescSetLayouts[1] != VK_NULL_HANDLE};
730 }
731
439732 void PipelineResourceSignatureVkImpl::InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache) const
440733 {
441734 auto TotalResources = GetTotalResourceCount();
442735 for (Uint32 r = 0; r < TotalResources; ++r)
443736 {
444737 const auto& Res = GetResource(r);
445 const auto& Bind = GetBinding(r);
446 ResourceCache.InitializeResources(Bind.DescSet, Bind.Binding, Res.ArraySize, GetVkDescriptorType(Res));
738 const auto& Attr = GetAttribs(r);
739 ResourceCache.InitializeResources(Attr.DescrSet, Attr.CacheOffset, Res.ArraySize, Attr.Type);
447740 }
448741 }
449742
450743 void PipelineResourceSignatureVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& DstResourceCache) const
451744 {
745 if (GetStaticVkDescriptorSetLayout() == VK_NULL_HANDLE || m_pResourceCache == nullptr)
746 return;
747
748 // SrcResourceCache contains only static resources.
749 // DstResourceCache contains static and mutable resources.
452750 const auto& SrcResourceCache = *m_pResourceCache;
453 (void)(SrcResourceCache);
454
455 for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
456 {
457 // AZ TODO
458 }
751 const auto& SrcDescrSet = SrcResourceCache.GetDescriptorSet(GetStaticDescrSetIndex());
752 auto& DstDescrSet = DstResourceCache.GetDescriptorSet(GetStaticDescrSetIndex());
753
754 // AZ TODO: optimize
755 for (Uint32 r = 0; r < GetTotalResourceCount(); ++r)
756 {
757 const auto& Res = GetResource(r);
758 const auto& Attr = GetAttribs(r);
759
760 if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && Attr.ImmutableSamplerAssigned)
761 continue; // Skip immutable separate samplers
762
763 if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
764 {
765 for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd)
766 {
767 auto CacheOffset = Attr.CacheOffset + ArrInd;
768 const auto& SrcCachedRes = SrcDescrSet.GetResource(CacheOffset);
769 IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr<IDeviceObject>();
770 if (!pObject)
771 LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetPrintName(Res, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'.");
772
773 IDeviceObject* pCachedResource = DstDescrSet.GetResource(CacheOffset).pObject;
774 if (pCachedResource != pObject)
775 {
776 VERIFY(pCachedResource == nullptr, "Static resource has already been initialized, and the resource to be assigned from the shader does not match previously assigned resource");
777 BindResource(pObject, ArrInd, r, DstResourceCache);
778 }
779 }
780 }
781 }
782
459783 #ifdef DILIGENT_DEBUG
460784 DstResourceCache.DbgVerifyDynamicBuffersCounter();
461785 #endif
462786 }
463787
788 Uint32 PipelineResourceSignatureVkImpl::GetStaticDescrSetIndex() const
789 {
790 return m_VkDescSetLayouts[0] != VK_NULL_HANDLE ? 0 : ~0u;
791 }
792
793 Uint32 PipelineResourceSignatureVkImpl::GetDynamicDescrSetIndex() const
794 {
795 return m_VkDescSetLayouts[1] != VK_NULL_HANDLE ? Uint32{m_VkDescSetLayouts[0] != VK_NULL_HANDLE} : ~0u;
796 }
797
798 void PipelineResourceSignatureVkImpl::CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache,
799 VkDescriptorSet vkDynamicDescriptorSet) const
800 {
801 VERIFY(HasDynamicDescrSet(), "This shader resource layout does not contain dynamic resources");
802 VERIFY_EXPR(vkDynamicDescriptorSet != VK_NULL_HANDLE);
803
804 #ifdef DILIGENT_DEBUG
805 static constexpr size_t ImgUpdateBatchSize = 4;
806 static constexpr size_t BuffUpdateBatchSize = 2;
807 static constexpr size_t TexelBuffUpdateBatchSize = 2;
808 static constexpr size_t AccelStructBatchSize = 2;
809 static constexpr size_t WriteDescriptorSetBatchSize = 2;
810 #else
811 static constexpr size_t ImgUpdateBatchSize = 128;
812 static constexpr size_t BuffUpdateBatchSize = 64;
813 static constexpr size_t TexelBuffUpdateBatchSize = 32;
814 static constexpr size_t AccelStructBatchSize = 32;
815 static constexpr size_t WriteDescriptorSetBatchSize = 32;
816 #endif
817
818 // Do not zero-initiaize arrays!
819 std::array<VkDescriptorImageInfo, ImgUpdateBatchSize> DescrImgInfoArr;
820 std::array<VkDescriptorBufferInfo, BuffUpdateBatchSize> DescrBuffInfoArr;
821 std::array<VkBufferView, TexelBuffUpdateBatchSize> DescrBuffViewArr;
822 std::array<VkWriteDescriptorSetAccelerationStructureKHR, AccelStructBatchSize> DescrAccelStructArr;
823 std::array<VkWriteDescriptorSet, WriteDescriptorSetBatchSize> WriteDescrSetArr;
824
825 auto DescrImgIt = DescrImgInfoArr.begin();
826 auto DescrBuffIt = DescrBuffInfoArr.begin();
827 auto BuffViewIt = DescrBuffViewArr.begin();
828 auto AccelStructIt = DescrAccelStructArr.begin();
829 auto WriteDescrSetIt = WriteDescrSetArr.begin();
830
831 const auto& SetResources = ResourceCache.GetDescriptorSet(GetDynamicDescrSetIndex());
832 const auto& LogicalDevice = GetDevice()->GetLogicalDevice();
833
834 // AZ TODO: optimize
835 for (Uint32 ResNum = 0, ArrElem = 0, Count = GetTotalResourceCount(); ResNum < Count;)
836 {
837 const auto& Res = GetResource(ResNum);
838 const auto& Attr = GetAttribs(ResNum);
839
840 if (Res.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
841 {
842 VERIFY_EXPR(ArrElem == 0);
843 ++ResNum;
844 continue;
845 }
846
847 WriteDescrSetIt->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
848 WriteDescrSetIt->pNext = nullptr;
849 VERIFY(SetResources.GetVkDescriptorSet() == VK_NULL_HANDLE, "Dynamic descriptor set must not be assigned to the resource cache");
850 WriteDescrSetIt->dstSet = vkDynamicDescriptorSet;
851 VERIFY(WriteDescrSetIt->dstSet != VK_NULL_HANDLE, "Vulkan descriptor set must not be null");
852 WriteDescrSetIt->dstBinding = Attr.BindingIndex;
853 WriteDescrSetIt->dstArrayElement = ArrElem;
854 // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding.
855 // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4)
856 WriteDescrSetIt->descriptorType = GetVkDescriptorType(Attr.Type);
857
858 // For every resource type, try to batch as many descriptor updates as we can
859 static_assert(static_cast<Uint32>(DescriptorType::Count) == 16, "Please update the switch below to handle the new descriptor type");
860 switch (Attr.Type)
861 {
862 case DescriptorType::UniformBuffer:
863 case DescriptorType::UniformBufferDynamic:
864 WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt);
865 while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
866 {
867 const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
868 *DescrBuffIt = CachedRes.GetUniformBufferDescriptorWriteInfo();
869 ++DescrBuffIt;
870 ++ArrElem;
871 }
872 break;
873
874 case DescriptorType::StorageBuffer:
875 case DescriptorType::StorageBufferDynamic:
876 case DescriptorType::StorageBuffer_ReadOnly:
877 case DescriptorType::StorageBufferDynamic_ReadOnly:
878 WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt);
879 while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
880 {
881 const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
882 *DescrBuffIt = CachedRes.GetStorageBufferDescriptorWriteInfo();
883 ++DescrBuffIt;
884 ++ArrElem;
885 }
886 break;
887
888 case DescriptorType::UniformTexelBuffer:
889 case DescriptorType::StorageTexelBuffer:
890 case DescriptorType::StorageTexelBuffer_ReadOnly:
891 WriteDescrSetIt->pTexelBufferView = &(*BuffViewIt);
892 while (ArrElem < Res.ArraySize && BuffViewIt != DescrBuffViewArr.end())
893 {
894 const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
895 *BuffViewIt = CachedRes.GetBufferViewWriteInfo();
896 ++BuffViewIt;
897 ++ArrElem;
898 }
899 break;
900
901 case DescriptorType::CombinedImageSampler:
902 case DescriptorType::SeparateImage:
903 case DescriptorType::StorageImage:
904 case DescriptorType::StorageImage_ReadOnly:
905 case DescriptorType::InputAttachment:
906 WriteDescrSetIt->pImageInfo = &(*DescrImgIt);
907 while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end())
908 {
909 const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
910 *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Attr.ImmutableSamplerAssigned);
911 ++DescrImgIt;
912 ++ArrElem;
913 }
914 break;
915
916 case DescriptorType::Sampler:
917 // Immutable samplers are permanently bound into the set layout; later binding a sampler
918 // into an immutable sampler slot in a descriptor set is not allowed (13.2.1)
919 if (!Attr.ImmutableSamplerAssigned)
920 {
921 WriteDescrSetIt->pImageInfo = &(*DescrImgIt);
922 while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end())
923 {
924 const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
925 *DescrImgIt = CachedRes.GetSamplerDescriptorWriteInfo();
926 ++DescrImgIt;
927 ++ArrElem;
928 }
929 }
930 else
931 {
932 ArrElem = Res.ArraySize;
933 WriteDescrSetIt->dstArrayElement = Res.ArraySize;
934 }
935 break;
936
937 case DescriptorType::AccelerationStructure:
938 WriteDescrSetIt->pNext = &(*AccelStructIt);
939 while (ArrElem < Res.ArraySize && AccelStructIt != DescrAccelStructArr.end())
940 {
941 const auto& CachedRes = SetResources.GetResource(Attr.CacheOffset + ArrElem);
942 *AccelStructIt = CachedRes.GetAccelerationStructureWriteInfo();
943 ++AccelStructIt;
944 ++ArrElem;
945 }
946 break;
947
948 default:
949 UNEXPECTED("Unexpected resource type");
950 }
951
952 WriteDescrSetIt->descriptorCount = ArrElem - WriteDescrSetIt->dstArrayElement;
953 if (ArrElem == Res.ArraySize)
954 {
955 ArrElem = 0;
956 ++ResNum;
957 }
958 // descriptorCount == 0 for immutable separate samplers
959 if (WriteDescrSetIt->descriptorCount > 0)
960 ++WriteDescrSetIt;
961
962 // If we ran out of space in any of the arrays or if we processed all resources,
963 // flush pending updates and reset iterators
964 if (DescrImgIt == DescrImgInfoArr.end() ||
965 DescrBuffIt == DescrBuffInfoArr.end() ||
966 BuffViewIt == DescrBuffViewArr.end() ||
967 AccelStructIt == DescrAccelStructArr.end() ||
968 WriteDescrSetIt == WriteDescrSetArr.end())
969 {
970 auto DescrWriteCount = static_cast<Uint32>(std::distance(WriteDescrSetArr.begin(), WriteDescrSetIt));
971 if (DescrWriteCount > 0)
972 LogicalDevice.UpdateDescriptorSets(DescrWriteCount, WriteDescrSetArr.data(), 0, nullptr);
973
974 DescrImgIt = DescrImgInfoArr.begin();
975 DescrBuffIt = DescrBuffInfoArr.begin();
976 BuffViewIt = DescrBuffViewArr.begin();
977 AccelStructIt = DescrAccelStructArr.begin();
978 WriteDescrSetIt = WriteDescrSetArr.begin();
979 }
980 }
981
982 auto DescrWriteCount = static_cast<Uint32>(std::distance(WriteDescrSetArr.begin(), WriteDescrSetIt));
983 if (DescrWriteCount > 0)
984 LogicalDevice.UpdateDescriptorSets(DescrWriteCount, WriteDescrSetArr.data(), 0, nullptr);
985 }
986
987 String PipelineResourceSignatureVkImpl::GetPrintName(const PipelineResourceDesc& ResDesc, Uint32 ArrayInd)
988 {
989 VERIFY_EXPR(ArrayInd < ResDesc.ArraySize);
990
991 if (ResDesc.ArraySize > 1)
992 {
993 std::stringstream ss;
994 ss << ResDesc.Name << '[' << ArrayInd << ']';
995 return ss.str();
996 }
997 else
998 return ResDesc.Name;
999 }
1000
1001 namespace
1002 {
1003 struct BindResourceHelper
1004 {
1005 <