Diligent Engine API Reference
ShaderResourceCacheD3D12.h
1 /* Copyright 2015-2018 Egor Yusov
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
12  *
13  * In no event and under no legal theory, whether in tort (including negligence),
14  * contract, or otherwise, unless required by applicable law (such as deliberate
15  * and grossly negligent acts) or agreed to in writing, shall any Contributor be
16  * liable for any damages, including any direct, indirect, special, incidental,
17  * or consequential damages of any character arising as a result of this License or
18  * out of the use or inability to use the software (including but not limited to damages
19  * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
20  * all other commercial damages or losses), even if such Contributor has been advised
21  * of the possibility of such damages.
22  */
23 
24 #pragma once
25 
28 
29 // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache/
30 
31 // Shader resource cache stores D3D12 resources in a continuous chunk of memory:
32 //
33 //
34 // __________________________________________________________
35 // m_pMemory | m_pResources, m_NumResources |
36 // | | |
37 // V | V
38 // | RootTable[0] | .... | RootTable[Nrt-1] | Res[0] | ... | Res[n-1] | .... | Res[0] | ... | Res[m-1] |
39 // | A \
40 // | | \
41 // |________________________________________________| \RefCntAutoPtr
42 // m_pResources, m_NumResources \_________
43 // | Object |
44 // ---------
45 //
46 // Nrt = m_NumTables
47 //
48 //
49 // The cache is also assigned decriptor heap space to store shader visible descriptor handles (for non-dynamic resources).
50 //
51 //
52 // DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV
53 // | DescrptHndl[0] ... DescrptHndl[n-1] | DescrptHndl[0] ... DescrptHndl[m-1] |
54 // A A
55 // | |
56 // | TableStartOffset | TableStartOffset
57 // | |
58 // | RootTable[0] | RootTable[1] | RootTable[2] | .... | RootTable[Nrt] |
59 // | |
60 // | TableStartOffset | InvalidDescriptorOffset
61 // | |
62 // V V
63 // | DescrptHndl[0] ... DescrptHndl[n-1] | X
64 // DESCRIPTOR_HEAP_TYPE_SAMPLER
65 //
66 //
67 //
68 // The allocation is inexed by the offset from the beginning of the root table
69 // Each root table is assigned the space to store exactly m_NumResources resources
70 // Dynamic resources are not assigned space in the descriptor heap allocation.
71 //
72 //
73 //
74 // | RootTable[i] | Res[0] ... Res[n-1] |
75 // \
76 // TableStartOffset\____
77 // \
78 // V
79 // ..... | DescrptHndl[0] ... DescrptHndl[n-1] | ....
80 //
81 
82 #include "DescriptorHeap.h"
83 
84 namespace Diligent
85 {
86 
87 enum class CachedResourceType : Int32
88 {
89  Unknown = -1,
90  CBV = 0,
91  TexSRV,
92  BufSRV,
93  TexUAV,
94  BufUAV,
95  Sampler,
96  NumTypes
97 };
98 
99 class ShaderResourceCacheD3D12
100 {
101 public:
102  // This enum is used for debug purposes only
103  enum DbgCacheContentType
104  {
105  StaticShaderResources,
106  SRBResources
107  };
108 
109  ShaderResourceCacheD3D12(DbgCacheContentType dbgContentType)
110 #ifdef _DEBUG
111  : m_DbgContentType(dbgContentType)
112 #endif
113  {
114  }
115 
116  ~ShaderResourceCacheD3D12();
117 
118  void Initialize(IMemoryAllocator &MemAllocator, Uint32 NumTables, Uint32 TableSizes[]);
119 
120  static constexpr Uint32 InvalidDescriptorOffset = static_cast<Uint32>(-1);
121 
122  //http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Cache-Structure
123  struct Resource
124  {
125  CachedResourceType Type = CachedResourceType::Unknown;
126  // CPU descriptor handle of a cached resource in CPU-only descriptor heap
127  // Note that for dynamic resources, this is the only available CPU descriptor handle
128  D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = {0};
129  RefCntAutoPtr<IDeviceObject> pObject;
130  };
131 
132  class RootTable
133  {
134  public:
135  RootTable(Uint32 NumResources, Resource *pResources) :
136  m_NumResources(NumResources),
137  m_pResources(pResources)
138  {}
139 
140  inline Resource& GetResource(Uint32 OffsetFromTableStart,
141  const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType,
142  const SHADER_TYPE dbgRefShaderType)
143  {
144  VERIFY(m_dbgHeapType == dbgDescriptorHeapType, "Incosistent descriptor heap type" );
145  VERIFY(m_dbgShaderType == dbgRefShaderType, "Incosistent shader type" );
146 
147  VERIFY(OffsetFromTableStart < m_NumResources, "Root table at index is not large enough to store descriptor at offset ", OffsetFromTableStart );
148  return m_pResources[OffsetFromTableStart];
149  }
150 
151  inline Uint32 GetSize()const{return m_NumResources; }
152 
153  // Offset from the start of the descriptor heap allocation to the start of the table
154  Uint32 m_TableStartOffset = InvalidDescriptorOffset;
155 
156 #ifdef _DEBUG
157  void SetDebugAttribs(Uint32 MaxOffset,
158  const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType,
159  const SHADER_TYPE dbgRefShaderType)
160  {
161  VERIFY_EXPR(m_NumResources == MaxOffset);
162  m_dbgHeapType = dbgDescriptorHeapType;
163  m_dbgShaderType = dbgRefShaderType;
164  }
165 
166  D3D12_DESCRIPTOR_HEAP_TYPE DbgGetHeapType()const{return m_dbgHeapType;}
167 #endif
168 
169  const Uint32 m_NumResources = 0;
170  private:
171 
172 #ifdef _DEBUG
173  D3D12_DESCRIPTOR_HEAP_TYPE m_dbgHeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES;
174  SHADER_TYPE m_dbgShaderType = SHADER_TYPE_UNKNOWN;
175 #endif
176 
177  Resource* const m_pResources = nullptr;
178  };
179 
180  inline RootTable& GetRootTable(Uint32 RootIndex)
181  {
182  VERIFY_EXPR(RootIndex < m_NumTables);
183  return reinterpret_cast<RootTable*>(m_pMemory)[RootIndex];
184  }
185 
186  inline Uint32 GetNumRootTables()const{return m_NumTables; }
187 
188  void SetDescriptorHeapSpace(DescriptorHeapAllocation &&CbcSrvUavHeapSpace, DescriptorHeapAllocation &&SamplerHeapSpace)
189  {
190  VERIFY(m_SamplerHeapSpace.GetCpuHandle().ptr == 0 && m_CbvSrvUavHeapSpace.GetCpuHandle().ptr == 0, "Space has already been allocated in GPU descriptor heaps");
191 #ifdef _DEBUG
192  Uint32 NumSamplerDescriptors = 0, NumSrvCbvUavDescriptors = 0;
193  for (Uint32 rt = 0; rt < m_NumTables; ++rt)
194  {
195  auto &Tbl = GetRootTable(rt);
196  if(Tbl.m_TableStartOffset != InvalidDescriptorOffset)
197  {
198  if(Tbl.DbgGetHeapType() == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
199  {
200  VERIFY(Tbl.m_TableStartOffset == NumSrvCbvUavDescriptors, "Descriptor space allocation is not continuous");
201  NumSrvCbvUavDescriptors = std::max(NumSrvCbvUavDescriptors, Tbl.m_TableStartOffset + Tbl.GetSize());
202  }
203  else
204  {
205  VERIFY(Tbl.m_TableStartOffset == NumSamplerDescriptors, "Descriptor space allocation is not continuous");
206  NumSamplerDescriptors = std::max(NumSamplerDescriptors, Tbl.m_TableStartOffset + Tbl.GetSize());
207  }
208  }
209  }
210  VERIFY(NumSrvCbvUavDescriptors == CbcSrvUavHeapSpace.GetNumHandles() || NumSrvCbvUavDescriptors == 0 && CbcSrvUavHeapSpace.GetCpuHandle(0).ptr == 0, "Unexpected descriptor heap allocation size" );
211  VERIFY(NumSamplerDescriptors == SamplerHeapSpace.GetNumHandles() || NumSamplerDescriptors == 0 && SamplerHeapSpace.GetCpuHandle(0).ptr == 0, "Unexpected descriptor heap allocation size" );
212 #endif
213 
214  m_CbvSrvUavHeapSpace = std::move(CbcSrvUavHeapSpace);
215  m_SamplerHeapSpace = std::move(SamplerHeapSpace);
216  }
217 
218  ID3D12DescriptorHeap* GetSrvCbvUavDescriptorHeap(){return m_CbvSrvUavHeapSpace.GetDescriptorHeap();}
219  ID3D12DescriptorHeap* GetSamplerDescriptorHeap() {return m_SamplerHeapSpace.GetDescriptorHeap();}
220 
221  // Returns CPU descriptor handle of a shader visible descriptor heap allocation
222  template<D3D12_DESCRIPTOR_HEAP_TYPE HeapType>
223  D3D12_CPU_DESCRIPTOR_HANDLE GetShaderVisibleTableCPUDescriptorHandle(Uint32 RootParamInd, Uint32 OffsetFromTableStart = 0)
224  {
225  auto &RootParam = GetRootTable(RootParamInd);
226  VERIFY(HeapType == RootParam.DbgGetHeapType(), "Invalid descriptor heap type");
227 
228  D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = {0};
229  // Descriptor heap allocation is not assigned for dynamic resources or
230  // in a special case when resource cache is used to store static
231  // variable assignments for a shader. It is also not assigned to root views
232  if( RootParam.m_TableStartOffset != InvalidDescriptorOffset )
233  {
234  VERIFY(RootParam.m_TableStartOffset + OffsetFromTableStart < RootParam.m_NumResources, "Offset is out of range");
235  if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER )
236  {
237  VERIFY_EXPR(!m_SamplerHeapSpace.IsNull());
238  CPUDescriptorHandle = m_SamplerHeapSpace.GetCpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart);
239  }
240  else if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV )
241  {
242  VERIFY_EXPR(!m_CbvSrvUavHeapSpace.IsNull());
243  CPUDescriptorHandle = m_CbvSrvUavHeapSpace.GetCpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart);
244  }
245  else
246  {
247  UNEXPECTED("Unexpected descriptor heap type");
248  }
249  }
250 
251  return CPUDescriptorHandle;
252  }
253 
254  // Returns GPU descriptor handle of a shader visible descriptor table
255  template<D3D12_DESCRIPTOR_HEAP_TYPE HeapType>
256  D3D12_GPU_DESCRIPTOR_HANDLE GetShaderVisibleTableGPUDescriptorHandle(Uint32 RootParamInd, Uint32 OffsetFromTableStart = 0)
257  {
258  auto &RootParam = GetRootTable(RootParamInd);
259  VERIFY(RootParam.m_TableStartOffset != InvalidDescriptorOffset, "GPU descriptor handle must never be requested for dynamic resources");
260  VERIFY(RootParam.m_TableStartOffset + OffsetFromTableStart < RootParam.m_NumResources, "Offset is out of range");
261 
262  D3D12_GPU_DESCRIPTOR_HANDLE GPUDescriptorHandle = {0};
263  VERIFY( HeapType == RootParam.DbgGetHeapType(), "Invalid descriptor heap type");
264  if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER )
265  {
266  VERIFY_EXPR(!m_SamplerHeapSpace.IsNull());
267  GPUDescriptorHandle = m_SamplerHeapSpace.GetGpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart);
268  }
269  else if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV )
270  {
271  VERIFY_EXPR(!m_CbvSrvUavHeapSpace.IsNull());
272  GPUDescriptorHandle = m_CbvSrvUavHeapSpace.GetGpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart);
273  }
274  else
275  {
276  UNEXPECTED("Unexpected descriptor heap type");
277  }
278 
279  return GPUDescriptorHandle;
280  }
281 
282 #ifdef _DEBUG
283  // Only for debug purposes: indicates what types of resources are stored in the cache
284  DbgCacheContentType DbgGetContentType()const{return m_DbgContentType;}
285 #endif
286 
287 private:
288  ShaderResourceCacheD3D12(const ShaderResourceCacheD3D12&) = delete;
289  ShaderResourceCacheD3D12(ShaderResourceCacheD3D12&&) = delete;
290  ShaderResourceCacheD3D12& operator = (const ShaderResourceCacheD3D12&) = delete;
291  ShaderResourceCacheD3D12& operator = (ShaderResourceCacheD3D12&&) = delete;
292 
293  // Allocation in a GPU-visible sampler descriptor heap
294  DescriptorHeapAllocation m_SamplerHeapSpace;
295 
296  // Allocation in a GPU-visible CBV/SRV/UAV descriptor heap
297  DescriptorHeapAllocation m_CbvSrvUavHeapSpace;
298 
299  IMemoryAllocator *m_pAllocator=nullptr;
300  void *m_pMemory = nullptr;
301  Uint32 m_NumTables = 0;
302 
303 #ifdef _DEBUG
304  // Only for debug purposes: indicates what types of resources are stored in the cache
305  const DbgCacheContentType m_DbgContentType;
306 #endif
307 };
308 
309 }
SHADER_TYPE
Describes the shader type.
Definition: Shader.h:46
Namespace for the OpenGL implementation of the graphics engine.
Definition: BufferD3D11Impl.h:34
Unknown shader type.
Definition: Shader.h:48