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

Diligent Engine API Reference

D3DShaderResourceLoader.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
26 #include "Shader.h"
27 #include "StringTools.h"
28
31
32 namespace Diligent
33 {
34 template<typename D3D_SHADER_DESC,
35 typename D3D_SHADER_INPUT_BIND_DESC,
36 typename TShaderReflection,
37
38 typename TOnResourcesCounted,
39 typename TOnNewCB,
40 typename TOnNewTexUAV,
41 typename TOnNewBuffUAV,
42 typename TOnNewBuffSRV,
43 typename TOnNewSampler,
44 typename TOnNewTexSRV>
45 void LoadD3DShaderResources(ID3DBlob *pShaderByteCode,
46
47 TOnResourcesCounted OnResourcesCounted,
48 TOnNewCB OnNewCB,
49 TOnNewTexUAV OnNewTexUAV,
50 TOnNewBuffUAV OnNewBuffUAV,
51 TOnNewBuffSRV OnNewBuffSRV,
52 TOnNewSampler OnNewSampler,
53 TOnNewTexSRV OnNewTexSRV,
54
55 const ShaderDesc &ShdrDesc,
56 const Char *SamplerSuffix)
57 {
58 CComPtr<TShaderReflection> pShaderReflection;
59 CHECK_D3D_RESULT_THROW( D3DReflect( pShaderByteCode->GetBufferPointer(), pShaderByteCode->GetBufferSize(), __uuidof(pShaderReflection), reinterpret_cast<void**>(static_cast<TShaderReflection**>(&pShaderReflection)) ),
60 "Failed to get the shader reflection" );
61
62 D3D_SHADER_DESC shaderDesc = {};
63 pShaderReflection->GetDesc( &shaderDesc );
64
65 std::vector<D3DShaderResourceAttribs, STDAllocatorRawMem<D3DShaderResourceAttribs> > Resources( STD_ALLOCATOR_RAW_MEM(D3DShaderResourceAttribs, GetRawAllocator(), "Allocator for vector<D3DShaderResourceAttribs>") );
66 Resources.reserve(shaderDesc.BoundResources);
67
68 Uint32 NumCBs = 0, NumTexSRVs = 0, NumTexUAVs = 0, NumBufSRVs = 0, NumBufUAVs = 0, NumSamplers = 0;
69 // Number of resources to skip (used for array resources)
70 UINT SkipCount = 1;
71 for( UINT Res = 0; Res < shaderDesc.BoundResources; Res += SkipCount )
72 {
73 D3D_SHADER_INPUT_BIND_DESC BindingDesc = {};
74 pShaderReflection->GetResourceBindingDesc( Res, &BindingDesc );
75
76 String Name(BindingDesc.Name);
77
78 SkipCount = 1;
79
80 UINT BindCount = BindingDesc.BindCount;
81
82 // Handle arrays
83 // For shader models 5_0 and before, every resource array element is enumerated individually.
84 // For instance, if the following texture array is defined in the shader:
85 //
86 // Texture2D<float3> g_tex2DDiffuse[4];
87 //
88 // The reflection system will enumerate 4 resources with the following names:
89 // "g_tex2DDiffuse[0]"
90 // "g_tex2DDiffuse[1]"
91 // "g_tex2DDiffuse[2]"
92 // "g_tex2DDiffuse[3]"
93 //
94 // Notice that if some array element is not used by the shader, it will not be enumerated
95
96 auto OpenBracketPos = Name.find('[');
97 if (String::npos != OpenBracketPos)
98 {
99 VERIFY(BindCount == 1, "When array elements are enumerated individually, BindCount is expected to always be 1");
100
101 // Name == "g_tex2DDiffuse[0]"
102 // ^
103 // OpenBracketPos
104 Name.erase(OpenBracketPos, Name.length() - OpenBracketPos);
105 // Name == "g_tex2DDiffuse"
106 VERIFY_EXPR(Name.length() == OpenBracketPos);
107 #ifdef _DEBUG
108 for (const auto &ExistingRes : Resources)
109 {
110 VERIFY(ExistingRes.Name != Name, "Resource with the same name has already been enumerated. All array elements are expected to be enumerated one after another");
111 }
112 #endif
113 for( UINT ArrElem = Res+1; ArrElem < shaderDesc.BoundResources; ++ArrElem)
114 {
115 D3D_SHADER_INPUT_BIND_DESC ArrElemBindingDesc = {};
116 pShaderReflection->GetResourceBindingDesc( ArrElem, &ArrElemBindingDesc );
117
118 // Make sure this case is handled correctly:
119 // "g_tex2DDiffuse[.]" != "g_tex2DDiffuse2[.]"
120 if ( strncmp(Name.c_str(), ArrElemBindingDesc.Name, OpenBracketPos) == 0 && ArrElemBindingDesc.Name[OpenBracketPos] == '[')
121 {
122 //g_tex2DDiffuse[2]
123 // ^
124 UINT Ind = atoi(ArrElemBindingDesc.Name+OpenBracketPos+1);
125 BindCount = std::max(BindCount, Ind+1);
126 VERIFY(ArrElemBindingDesc.BindPoint == BindingDesc.BindPoint + Ind,
127 "Array elements are expected to use contigous bind points.\n",
128 BindingDesc.Name, " uses slot ", BindingDesc.BindPoint, ", so ", ArrElemBindingDesc.Name, " is expected to use slot ", BindingDesc.BindPoint + Ind, " while ", ArrElemBindingDesc.BindPoint, " is actually used" );
129
130 // Note that skip count may not necessarily be the same as BindCount.
131 // If some array elements are not used by the shader, the reflection system skips them
132 ++SkipCount;
133 }
134 else
135 {
136 break;
137 }
138 }
139 }
140
141
142 SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_NUM_TYPES;
143 bool IsStaticSampler = false;
144 if (BindingDesc.Type == D3D_SIT_SAMPLER)
145 {
146 for (Uint32 s = 0; s < ShdrDesc.NumStaticSamplers; ++s)
147 {
148 if( StrCmpSuff(Name.c_str(), ShdrDesc.StaticSamplers[s].TextureName, SamplerSuffix) )
149 {
150 IsStaticSampler = true;
151 break;
152 }
153 }
154 // Use texture name to derive sampler type
155 VarType = GetShaderVariableType(ShdrDesc.DefaultVariableType, ShdrDesc.VariableDesc, ShdrDesc.NumVariables,
156 [&](const char *TexName)
157 {
158 return StrCmpSuff(Name.c_str(), TexName, SamplerSuffix);
159 }
160 );
161 }
162 else
163 {
164 VarType = GetShaderVariableType(Name.c_str(), ShdrDesc.DefaultVariableType, ShdrDesc.VariableDesc, ShdrDesc.NumVariables);
165 }
166
167
168 switch( BindingDesc.Type )
169 {
170 case D3D_SIT_CBUFFER: ++NumCBs; break;
171 case D3D_SIT_TBUFFER: UNSUPPORTED( "TBuffers are not supported" ); break;
172 case D3D_SIT_TEXTURE: ++(BindingDesc.Dimension == D3D_SRV_DIMENSION_BUFFER ? NumBufSRVs : NumTexSRVs); break;
173 case D3D_SIT_SAMPLER: ++NumSamplers; break;
174 case D3D_SIT_UAV_RWTYPED: ++(BindingDesc.Dimension == D3D_SRV_DIMENSION_BUFFER ? NumBufUAVs : NumTexUAVs); break;
175 case D3D_SIT_STRUCTURED: ++NumBufSRVs; break;
176 case D3D_SIT_UAV_RWSTRUCTURED: ++NumBufUAVs; break;
177 case D3D_SIT_BYTEADDRESS: UNSUPPORTED( "Byte address buffers are not supported" ); break;
178 case D3D_SIT_UAV_RWBYTEADDRESS: ++NumBufUAVs; break;
179 case D3D_SIT_UAV_APPEND_STRUCTURED: UNSUPPORTED( "Append structured buffers are not supported" ); break;
180 case D3D_SIT_UAV_CONSUME_STRUCTURED: UNSUPPORTED( "Consume structured buffers are not supported" ); break;
181 case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: UNSUPPORTED( "RW structured buffers with counter are not supported" ); break;
182 default: UNEXPECTED("Unexpected resource type");
183 }
184 Resources.emplace_back(std::move(Name), BindingDesc.BindPoint, BindCount, BindingDesc.Type, VarType, BindingDesc.Dimension, D3DShaderResourceAttribs::InvalidSamplerId, IsStaticSampler);
185 }
186
187
188 #ifdef _DEBUG
189 if(ShdrDesc.NumVariables != 0 || ShdrDesc.NumStaticSamplers != 0 )
190 {
191 for (Uint32 v = 0; v < ShdrDesc.NumVariables; ++v)
192 {
193 bool VariableFound = false;
194 const auto *VarName = ShdrDesc.VariableDesc[v].Name;
195
196 for (const auto& Res : Resources)
197 {
198 // Skip samplers as they are not handled as independent variables
199 if (Res.GetInputType() != D3D_SIT_SAMPLER && Res.Name.compare(VarName) == 0)
200 {
201 VariableFound = true;
202 break;
203 }
204 }
205 if(!VariableFound)
206 {
207 LOG_WARNING_MESSAGE("Variable \"", VarName, "\" not found in shader \"", ShdrDesc.Name, '\"');
208 }
209 }
210
211 for (Uint32 s = 0; s < ShdrDesc.NumStaticSamplers; ++s)
212 {
213 bool TextureFound = false;
214 const auto *TexName = ShdrDesc.StaticSamplers[s].TextureName;
215
216 for (const auto& Res : Resources)
217 {
218 if ( Res.GetInputType() == D3D_SIT_TEXTURE && Res.GetSRVDimension() != D3D_SRV_DIMENSION_BUFFER && Res.Name.compare(TexName) == 0)
219 {
220 TextureFound = true;
221 break;
222 }
223 }
224 if(!TextureFound)
225 {
226 LOG_WARNING_MESSAGE("Static sampler specifies a texture \"", TexName, "\" that is not found in shader \"", ShdrDesc.Name, '\"');
227 }
228 }
229 }
230 #endif
231
232 OnResourcesCounted(NumCBs, NumTexSRVs, NumTexUAVs, NumBufSRVs, NumBufUAVs, NumSamplers);
233
234 std::vector<D3DShaderResourceAttribs, STDAllocatorRawMem<D3DShaderResourceAttribs> > TextureSRVs( STD_ALLOCATOR_RAW_MEM(D3DShaderResourceAttribs, GetRawAllocator(), "Allocator for vector<D3DShaderResourceAttribs>") );
235 TextureSRVs.reserve(NumTexSRVs);
236
237 for(auto &Res : Resources)
238 {
239 switch( Res.GetInputType() )
240 {
241 case D3D_SIT_CBUFFER:
242 {
243 OnNewCB( std::move(Res) );
244 break;
245 }
246
247 case D3D_SIT_TBUFFER:
248 {
249 UNSUPPORTED( "TBuffers are not supported" );
250 break;
251 }
252
253 case D3D_SIT_TEXTURE:
254 {
255 if( Res.GetSRVDimension() == D3D_SRV_DIMENSION_BUFFER )
256 {
257 OnNewBuffSRV( std::move(Res) );
258 }
259 else
260 {
261 TextureSRVs.emplace_back( std::move(Res) );
262 }
263 break;
264 }
265
266 case D3D_SIT_SAMPLER:
267 {
268 OnNewSampler( std::move(Res) );
269 break;
270 }
271
272 case D3D_SIT_UAV_RWTYPED:
273 {
274 if( Res.GetSRVDimension() == D3D_SRV_DIMENSION_BUFFER )
275 {
276 OnNewBuffUAV( std::move(Res) );
277 }
278 else
279 {
280 OnNewTexUAV( std::move(Res) );
281 }
282 break;
283 }
284
285 case D3D_SIT_STRUCTURED:
286 {
287 OnNewBuffSRV( std::move(Res) );
288 break;
289 }
290
291 case D3D_SIT_UAV_RWSTRUCTURED:
292 {
293 OnNewBuffUAV( std::move(Res) );
294 break;
295 }
296
297 case D3D_SIT_BYTEADDRESS:
298 {
299 UNSUPPORTED( "Byte address buffers are not supported" );
300 break;
301 }
302
303 case D3D_SIT_UAV_RWBYTEADDRESS:
304 {
305 OnNewBuffUAV( std::move(Res) );
306 break;
307 }
308
309 case D3D_SIT_UAV_APPEND_STRUCTURED:
310 {
311 UNSUPPORTED( "Append structured buffers are not supported" );
312 break;
313 }
314
315 case D3D_SIT_UAV_CONSUME_STRUCTURED:
316 {
317 UNSUPPORTED( "Consume structured buffers are not supported" );
318 break;
319 }
320
321 case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER:
322 {
323 UNSUPPORTED( "RW structured buffers with counter are not supported" );
324 break;
325 }
326 }
327 }
328
329 // Process texture SRVs. We need to do this after all samplers are initialized
330 for( auto &Tex : TextureSRVs )
331 {
332 OnNewTexSRV( std::move(Tex) );
333 }
334 }
335 }
Diligent
Graphics engine namespace.
Definition: AdaptiveFixedBlockAllocator.h:30
Diligent::GetRawAllocator
IMemoryAllocator & GetRawAllocator()
Returns raw memory allocator.
Definition: EngineMemory.cpp:46
Diligent::SHADER_VARIABLE_TYPE
SHADER_VARIABLE_TYPE
Describes shader variable type that is used by ShaderVariableDesc.
Definition: Shader.h:100
Diligent::String
std::basic_string< Char > String
String variable.
Definition: BasicTypes.h:51
Diligent::Uint32
uint32_t Uint32
32-bit unsigned integer
Definition: BasicTypes.h:39
Diligent::SHADER_VARIABLE_TYPE_NUM_TYPES
Total number of shader variable types.
Definition: Shader.h:117