Diligent Engine  v.2.4.g
D3DShaderResourceLoader.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 
30 #include <string>
31 #include <vector>
32 #include <unordered_set>
33 
34 #include "Shader.h"
35 #include "StringTools.hpp"
36 
39 
40 namespace Diligent
41 {
42 
44 {
52 };
53 
54 template <typename D3D_SHADER_DESC,
55  typename D3D_SHADER_INPUT_BIND_DESC,
56 
57  typename TShaderReflection,
58  typename THandleShaderDesc,
59  typename TOnResourcesCounted,
60  typename TOnNewCB,
61  typename TOnNewTexUAV,
62  typename TOnNewBuffUAV,
63  typename TOnNewBuffSRV,
64  typename TOnNewSampler,
65  typename TOnNewTexSRV,
66  typename TOnNewAccelStruct>
67 void LoadD3DShaderResources(TShaderReflection* pShaderReflection,
68  THandleShaderDesc HandleShaderDesc,
69  TOnResourcesCounted OnResourcesCounted,
70  TOnNewCB OnNewCB,
71  TOnNewTexUAV OnNewTexUAV,
72  TOnNewBuffUAV OnNewBuffUAV,
73  TOnNewBuffSRV OnNewBuffSRV,
74  TOnNewSampler OnNewSampler,
75  TOnNewTexSRV OnNewTexSRV,
76  TOnNewAccelStruct OnNewAccelStruct)
77 {
78  D3D_SHADER_DESC shaderDesc = {};
79  pShaderReflection->GetDesc(&shaderDesc);
80 
81  HandleShaderDesc(shaderDesc);
82 
83  std::vector<D3DShaderResourceAttribs, STDAllocatorRawMem<D3DShaderResourceAttribs>> Resources(STD_ALLOCATOR_RAW_MEM(D3DShaderResourceAttribs, GetRawAllocator(), "Allocator for vector<D3DShaderResourceAttribs>"));
84  Resources.reserve(shaderDesc.BoundResources);
85  std::unordered_set<std::string> ResourceNamesTmpPool;
86 
88 
89  size_t ResourceNamesPoolSize = 0;
90  // Number of resources to skip (used for array resources)
91  UINT SkipCount = 1;
92  for (UINT Res = 0; Res < shaderDesc.BoundResources; Res += SkipCount)
93  {
94  D3D_SHADER_INPUT_BIND_DESC BindingDesc = {};
95  pShaderReflection->GetResourceBindingDesc(Res, &BindingDesc);
96 
97  if (BindingDesc.BindPoint == UINT32_MAX)
98  BindingDesc.BindPoint = D3DShaderResourceAttribs::InvalidBindPoint;
99 
100  std::string Name(BindingDesc.Name);
101 
102  SkipCount = 1;
103 
104  UINT BindCount = BindingDesc.BindCount;
105  if (BindCount == UINT_MAX)
106  {
107  // For some reason
108  // Texture2D g_Textures[]
109  // produces BindCount == 0, but
110  // ConstantBuffer<CBData> g_ConstantBuffers[]
111  // produces BindCount == UINT_MAX
112  BindCount = 0;
113  }
114 
115  // Handle arrays
116  // For shader models 5_0 and before, every resource array element is enumerated individually.
117  // For instance, if the following texture array is defined in the shader:
118  //
119  // Texture2D<float3> g_tex2DDiffuse[4];
120  //
121  // The reflection system will enumerate 4 resources with the following names:
122  // "g_tex2DDiffuse[0]"
123  // "g_tex2DDiffuse[1]"
124  // "g_tex2DDiffuse[2]"
125  // "g_tex2DDiffuse[3]"
126  //
127  // Notice that if some array element is not used by the shader, it will not be enumerated
128 
129  auto OpenBracketPos = Name.find('[');
130  if (String::npos != OpenBracketPos)
131  {
132  VERIFY(BindCount == 1, "When array elements are enumerated individually, BindCount is expected to always be 1");
133 
134  // Name == "g_tex2DDiffuse[0]"
135  // ^
136  // OpenBracketPos
137  Name.erase(OpenBracketPos, Name.length() - OpenBracketPos);
138  // Name == "g_tex2DDiffuse"
139  VERIFY_EXPR(Name.length() == OpenBracketPos);
140 #ifdef DILIGENT_DEBUG
141  for (const auto& ExistingRes : Resources)
142  {
143  VERIFY(Name.compare(ExistingRes.Name) != 0, "Resource with the same name has already been enumerated. All array elements are expected to be enumerated one after another");
144  }
145 #endif
146  for (UINT ArrElem = Res + 1; ArrElem < shaderDesc.BoundResources; ++ArrElem)
147  {
148  D3D_SHADER_INPUT_BIND_DESC ArrElemBindingDesc = {};
149  pShaderReflection->GetResourceBindingDesc(ArrElem, &ArrElemBindingDesc);
150 
151  // Make sure this case is handled correctly:
152  // "g_tex2DDiffuse[.]" != "g_tex2DDiffuse2[.]"
153  if (strncmp(Name.c_str(), ArrElemBindingDesc.Name, OpenBracketPos) == 0 && ArrElemBindingDesc.Name[OpenBracketPos] == '[')
154  {
155  //g_tex2DDiffuse[2]
156  // ^
157  UINT Ind = atoi(ArrElemBindingDesc.Name + OpenBracketPos + 1);
158  BindCount = std::max(BindCount, Ind + 1);
159  VERIFY(ArrElemBindingDesc.BindPoint == BindingDesc.BindPoint + Ind,
160  "Array elements are expected to use contigous bind points.\n",
161  BindingDesc.Name, " uses slot ", BindingDesc.BindPoint, ", so ", ArrElemBindingDesc.Name,
162  " is expected to use slot ", BindingDesc.BindPoint + Ind, " while ", ArrElemBindingDesc.BindPoint,
163  " is actually used");
164 
165  // Note that skip count may not necessarily be the same as BindCount.
166  // If some array elements are not used by the shader, the reflection system skips them
167  ++SkipCount;
168  }
169  else
170  {
171  break;
172  }
173  }
174  }
175 
176  switch (BindingDesc.Type)
177  {
178  // clang-format off
179  case D3D_SIT_CBUFFER: ++RC.NumCBs; break;
180  case D3D_SIT_TBUFFER: UNSUPPORTED( "TBuffers are not supported" ); break;
181  case D3D_SIT_TEXTURE: ++(BindingDesc.Dimension == D3D_SRV_DIMENSION_BUFFER ? RC.NumBufSRVs : RC.NumTexSRVs); break;
182  case D3D_SIT_SAMPLER: ++RC.NumSamplers; break;
183  case D3D_SIT_UAV_RWTYPED: ++(BindingDesc.Dimension == D3D_SRV_DIMENSION_BUFFER ? RC.NumBufUAVs : RC.NumTexUAVs); break;
184  case D3D_SIT_STRUCTURED: ++RC.NumBufSRVs; break;
185  case D3D_SIT_UAV_RWSTRUCTURED: ++RC.NumBufUAVs; break;
186  case D3D_SIT_BYTEADDRESS: ++RC.NumBufSRVs; break;
187  case D3D_SIT_UAV_RWBYTEADDRESS: ++RC.NumBufUAVs; break;
188  case D3D_SIT_UAV_APPEND_STRUCTURED: UNSUPPORTED( "Append structured buffers are not supported" ); break;
189  case D3D_SIT_UAV_CONSUME_STRUCTURED: UNSUPPORTED( "Consume structured buffers are not supported" ); break;
190  case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: UNSUPPORTED( "RW structured buffers with counter are not supported" ); break;
191  // clang-format on
192 
193 #pragma warning(push)
194 #pragma warning(disable : 4063)
195  // D3D_SIT_RTACCELERATIONSTRUCTURE enum value is missing in Win SDK 17763, so we emulate it as #define, which
196  // makes the compiler emit the following warning:
197  // warning C4063: case '12' is not a valid value for switch of enum '_D3D_SHADER_INPUT_TYPE'
199 #pragma warning(pop)
200 
201  default: UNEXPECTED("Unexpected resource type");
202  }
203  ResourceNamesPoolSize += Name.length() + 1;
204  auto it = ResourceNamesTmpPool.emplace(std::move(Name));
205  Resources.emplace_back(
206  it.first->c_str(),
207  BindingDesc.BindPoint,
208  BindCount,
209  BindingDesc.Type,
210  BindingDesc.Dimension,
212  }
213 
214  OnResourcesCounted(RC, ResourceNamesPoolSize);
215 
216  std::vector<size_t, STDAllocatorRawMem<size_t>> TexSRVInds(STD_ALLOCATOR_RAW_MEM(size_t, GetRawAllocator(), "Allocator for vector<size_t>"));
217  TexSRVInds.reserve(RC.NumTexSRVs);
218 
219  for (size_t ResInd = 0; ResInd < Resources.size(); ++ResInd)
220  {
221  const auto& Res = Resources[ResInd];
222  switch (Res.GetInputType())
223  {
224  case D3D_SIT_CBUFFER:
225  {
226  OnNewCB(Res);
227  break;
228  }
229 
230  case D3D_SIT_TBUFFER:
231  {
232  UNSUPPORTED("TBuffers are not supported");
233  break;
234  }
235 
236  case D3D_SIT_TEXTURE:
237  {
238  if (Res.GetSRVDimension() == D3D_SRV_DIMENSION_BUFFER)
239  {
240  OnNewBuffSRV(Res);
241  }
242  else
243  {
244  // Texture SRVs must be processed all samplers are initialized
245  TexSRVInds.push_back(ResInd);
246  }
247  break;
248  }
249 
250  case D3D_SIT_SAMPLER:
251  {
252  OnNewSampler(Res);
253  break;
254  }
255 
256  case D3D_SIT_UAV_RWTYPED:
257  {
258  if (Res.GetSRVDimension() == D3D_SRV_DIMENSION_BUFFER)
259  {
260  OnNewBuffUAV(Res);
261  }
262  else
263  {
264  OnNewTexUAV(Res);
265  }
266  break;
267  }
268 
269  case D3D_SIT_STRUCTURED:
270  {
271  OnNewBuffSRV(Res);
272  break;
273  }
274 
275  case D3D_SIT_UAV_RWSTRUCTURED:
276  {
277  OnNewBuffUAV(Res);
278  break;
279  }
280 
281  case D3D_SIT_BYTEADDRESS:
282  {
283  OnNewBuffSRV(Res);
284  break;
285  }
286 
287  case D3D_SIT_UAV_RWBYTEADDRESS:
288  {
289  OnNewBuffUAV(Res);
290  break;
291  }
292 
293  case D3D_SIT_UAV_APPEND_STRUCTURED:
294  {
295  UNSUPPORTED("Append structured buffers are not supported");
296  break;
297  }
298 
299  case D3D_SIT_UAV_CONSUME_STRUCTURED:
300  {
301  UNSUPPORTED("Consume structured buffers are not supported");
302  break;
303  }
304 
305  case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER:
306  {
307  UNSUPPORTED("RW structured buffers with counter are not supported");
308  break;
309  }
310 
311 #pragma warning(push)
312 #pragma warning(disable : 4063)
313  // D3D_SIT_RTACCELERATIONSTRUCTURE enum value is missing in Win SDK 17763, so we emulate it as #define, which
314  // makes the compiler emit the following warning:
315  // warning C4063: case '12' is not a valid value for switch of enum '_D3D_SHADER_INPUT_TYPE'
317 #pragma warning(pop)
318  {
319  OnNewAccelStruct(Res);
320  break;
321  }
322 
323  default:
324  {
325  UNEXPECTED("Unexpected resource input type");
326  }
327  }
328  }
329 
330  // Process texture SRVs. We need to do this after all samplers are initialized
331  for (auto TexSRVInd : TexSRVInds)
332  {
333  OnNewTexSRV(Resources[TexSRVInd]);
334  }
335 }
336 
337 } // namespace Diligent
Diligent::D3DShaderResourceCounters
Definition: D3DShaderResourceLoader.hpp:43
Diligent::LoadD3DShaderResources
void LoadD3DShaderResources(TShaderReflection *pShaderReflection, THandleShaderDesc HandleShaderDesc, TOnResourcesCounted OnResourcesCounted, TOnNewCB OnNewCB, TOnNewTexUAV OnNewTexUAV, TOnNewBuffUAV OnNewBuffUAV, TOnNewBuffSRV OnNewBuffSRV, TOnNewSampler OnNewSampler, TOnNewTexSRV OnNewTexSRV, TOnNewAccelStruct OnNewAccelStruct)
Definition: D3DShaderResourceLoader.hpp:67
Shader.h
Diligent::D3DShaderResourceCounters::NumSamplers
Uint32 NumSamplers
Definition: D3DShaderResourceLoader.hpp:50
Diligent::D3DShaderResourceCounters::NumAccelStructs
Uint32 NumAccelStructs
Definition: D3DShaderResourceLoader.hpp:51
UNEXPECTED
#define UNEXPECTED(...)
Definition: DebugUtilities.hpp:77
Diligent::D3DShaderResourceAttribs::InvalidBindPoint
static constexpr const Uint16 InvalidBindPoint
Definition: ShaderResources.hpp:117
UNSUPPORTED
#define UNSUPPORTED(...)
Definition: DebugUtilities.hpp:78
Diligent::GetRawAllocator
IMemoryAllocator & GetRawAllocator()
Returns raw memory allocator.
Definition: EngineMemory.cpp:51
D3D_SRV_DIMENSION_BUFFER
#define D3D_SRV_DIMENSION_BUFFER
Definition: D3D12TypeDefinitions.h:152
Diligent::D3DShaderResourceAttribs::InvalidSamplerId
static constexpr const Uint32 InvalidSamplerId
Definition: ShaderResources.hpp:114
Diligent::D3DShaderResourceCounters::NumBufUAVs
Uint32 NumBufUAVs
Definition: D3DShaderResourceLoader.hpp:49
Diligent::D3DShaderResourceCounters::NumTexUAVs
Uint32 NumTexUAVs
Definition: D3DShaderResourceLoader.hpp:47
Diligent::Uint32
uint32_t Uint32
32-bit unsigned integer
Definition: BasicTypes.h:51
Diligent::D3DShaderResourceCounters::NumBufSRVs
Uint32 NumBufSRVs
Definition: D3DShaderResourceLoader.hpp:48
StringTools.hpp
Diligent::D3DShaderResourceAttribs
Definition: ShaderResources.hpp:80
Diligent::D3DShaderResourceCounters::NumCBs
Uint32 NumCBs
Definition: D3DShaderResourceLoader.hpp:45
std::max
Diligent::Vector2< T > max(const Diligent::Vector2< T > &Left, const Diligent::Vector2< T > &Right)
Definition: BasicMath.hpp:2261
STD_ALLOCATOR_RAW_MEM
#define STD_ALLOCATOR_RAW_MEM(Type, Allocator, Description)
Definition: STDAllocator.hpp:179
VERIFY_EXPR
#define VERIFY_EXPR(...)
Definition: DebugUtilities.hpp:79
VERIFY
#define VERIFY(...)
Definition: DebugUtilities.hpp:76
Diligent::D3DShaderResourceCounters::NumTexSRVs
Uint32 NumTexSRVs
Definition: D3DShaderResourceLoader.hpp:46
BindCount
Uint32 BindCount
Definition: DXBCUtils.cpp:84
Diligent
The library uses Direct3D-style math:
Definition: AdvancedMath.hpp:37
D3D_SIT_RTACCELERATIONSTRUCTURE
#define D3D_SIT_RTACCELERATIONSTRUCTURE
Definition: ShaderResources.hpp:65