Diligent Engine API Reference
ShaderResources.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 
29 
30 // ShaderResources class uses continuous chunk of memory to store all resources, as follows:
31 //
32 //
33 // m_MemoryBuffer m_TexSRVOffset m_TexUAVOffset m_BufSRVOffset m_BufUAVOffset m_SamplersOffset m_MemorySize
34 // | | | | | | |
35 // | CB[0] ... CB[Ncb-1] | TexSRV[0] ... TexSRV[Ntsrv-1] | TexUAV[0] ... TexUAV[Ntuav-1] | BufSRV[0] ... BufSRV[Nbsrv-1] | BufUAV[0] ... BufUAV[Nbuav-1] | Sam[0] ... Sam[Nsam-1] |
36 //
37 // Ncb - number of constant buffers
38 // Ntsrv - number of texture SRVs
39 // Ntuav - number of texture UAVs
40 // Nbsrv - number of buffer SRVs
41 // Nbuav - number of buffer UAVs
42 // Nsam - number of samplers
43 //
44 //
45 // If texture SRV is assigned a sampler, it is referenced through SamplerId:
46 //
47 // _________________________SamplerId_______________________
48 // | |
49 // | V
50 // | CBs | ... TexSRV[n] ... | TexUAVs | BufSRVs | BufUAVs | Sam[0] ... Sam[SamplerId] ... |
51 //
52 //
53 
54 #include <memory>
55 
56 #define NOMINMAX
57 #include <d3dcommon.h>
58 
59 #include "Shader.h"
60 #include "STDAllocator.h"
61 
62 namespace Diligent
63 {
64 
65 static const Char* D3DSamplerSuffix = "_sampler";
66 
67 inline bool IsAllowedType(SHADER_VARIABLE_TYPE VarType, Uint32 AllowedTypeBits)noexcept
68 {
69  return ((1 << VarType) & AllowedTypeBits) != 0;
70 }
71 
72 inline Uint32 GetAllowedTypeBits(const SHADER_VARIABLE_TYPE *AllowedVarTypes, Uint32 NumAllowedTypes)noexcept
73 {
74  if(AllowedVarTypes == nullptr)
75  return 0xFFFFFFFF;
76 
77  Uint32 AllowedTypeBits = 0;
78  for(Uint32 i=0; i < NumAllowedTypes; ++i)
79  AllowedTypeBits |= 1 << AllowedVarTypes[i];
80  return AllowedTypeBits;
81 }
82 
83 
84 struct D3DShaderResourceAttribs
85 {
86  D3DShaderResourceAttribs(String &&_Name,
87  UINT _BindPoint,
88  UINT _BindCount,
89  D3D_SHADER_INPUT_TYPE _InputType,
90  SHADER_VARIABLE_TYPE _VariableType,
91  D3D_SRV_DIMENSION SRVDimension,
92  Uint32 SamplerId,
93  bool _IsStaticSampler) :
94  Name(std::move(_Name)),
95  BindPoint(static_cast<Uint16>(_BindPoint)),
96  BindCount(static_cast<Uint16>(_BindCount)),
97  PackedAttribs( PackAttribs(_InputType, _VariableType, SRVDimension, SamplerId, _IsStaticSampler) )
98  {
99  VERIFY( static_cast<Uint32>(_InputType) <= ShaderInputTypeMask, "Shader input type is out of expected range");
100  VERIFY( static_cast<Uint32>(_VariableType) <= VariableTypeMask, "Variable type is out of expected range");
101  VERIFY( static_cast<Uint32>(SRVDimension) <= SRVDimMask, "SRV dimensions is out of expected range");
102  VERIFY(SamplerId <= SamplerIdMask, "Sampler Id is out of allowed range" );
103  VERIFY_EXPR(GetInputType() == _InputType);
104  VERIFY_EXPR(GetVariableType() == _VariableType);
105  VERIFY(_BindPoint <= MaxBindPoint || _BindPoint == InvalidBindPoint, "Bind Point is out of allowed range" );
106  VERIFY(_BindCount <= MaxBindCount, "Bind Count is out of allowed range" );
107 #ifdef _DEBUG
108  if(_InputType==D3D_SIT_SAMPLER)
109  {
110  VERIFY_EXPR(IsStaticSampler() == _IsStaticSampler);
111  }
112  else
113  {
114  VERIFY(!_IsStaticSampler, "Only samplers can be marked as static");
115  }
116 
117  if (_InputType == D3D_SIT_TEXTURE)
118  {
119  VERIFY_EXPR(GetSamplerId() == SamplerId);
120  }
121  else
122  {
123  VERIFY(SamplerId == InvalidSamplerId, "Only textures can be assigned valid texture sampler");
124  }
125 
126  if(_IsStaticSampler)
127  {
128  VERIFY( _InputType == D3D_SIT_SAMPLER, "Invalid input type: D3D_SIT_SAMPLER is expected" );
129  }
130 #endif
131  }
132 
133  D3DShaderResourceAttribs(const D3DShaderResourceAttribs& rhs) = default;
134 
135  D3DShaderResourceAttribs(const D3DShaderResourceAttribs& rhs, Uint32 SamplerId)noexcept :
136  Name(rhs.Name),
137  BindPoint(rhs.BindPoint),
138  BindCount(rhs.BindCount),
139  PackedAttribs( PackAttribs(rhs.GetInputType(), rhs.GetVariableType(), rhs.GetSRVDimension(), SamplerId, false) )
140  {
141  VERIFY(GetInputType() == D3D_SIT_TEXTURE, "Only textures can be assigned a texture sampler");
142 
143  VERIFY_EXPR(GetInputType() == rhs.GetInputType());
144  VERIFY_EXPR(GetVariableType() == rhs.GetVariableType());
145  VERIFY_EXPR(GetSamplerId() == SamplerId);
146  }
147 
148  D3DShaderResourceAttribs(D3DShaderResourceAttribs&& rhs, Uint32 SamplerId)noexcept :
149  Name(std::move(rhs.Name)),
150  BindPoint(rhs.BindPoint),
151  BindCount(rhs.BindCount),
152  PackedAttribs( PackAttribs(rhs.GetInputType(), rhs.GetVariableType(), rhs.GetSRVDimension(), SamplerId, false) )
153  {
154  VERIFY(GetInputType() == D3D_SIT_TEXTURE, "Only textures can be assigned a texture sampler");
155 
156  VERIFY_EXPR(GetInputType() == rhs.GetInputType());
157  VERIFY_EXPR(GetVariableType() == rhs.GetVariableType());
158  VERIFY_EXPR(GetSamplerId() == SamplerId);
159  }
160 
161  D3DShaderResourceAttribs(D3DShaderResourceAttribs&& rhs)noexcept :
162  Name(std::move(rhs.Name)),
163  BindPoint(rhs.BindPoint),
164  BindCount(rhs.BindCount),
165  PackedAttribs( rhs.PackedAttribs )
166  {
167  }
168 
169  D3D_SHADER_INPUT_TYPE GetInputType()const
170  {
171  return static_cast<D3D_SHADER_INPUT_TYPE>( (PackedAttribs >> ShaderInputTypeBitOffset) & ShaderInputTypeMask );
172  }
173 
174  SHADER_VARIABLE_TYPE GetVariableType()const
175  {
176  return static_cast<SHADER_VARIABLE_TYPE>( (PackedAttribs >> VariableTypeBitOffset) & VariableTypeMask );
177  }
178 
179  D3D_SRV_DIMENSION GetSRVDimension()const
180  {
181  return static_cast<D3D_SRV_DIMENSION>( (PackedAttribs >> SRVDimBitOffset) & SRVDimMask );
182  }
183 
184  Uint32 GetSamplerId()const
185  {
186  VERIFY( GetInputType() == D3D_SIT_TEXTURE, "Invalid input type: D3D_SIT_TEXTURE is expected" );
187  return (PackedAttribs >> SamplerIdBitOffset) & SamplerIdMask;
188  }
189 
190  bool IsStaticSampler()const
191  {
192  VERIFY( GetInputType() == D3D_SIT_SAMPLER, "Invalid input type: D3D_SIT_SAMPLER is expected" );
193  return (PackedAttribs & (1 << IsStaticSamplerFlagBitOffset)) != 0;
194  }
195 
196  bool IsValidSampler()const
197  {
198  VERIFY( GetInputType() == D3D_SIT_TEXTURE, "Invalid input type: D3D_SIT_TEXTURE is expected" );
199  return GetSamplerId() != InvalidSamplerId;
200  }
201 
202  bool IsValidBindPoint()const
203  {
204  return BindPoint != InvalidBindPoint;
205  }
206 
207  static constexpr Uint16 InvalidBindPoint = std::numeric_limits<Uint16>::max();
208 
209  String Name; // Move ctor will not work if it is const
210  const Uint16 BindPoint;
211  const Uint16 BindCount;
212 
213  String GetPrintName(Uint32 ArrayInd)const
214  {
215  VERIFY_EXPR(ArrayInd < BindCount);
216  if(BindCount > 1)
217  return String(Name) + '[' + std::to_string(ArrayInd) + ']';
218  else
219  return Name;
220  }
221 private:
222  static constexpr Uint16 MaxBindPoint = InvalidBindPoint-1;
223  static constexpr Uint16 MaxBindCount = std::numeric_limits<Uint16>::max();
224 
225  static constexpr Uint32 ShaderInputTypeBits = 4; // Max value: D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER==11
226  static constexpr Uint32 ShaderInputTypeMask = (1 << ShaderInputTypeBits)-1;
227  static constexpr Uint32 ShaderInputTypeBitOffset = 0;
228  static_assert( D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER <= ShaderInputTypeMask, "Not enough bits to represent D3D_SHADER_INPUT_TYPE" );
229 
230  static constexpr Uint32 VariableTypeBits = 3; // Max value: SHADER_VARIABLE_TYPE_DYNAMIC == 2
231  static constexpr Uint32 VariableTypeMask = (1<<VariableTypeBits)-1;
232  static constexpr Uint32 VariableTypeBitOffset = ShaderInputTypeBitOffset + ShaderInputTypeBits;
233  static_assert( SHADER_VARIABLE_TYPE_NUM_TYPES-1 <= VariableTypeMask, "Not enough bits to represent SHADER_VARIABLE_TYPE" );
234 
235  static constexpr Uint32 SRVDimBits = 4; // Max value: D3D_SRV_DIMENSION_BUFFEREX == 11
236  static constexpr Uint32 SRVDimMask = (1<<SRVDimBits)-1;
237  static constexpr Uint32 SRVDimBitOffset = VariableTypeBitOffset + VariableTypeBits;
238  static_assert( D3D_SRV_DIMENSION_BUFFEREX <= SRVDimMask, "Not enough bits to represent D3D_SRV_DIMENSION" );
239 
240  static constexpr Uint32 SamplerIdBits = 32 - 1 - ShaderInputTypeBits - VariableTypeBits - SRVDimBits;
241  static constexpr Uint32 SamplerIdMask = (1 << SamplerIdBits) - 1;
242  static constexpr Uint32 SamplerIdBitOffset = SRVDimBitOffset + SRVDimBits;
243 public:
244  static constexpr Uint32 InvalidSamplerId = SamplerIdMask;
245 private:
246 
247  static constexpr Uint32 IsStaticSamplerFlagBits = 1;
248  static constexpr Uint32 IsStaticSamplerFlagMask = (1 << IsStaticSamplerFlagBits) - 1;
249  static constexpr Uint32 IsStaticSamplerFlagBitOffset = SamplerIdBitOffset + SamplerIdBits;
250  static_assert(IsStaticSamplerFlagBitOffset == 31, "Unexpected static sampler flag offset");
251 
252  static Uint32 PackAttribs(D3D_SHADER_INPUT_TYPE _InputType, SHADER_VARIABLE_TYPE _VariableType, D3D_SRV_DIMENSION SRVDimension, Uint32 SamplerId, bool _IsStaticSampler)
253  {
254  return ((static_cast<Uint32>(_InputType) & ShaderInputTypeMask) << ShaderInputTypeBitOffset) |
255  ((static_cast<Uint32>(_VariableType) & VariableTypeMask) << VariableTypeBitOffset ) |
256  ((static_cast<Uint32>(SRVDimension) & SRVDimMask) << SRVDimBitOffset) |
257  ((SamplerId & SamplerIdMask) << SamplerIdBitOffset) |
258  ((_IsStaticSampler ? 1 : 0) << IsStaticSamplerFlagBitOffset);
259  }
260 
261  // 4 3 4 20 1
262  // bit | 0 1 2 3 | 4 5 6 | 7 8 9 10 | 11 12 ... 30 | 31 |
263  // | | | | | |
264  // | InputType | VariableType | SRV Dim | SamplerId | StaticSamplerFlag |
265  const Uint32 PackedAttribs;
266 };
267 
268 
271 {
272 public:
273  ShaderResources(IMemoryAllocator &Allocator, SHADER_TYPE ShaderType);
274 
275  // Copies specified types of resources from another ShaderResources objects
276  // Only resources listed in AllowedVarTypes are copied
277  ShaderResources(IMemoryAllocator &Allocator,
278  const ShaderResources& SrcResources,
279  const SHADER_VARIABLE_TYPE *AllowedVarTypes,
280  Uint32 NumAllowedTypes);
281 
282  ShaderResources (const ShaderResources&) = delete;
283  ShaderResources (ShaderResources&&) = delete;
284  ShaderResources& operator = (const ShaderResources&) = delete;
285  ShaderResources& operator = (ShaderResources&&) = delete;
286 
287  ~ShaderResources();
288 
289  Uint32 GetNumCBs() const noexcept{ return (m_TexSRVOffset - 0); }
290  Uint32 GetNumTexSRV() const noexcept{ return (m_TexUAVOffset - m_TexSRVOffset); }
291  Uint32 GetNumTexUAV() const noexcept{ return (m_BufSRVOffset - m_TexUAVOffset); }
292  Uint32 GetNumBufSRV() const noexcept{ return (m_BufUAVOffset - m_BufSRVOffset); }
293  Uint32 GetNumBufUAV() const noexcept{ return (m_SamplersOffset - m_BufUAVOffset); }
294  Uint32 GetNumSamplers()const noexcept{ return (m_BufferEndOffset- m_SamplersOffset); }
295 
296  const D3DShaderResourceAttribs& GetCB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumCBs(), 0); }
297  const D3DShaderResourceAttribs& GetTexSRV (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumTexSRV(), m_TexSRVOffset); }
298  const D3DShaderResourceAttribs& GetTexUAV (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumTexUAV(), m_TexUAVOffset); }
299  const D3DShaderResourceAttribs& GetBufSRV (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumBufSRV(), m_BufSRVOffset); }
300  const D3DShaderResourceAttribs& GetBufUAV (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumBufUAV(), m_BufUAVOffset); }
301  const D3DShaderResourceAttribs& GetSampler(Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSamplers(), m_SamplersOffset); }
302 
303 
304  void CountResources(const SHADER_VARIABLE_TYPE *AllowedVarTypes, Uint32 NumAllowedTypes,
305  Uint32& NumCBs, Uint32& NumTexSRVs, Uint32& NumTexUAVs,
306  Uint32& NumBufSRVs, Uint32& NumBufUAVs, Uint32& NumSamplers)const noexcept;
307 
308  SHADER_TYPE GetShaderType()const noexcept{return m_ShaderType;}
309 
310  // Process only resources listed in AllowedVarTypes
311  template<typename THandleCB,
312  typename THandleTexSRV,
313  typename THandleTexUAV,
314  typename THandleBufSRV,
315  typename THandleBufUAV>
316  void ProcessResources(const SHADER_VARIABLE_TYPE *AllowedVarTypes,
317  Uint32 NumAllowedTypes,
318  THandleCB HandleCB,
319  THandleTexSRV HandleTexSRV,
320  THandleTexUAV HandleTexUAV,
321  THandleBufSRV HandleBufSRV,
322  THandleBufUAV HandleBufUAV)const
323  {
324  Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
325 
326  for(Uint32 n=0; n < GetNumCBs(); ++n)
327  {
328  const auto& CB = GetCB(n);
329  if( IsAllowedType(CB.GetVariableType(), AllowedTypeBits) )
330  HandleCB(CB);
331  }
332 
333  for(Uint32 n=0; n < GetNumTexSRV(); ++n)
334  {
335  const auto &TexSRV = GetTexSRV(n);
336  if( IsAllowedType(TexSRV.GetVariableType(), AllowedTypeBits) )
337  HandleTexSRV(TexSRV);
338  }
339 
340  for(Uint32 n=0; n < GetNumTexUAV(); ++n)
341  {
342  const auto &TexUAV = GetTexUAV(n);
343  if( IsAllowedType(TexUAV.GetVariableType(), AllowedTypeBits) )
344  HandleTexUAV(TexUAV);
345  }
346 
347  for(Uint32 n=0; n < GetNumBufSRV(); ++n)
348  {
349  const auto &BufSRV = GetBufSRV(n);
350  if( IsAllowedType(BufSRV.GetVariableType(), AllowedTypeBits) )
351  HandleBufSRV(BufSRV);
352  }
353 
354  for(Uint32 n=0; n < GetNumBufUAV(); ++n)
355  {
356  const auto& BufUAV = GetBufUAV(n);
357  if( IsAllowedType(BufUAV.GetVariableType(), AllowedTypeBits) )
358  HandleBufUAV(BufUAV);
359  }
360  }
361 
362 protected:
363  void Initialize(IMemoryAllocator &Allocator, Uint32 NumCBs, Uint32 NumTexSRVs, Uint32 NumTexUAVs, Uint32 NumBufSRVs, Uint32 NumBufUAVs, Uint32 NumSamplers);
364 
365  __forceinline D3DShaderResourceAttribs& GetResAttribs(Uint32 n, Uint32 NumResources, Uint32 Offset)noexcept
366  {
367  VERIFY(n < NumResources, "Resource index (", n, ") is out of range. Max allowed index: ", NumResources-1);
368  VERIFY_EXPR(Offset + n < m_BufferEndOffset);
369  return reinterpret_cast<D3DShaderResourceAttribs*>(m_MemoryBuffer.get())[Offset + n];
370  }
371 
372  __forceinline const D3DShaderResourceAttribs& GetResAttribs(Uint32 n, Uint32 NumResources, Uint32 Offset)const noexcept
373  {
374  VERIFY(n < NumResources, "Resource index (", n, ") is out of range. Max allowed index: ", NumResources-1);
375  VERIFY_EXPR(Offset + n < m_BufferEndOffset);
376  return reinterpret_cast<D3DShaderResourceAttribs*>(m_MemoryBuffer.get())[Offset + n];
377  }
378 
379  D3DShaderResourceAttribs& GetCB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumCBs(), 0); }
380  D3DShaderResourceAttribs& GetTexSRV (Uint32 n)noexcept{ return GetResAttribs(n, GetNumTexSRV(), m_TexSRVOffset); }
381  D3DShaderResourceAttribs& GetTexUAV (Uint32 n)noexcept{ return GetResAttribs(n, GetNumTexUAV(), m_TexUAVOffset); }
382  D3DShaderResourceAttribs& GetBufSRV (Uint32 n)noexcept{ return GetResAttribs(n, GetNumBufSRV(), m_BufSRVOffset); }
383  D3DShaderResourceAttribs& GetBufUAV (Uint32 n)noexcept{ return GetResAttribs(n, GetNumBufUAV(), m_BufUAVOffset); }
384  D3DShaderResourceAttribs& GetSampler(Uint32 n)noexcept{ return GetResAttribs(n, GetNumSamplers(), m_SamplersOffset); }
385 
386  Uint32 FindAssignedSamplerId(const D3DShaderResourceAttribs& TexSRV)const;
387 
388 private:
389  // Memory buffer that holds all resources as continuous chunk of memory:
390  // | CBs | TexSRVs | TexUAVs | BufSRVs | BufUAVs | Samplers |
391  std::unique_ptr< void, STDDeleterRawMem<void> > m_MemoryBuffer;
392 
393  // Offsets in elements of D3DShaderResourceAttribs
394  typedef Uint16 OffsetType;
395  OffsetType m_TexSRVOffset = 0;
396  OffsetType m_TexUAVOffset = 0;
397  OffsetType m_BufSRVOffset = 0;
398  OffsetType m_BufUAVOffset = 0;
399  OffsetType m_SamplersOffset = 0;
400  OffsetType m_BufferEndOffset = 0;
401 
402  SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN;
403 };
404 
405 }
SHADER_TYPE
Describes the shader type.
Definition: Shader.h:46
Graphics engine namespace.
Definition: AdaptiveFixedBlockAllocator.h:30
Definition: AdvancedMath.h:316
Diligent::ShaderResources class.
Definition: ShaderResources.h:270
Base interface for a raw memory allocator.
Definition: MemoryAllocator.h:35
SHADER_VARIABLE_TYPE
Describes shader variable type that is used by ShaderVariableDesc.
Definition: Shader.h:100
std::basic_string< Char > String
String variable.
Definition: BasicTypes.h:51
Unknown shader type.
Definition: Shader.h:48
uint16_t Uint16
16-bit unsigned integer
Definition: BasicTypes.h:40
uint32_t Uint32
32-bit unsigned integer
Definition: BasicTypes.h:39
Total number of shader variable types.
Definition: Shader.h:117