Diligent Engine  v.2.4.g
ShaderResourceCacheVk.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2021 Diligent Graphics LLC
3  * Copyright 2015-2019 Egor Yusov
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * In no event and under no legal theory, whether in tort (including negligence),
18  * contract, or otherwise, unless required by applicable law (such as deliberate
19  * and grossly negligent acts) or agreed to in writing, shall any Contributor be
20  * liable for any damages, including any direct, indirect, special, incidental,
21  * or consequential damages of any character arising as a result of this License or
22  * out of the use or inability to use the software (including but not limited to damages
23  * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
24  * all other commercial damages or losses), even if such Contributor has been advised
25  * of the possibility of such damages.
26  */
27 
28 #pragma once
29 
32 
33 // Shader resource cache stores Vk resources in a continuous chunk of memory:
34 //
35 // |Vulkan Descriptor Set|
36 // A ___________________________________________________________
37 // m_pMemory | | m_pResources, m_NumResources == m |
38 // | m_DescriptorSetAllocation| | |
39 // V | | V
40 // | DescriptorSet[0] | .... | DescriptorSet[Ns-1] | Res[0] | ... | Res[n-1] | .... | Res[0] | ... | Res[m-1] |
41 // | | A \
42 // | | | \
43 // | |________________________________________________| \RefCntAutoPtr
44 // | m_pResources, m_NumResources == n \_________
45 // | | Object |
46 // | m_DescriptorSetAllocation ---------
47 // V
48 // |Vulkan Descriptor Set|
49 //
50 // Ns = m_NumSets
51 //
52 //
53 // Descriptor set for static and mutable resources is assigned during cache initialization
54 // Descriptor set for dynamic resources is assigned at every draw call
55 
56 #include <vector>
57 #include <memory>
58 
60 #include "SPIRVShaderResources.hpp"
61 #include "BufferVkImpl.hpp"
65 
66 namespace Diligent
67 {
68 
69 class DeviceContextVkImpl;
70 
71 // sizeof(ShaderResourceCacheVk) == 24 (x64, msvc, Release)
73 {
74 public:
75  explicit ShaderResourceCacheVk(ResourceCacheContentType ContentType) noexcept :
76  m_TotalResources{0},
77  m_ContentType{static_cast<Uint32>(ContentType)}
78  {
79  VERIFY_EXPR(GetContentType() == ContentType);
80  }
81 
82  // clang-format off
87  // clang-format on
88 
90 
91  static size_t GetRequiredMemorySize(Uint32 NumSets, const Uint32* SetSizes);
92 
93  void InitializeSets(IMemoryAllocator& MemAllocator, Uint32 NumSets, const Uint32* SetSizes);
94  void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type, bool HasImmutableSampler);
95 
96  // sizeof(Resource) == 16 (x64, msvc, Release)
97  struct Resource
98  {
99  explicit Resource(DescriptorType _Type, bool _HasImmutableSampler) noexcept :
100  Type{_Type},
101  HasImmutableSampler{_HasImmutableSampler}
102  {
104  "Immutable sampler can only be assigned to a combined image sampler or a separate sampler");
105  }
106 
107  // clang-format off
108  Resource (const Resource&) = delete;
109  Resource (Resource&&) = delete;
110  Resource& operator = (const Resource&) = delete;
111  Resource& operator = (Resource&&) = delete;
112 
113 /* 0 */ const DescriptorType Type;
114 /* 1 */ const bool HasImmutableSampler;
115 /*2-7*/ // Unused
117 
118  VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo() const;
119  VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo() const;
120  VkDescriptorImageInfo GetImageDescriptorWriteInfo () const;
121  VkBufferView GetBufferViewWriteInfo () const;
122  VkDescriptorImageInfo GetSamplerDescriptorWriteInfo() const;
123  VkDescriptorImageInfo GetInputAttachmentDescriptorWriteInfo() const;
124  VkWriteDescriptorSetAccelerationStructureKHR GetAccelerationStructureWriteInfo() const;
125  // clang-format on
126 
127  bool IsNull() const { return pObject == nullptr; }
128  };
129 
130  // sizeof(DescriptorSet) == 48 (x64, msvc, Release)
132  {
133  public:
134  // clang-format off
135  DescriptorSet(Uint32 NumResources, Resource *pResources) :
136  m_NumResources {NumResources},
137  m_pResources {pResources }
138  {}
139 
140  DescriptorSet (const DescriptorSet&) = delete;
141  DescriptorSet (DescriptorSet&&) = delete;
142  DescriptorSet& operator = (const DescriptorSet&) = delete;
144  // clang-format on
145 
146  const Resource& GetResource(Uint32 CacheOffset) const
147  {
148  VERIFY(CacheOffset < m_NumResources, "Offset ", CacheOffset, " is out of range");
149  return m_pResources[CacheOffset];
150  }
151 
152  Uint32 GetSize() const { return m_NumResources; }
153 
154  VkDescriptorSet GetVkDescriptorSet() const
155  {
156  return m_DescriptorSetAllocation.GetVkDescriptorSet();
157  }
158 
159  // clang-format off
160 /* 0 */ const Uint32 m_NumResources = 0;
161 
162  private:
163  friend ShaderResourceCacheVk;
164  Resource& GetResource(Uint32 CacheOffset)
165  {
166  VERIFY(CacheOffset < m_NumResources, "Offset ", CacheOffset, " is out of range");
167  return m_pResources[CacheOffset];
168  }
169 
170 /* 8 */ Resource* const m_pResources = nullptr;
171 /*16 */ DescriptorSetAllocation m_DescriptorSetAllocation;
172 /*48 */ // End of structure
173  // clang-format on
174  };
175 
177  {
178  VERIFY_EXPR(Index < m_NumSets);
179  return reinterpret_cast<const DescriptorSet*>(m_pMemory.get())[Index];
180  }
181 
183  {
184  auto& DescrSet = GetDescriptorSet(SetIndex);
185  VERIFY(DescrSet.GetSize() > 0, "Descriptor set is empty");
186  VERIFY(!DescrSet.m_DescriptorSetAllocation, "Descriptor set alloction has already been initialized");
187  DescrSet.m_DescriptorSetAllocation = std::move(Allocation);
188  }
189 
190  // Sets the resource at the given desriptor set index and offset
191  const Resource& SetResource(const VulkanUtilities::VulkanLogicalDevice* pLogicalDevice,
192  Uint32 SetIndex,
193  Uint32 Offset,
194  Uint32 BindingIndex,
195  Uint32 ArrayIndex,
196  RefCntAutoPtr<IDeviceObject>&& pObject);
197 
198  const Resource& ResetResource(Uint32 SetIndex,
199  Uint32 Offset)
200  {
201  return SetResource(nullptr, SetIndex, Offset, ~0u, ~0u, RefCntAutoPtr<IDeviceObject>{});
202  }
203 
204  Uint32 GetNumDescriptorSets() const { return m_NumSets; }
205  Uint32 GetNumDynamicBuffers() const { return m_NumDynamicBuffers; }
206 
207  ResourceCacheContentType GetContentType() const { return static_cast<ResourceCacheContentType>(m_ContentType); }
208 
209 #ifdef DILIGENT_DEBUG
210  // Only for debug purposes: indicates what types of resources are stored in the cache
211  void DbgVerifyResourceInitialization() const;
212  void DbgVerifyDynamicBuffersCounter() const;
213 #endif
214 
215  template <bool VerifyOnly>
216  void TransitionResources(DeviceContextVkImpl* pCtxVkImpl);
217 
218  __forceinline Uint32 GetDynamicBufferOffsets(Uint32 CtxId, DeviceContextVkImpl* pCtxVkImpl, std::vector<uint32_t>& Offsets) const;
219 
220 private:
221  Resource* GetFirstResourcePtr()
222  {
223  return reinterpret_cast<Resource*>(reinterpret_cast<DescriptorSet*>(m_pMemory.get()) + m_NumSets);
224  }
225  const Resource* GetFirstResourcePtr() const
226  {
227  return reinterpret_cast<const Resource*>(reinterpret_cast<const DescriptorSet*>(m_pMemory.get()) + m_NumSets);
228  }
229 
231  {
232  VERIFY_EXPR(Index < m_NumSets);
233  return reinterpret_cast<DescriptorSet*>(m_pMemory.get())[Index];
234  }
235 
236  std::unique_ptr<void, STDDeleter<void, IMemoryAllocator>> m_pMemory;
237 
238  Uint16 m_NumSets = 0;
239 
240  // Total actual number of dynamic buffers (that were created with USAGE_DYNAMIC) bound in the resource cache
241  // regardless of the variable type. Note this variable is not equal to dynamic offsets count, which is constant.
242  Uint16 m_NumDynamicBuffers = 0;
243  Uint32 m_TotalResources : 31;
244 
245  // Indicates what types of resources are stored in the cache
246  const Uint32 m_ContentType : 1;
247 
248 #ifdef DILIGENT_DEBUG
249  // Debug array that stores flags indicating if resources in the cache have been initialized
250  std::vector<std::vector<bool>> m_DbgInitializedResources;
251 #endif
252 };
253 
255  DeviceContextVkImpl* pCtxVkImpl,
256  std::vector<uint32_t>& Offsets) const
257 {
258  // If any of the sets being bound include dynamic uniform or storage buffers, then
259  // pDynamicOffsets includes one element for each array element in each dynamic descriptor
260  // type binding in each set. Values are taken from pDynamicOffsets in an order such that
261  // all entries for set N come before set N+1; within a set, entries are ordered by the binding
262  // numbers (unclear if this is SPIRV binding or VkDescriptorSetLayoutBinding number) in the
263  // descriptor set layouts; and within a binding array, elements are in order. (13.2.5)
264 
265  // In each descriptor set, all uniform buffers with dynamic offsets (DescriptorType::UniformBufferDynamic)
266  // for every shader stage come first, followed by all storage buffers with dynamic offsets
267  // (DescriptorType::StorageBufferDynamic and DescriptorType::StorageBufferDynamic_ReadOnly) for every shader stage,
268  // followed by all other resources.
269  Uint32 OffsetInd = 0;
270  for (Uint32 set = 0; set < m_NumSets; ++set)
271  {
272  const auto& DescrSet = GetDescriptorSet(set);
273  const auto SetSize = DescrSet.GetSize();
274 
275  Uint32 res = 0;
276  while (res < SetSize)
277  {
278  const auto& Res = DescrSet.GetResource(res);
279  if (Res.Type == DescriptorType::UniformBufferDynamic)
280  {
281  const auto* pBufferVk = Res.pObject.RawPtr<const BufferVkImpl>();
282  const auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
283  Offsets[OffsetInd++] = Offset;
284  ++res;
285  }
286  else
287  break;
288  }
289 
290  while (res < SetSize)
291  {
292  const auto& Res = DescrSet.GetResource(res);
293  if (Res.Type == DescriptorType::StorageBufferDynamic ||
295  {
296  const auto* pBufferVkView = Res.pObject.RawPtr<const BufferViewVkImpl>();
297  const auto* pBufferVk = pBufferVkView != nullptr ? pBufferVkView->GetBuffer<const BufferVkImpl>() : nullptr;
298  const auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
299  Offsets[OffsetInd++] = Offset;
300  ++res;
301  }
302  else
303  break;
304  }
305 
306 #ifdef DILIGENT_DEBUG
307  for (; res < SetSize; ++res)
308  {
309  const auto& Res = DescrSet.GetResource(res);
313  "All dynamic uniform and storage buffers are expected to go first in the beginning of each descriptor set");
314  }
315 #endif
316  }
317  return OffsetInd;
318 }
319 
320 } // namespace Diligent
Diligent::ResourceCacheContentType
ResourceCacheContentType
The type of the content that is stored in the shader resource cache.
Definition: ShaderResourceCacheCommon.hpp:39
Diligent::ShaderResourceCacheVk::Resource::GetSamplerDescriptorWriteInfo
VkDescriptorImageInfo GetSamplerDescriptorWriteInfo() const
Definition: ShaderResourceCacheVk.cpp:689
Diligent::ShaderResourceCacheVk::DescriptorSet::GetResource
const Resource & GetResource(Uint32 CacheOffset) const
Definition: ShaderResourceCacheVk.hpp:146
Diligent::ShaderResourceCacheVk::Resource
Definition: ShaderResourceCacheVk.hpp:97
VulkanLogicalDevice.hpp
ShaderResourceCacheCommon.hpp
Diligent::ShaderResourceCacheVk::Resource::Type
const DescriptorType Type
Definition: ShaderResourceCacheVk.hpp:113
Diligent::ShaderResourceCacheVk::Resource::GetImageDescriptorWriteInfo
VkDescriptorImageInfo GetImageDescriptorWriteInfo() const
Definition: ShaderResourceCacheVk.cpp:619
Diligent::ShaderResourceCacheVk::TransitionResources
void TransitionResources(DeviceContextVkImpl *pCtxVkImpl)
Definition: ShaderResourceCacheVk.cpp:340
Diligent::ShaderResourceCacheVk::InitializeSets
void InitializeSets(IMemoryAllocator &MemAllocator, Uint32 NumSets, const Uint32 *SetSizes)
Definition: ShaderResourceCacheVk.cpp:53
Diligent::ShaderResourceCacheVk::Resource::IsNull
bool IsNull() const
Definition: ShaderResourceCacheVk.hpp:127
Diligent::ShaderResourceCacheVk::ResetResource
const Resource & ResetResource(Uint32 SetIndex, Uint32 Offset)
Definition: ShaderResourceCacheVk.hpp:198
VulkanUtilities::VulkanLogicalDevice
Definition: VulkanLogicalDevice.hpp:88
Diligent::DescriptorType::StorageBufferDynamic_ReadOnly
@ StorageBufferDynamic_ReadOnly
Diligent::ShaderResourceCacheVk::Resource::Resource
Resource(DescriptorType _Type, bool _HasImmutableSampler) noexcept
Definition: ShaderResourceCacheVk.hpp:99
BufferVkImpl.hpp
Diligent::BufferVkImpl::GetDynamicOffset
Uint32 GetDynamicOffset(Uint32 CtxId, DeviceContextVkImpl *pCtx) const
Definition: BufferVkImpl.hpp:71
Diligent::ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo
VkBufferView GetBufferViewWriteInfo() const
Definition: ShaderResourceCacheVk.cpp:674
Diligent::ShaderResourceCacheVk::GetContentType
ResourceCacheContentType GetContentType() const
Definition: ShaderResourceCacheVk.hpp:207
Diligent::ShaderResourceCacheVk::DescriptorSet::GetSize
Uint32 GetSize() const
Definition: ShaderResourceCacheVk.hpp:152
Diligent::ShaderResourceCacheVk::Resource::GetInputAttachmentDescriptorWriteInfo
VkDescriptorImageInfo GetInputAttachmentDescriptorWriteInfo() const
Definition: ShaderResourceCacheVk.cpp:705
Diligent::ShaderResourceCacheVk::Resource::operator=
Resource & operator=(const Resource &)=delete
Diligent::ShaderResourceCacheVk
Definition: ShaderResourceCacheVk.hpp:72
Diligent::DescriptorType::UniformBufferDynamic
@ UniformBufferDynamic
Diligent::ShaderResourceCacheVk::~ShaderResourceCacheVk
~ShaderResourceCacheVk()
Definition: ShaderResourceCacheVk.cpp:165
Diligent::ShaderResourceCacheVk::GetDynamicBufferOffsets
__forceinline Uint32 GetDynamicBufferOffsets(Uint32 CtxId, DeviceContextVkImpl *pCtxVkImpl, std::vector< uint32_t > &Offsets) const
Definition: ShaderResourceCacheVk.hpp:254
Diligent::BufferViewBase::GetBuffer
virtual IBuffer * GetBuffer() const override final
Implementation of IBufferView::GetBuffer()
Definition: BufferViewBase.hpp:83
set
set(SOURCE src/AppleDebug.mm src/AppleFileSystem.cpp) add_library(Diligent-ApplePlatform $
Definition: CMakeLists.txt:20
Diligent::ShaderResourceCacheVk::Resource::GetAccelerationStructureWriteInfo
VkWriteDescriptorSetAccelerationStructureKHR GetAccelerationStructureWriteInfo() const
Definition: ShaderResourceCacheVk.cpp:721
Diligent::DescriptorSetAllocation
Definition: DescriptorPoolManager.hpp:50
Diligent::ShaderResourceCacheVk::Resource::HasImmutableSampler
const bool HasImmutableSampler
Definition: ShaderResourceCacheVk.hpp:114
VulkanUtilities::VulkanHandleTypeId::DescriptorSet
@ DescriptorSet
Diligent::RefCntAutoPtr
Template class that implements reference counting.
Definition: RefCntAutoPtr.hpp:73
Diligent::ShaderResourceCacheVk::DescriptorSet::DescriptorSet
DescriptorSet(Uint32 NumResources, Resource *pResources)
Definition: ShaderResourceCacheVk.hpp:135
Type
const D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type
Definition: PipelineStateD3D12Impl.cpp:69
Diligent::Uint32
uint32_t Uint32
32-bit unsigned integer
Definition: BasicTypes.h:51
Diligent::DescriptorType::StorageBufferDynamic
@ StorageBufferDynamic
Diligent::DeviceContextVkImpl
Device context implementation in Vulkan backend.
Definition: DeviceContextVkImpl.hpp:67
Diligent::ShaderResourceCacheVk::Resource::GetUniformBufferDescriptorWriteInfo
VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo() const
Definition: ShaderResourceCacheVk.cpp:548
Diligent::ShaderResourceCacheVk::DescriptorSet
Definition: ShaderResourceCacheVk.hpp:131
Diligent::DescriptorType
DescriptorType
Definition: PipelineResourceAttribsVk.hpp:42
Diligent::ShaderResourceCacheVk::Resource::GetStorageBufferDescriptorWriteInfo
VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo() const
Definition: ShaderResourceCacheVk.cpp:571
Diligent::DescriptorType::Sampler
@ Sampler
Diligent::ShaderResourceCacheVk::GetRequiredMemorySize
static size_t GetRequiredMemorySize(Uint32 NumSets, const Uint32 *SetSizes)
Definition: ShaderResourceCacheVk.cpp:44
Diligent::BufferVkImpl
Buffer object implementation in Vulkan backend.
Definition: BufferVkImpl.hpp:46
Diligent::Uint16
uint16_t Uint16
16-bit unsigned integer
Definition: BasicTypes.h:52
Diligent::ShaderResourceCacheVk::GetNumDescriptorSets
Uint32 GetNumDescriptorSets() const
Definition: ShaderResourceCacheVk.hpp:204
Diligent::ShaderResourceCacheVk::DescriptorSet::operator=
DescriptorSet & operator=(const DescriptorSet &)=delete
Diligent::ShaderResourceCacheVk::ShaderResourceCacheVk
ShaderResourceCacheVk(ResourceCacheContentType ContentType) noexcept
Definition: ShaderResourceCacheVk.hpp:75
VERIFY_EXPR
#define VERIFY_EXPR(...)
Definition: DebugUtilities.hpp:79
Diligent::ShaderResourceCacheVk::SetResource
const Resource & SetResource(const VulkanUtilities::VulkanLogicalDevice *pLogicalDevice, Uint32 SetIndex, Uint32 Offset, Uint32 BindingIndex, Uint32 ArrayIndex, RefCntAutoPtr< IDeviceObject > &&pObject)
Definition: ShaderResourceCacheVk.cpp:177
VERIFY
#define VERIFY(...)
Definition: DebugUtilities.hpp:76
Diligent::DescriptorType::CombinedImageSampler
@ CombinedImageSampler
Diligent::ShaderResourceCacheVk::AssignDescriptorSetAllocation
void AssignDescriptorSetAllocation(Uint32 SetIndex, DescriptorSetAllocation &&Allocation)
Definition: ShaderResourceCacheVk.hpp:182
SPIRVShaderResources.hpp
Diligent::DescriptorSetAllocation::GetVkDescriptorSet
VkDescriptorSet GetVkDescriptorSet() const
Definition: DescriptorPoolManager.hpp:112
Diligent::ShaderResourceCacheVk::DescriptorSet::GetVkDescriptorSet
VkDescriptorSet GetVkDescriptorSet() const
Definition: ShaderResourceCacheVk.hpp:154
DescriptorPoolManager.hpp
Diligent::ShaderResourceCacheVk::InitializeResources
void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type, bool HasImmutableSampler)
Definition: ShaderResourceCacheVk.cpp:103
Diligent::ShaderResourceCacheVk::Resource::pObject
RefCntAutoPtr< IDeviceObject > pObject
Definition: ShaderResourceCacheVk.hpp:116
Diligent::ShaderResourceCacheVk::operator=
ShaderResourceCacheVk & operator=(const ShaderResourceCacheVk &)=delete
Diligent::BufferViewVkImpl
Buffer view implementation in Vulkan backend.
Definition: BufferViewVkImpl.hpp:41
Diligent
The library uses Direct3D-style math:
Definition: AdvancedMath.hpp:37
Diligent::ShaderResourceCacheVk::GetDescriptorSet
const DescriptorSet & GetDescriptorSet(Uint32 Index) const
Definition: ShaderResourceCacheVk.hpp:176
PipelineResourceAttribsVk.hpp
Diligent::ShaderResourceCacheVk::DescriptorSet::m_NumResources
const Uint32 m_NumResources
Definition: ShaderResourceCacheVk.hpp:160
Diligent::ShaderResourceCacheVk::GetNumDynamicBuffers
Uint32 GetNumDynamicBuffers() const
Definition: ShaderResourceCacheVk.hpp:205