Diligent Engine API Reference: D:/GitHub/DiligentEngine/DiligentCore/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.h Source File

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 }
Diligent::SHADER_TYPE
SHADER_TYPE
Describes the shader type.
Definition: Shader.h:46
Diligent
Namespace for the OpenGL implementation of the graphics engine.
Definition: BufferD3D11Impl.h:34
Diligent::SHADER_TYPE_UNKNOWN
Unknown shader type.
Definition: Shader.h:48