Diligent Graphics > Diligent Engine > Architecture > D3D11 > Shader Resource Layout
Shader Resource Layout
Shader resource binding system in D3D11-based implementation consists of two main components: shader resource layout ( ShaderResourceLayoutD3D11) and shader resource cache ( ShaderResourceCacheD3D11). Direct3D11 uses single-stage shader resource binding model, where textures, buffers and sampler are bound directly to shader registers. Mapping between shader resources and HLSL registers is already captured by ShaderResourcesD3D11 class, so shader resource layout does not define any new couplings. Instead, it is intended to provide connection between shader resources and shader resource cache. There are two scenarios in which shader resource layouts and caches are used in D3D11 implementation:
- Every shader object (
ShaderD3D11Impl) comprises an instance of shader resource layout to facilitate management of static shader resources
- The layout object is bound to the shader resource cache that provides storage for object references
Kamagra cialis on line Fizz tablets are effervescent tabs that rapidly dissolve in a glass of water. After the acceptence of contract of this bridge in cialis prescription prices 1979, it’s fine steel work began. The commander levitra augmentation of the blood vessel in the penile region is 1cm wide while those in the heart are 3cm wide. People frequently have their post find these guys levitra on line sales delivered to work.
- Every shader resource binding object (
ShaderResourceBindingD3D11Impl) contains shader resource cache and shader resource layout of every active shader stage
- Every resource layout object is connected to corresponding shader resource cache that provides storage for object references
Unlike in D3D12 implementation, shader resource layout is always coupled with shader resource cache in D3D11 implementation.
Shader Resource Layout Structure
Shader resource layout class defines a number of internal structures to facilitate resource management, which are all derived from the same base class ShaderVariableD3DBase<ShaderResourceLayoutD3D11>. ShaderVariableD3DBase is a template class that provides common base functionality for D3D11 and D3D12 implementations. It is defined as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
template<typename TShaderResourceLayout> struct ShaderVariableD3DBase : public IShaderVariable { ShaderVariableD3DBase(TShaderResourceLayout &ParentResLayout, const D3DShaderResourceAttribs &ResourcesAttribs) : m_ParentResLayout(ParentResLayout), Attribs(ResourcesAttribs) { } virtual IReferenceCounters* GetReferenceCounters()const override final { return m_ParentResLayout.GetOwner().GetReferenceCounters(); } virtual Atomics::Long AddRef()override final { return m_ParentResLayout.GetOwner().AddRef(); } virtual Atomics::Long Release()override final { return m_ParentResLayout.GetOwner().Release(); } void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface )override final { if( ppInterface == nullptr ) return; *ppInterface = nullptr; if( IID == IID_ShaderVariable || IID == IID_Unknown ) { *ppInterface = this; (*ppInterface)->AddRef(); } } const D3DShaderResourceAttribs &Attribs; protected: TShaderResourceLayout &m_ParentResLayout; }; |
The class keeps references to the D3DShaderResourceAttribs instance that stores attributes of this shader resource, as well as reference to the parent resource layout object ( ShaderResourceLayoutD3D11 in D3D11, and ShaderResourceLayoutD3D12 in D3D12). It also implements common functions of the IShaderVariable interface. Note that reference counting-related methods AddRef(), Release(), and GetReferenceCounters() delegate calls to the parent resource layout.
ShaderResourceLayoutD3D11 uses the following internal structures: ConstBuffBindInfo, TexAndSamplerBindInfo, TexUAVBindInfo, BuffUAVBindInfo, and BuffSRVBindInfo. This separation is governed by operations that may be essential to bind different types of resources. For instance, before a texture can be set as SRV, it may be necessary to unbind it from render target slot. On the other hand, before a buffer can be set as UAV, it may be necessary to unbind it from vertex buffer slot. At the same time, both texture and buffer SRV are set through the same D3D11 call (which is reflected in the structure of the shader resource cache described next).
To assure coherent access, the class allocates continuous chunk of memory and keeps its internal structures in the order just mentioned (all CBs first, then all texture and sampler objects, and so on). Except for TexAndSamplerBindInfo, the structures define no new members and are intended to provide specific implementations for IShaderVaraible::Set() and IShaderVaraible::SetArray() methods that bind object or object array to a shader resource variable. The only new member that TexAndSamplerBindInfo defines is the reference to the sampler assigned to this texture SRV.
Consider a shader that uses the following shader resources:
1 2 3 4 5 6 7 8 9 |
cbuffer cbBuff0; cbuffer cbBuff1; Texture2D g_Tex0; Texture2D g_Tex1[8]; SamplerState g_Tex0_sampler; RWTexture2D<float4> g_rwTex[4]; Buffer<float4> g_Buff[2]; |
When ShaderD3D11Impl object is created, its constructor parses compiled shader bytecode and initializes an instance of ShaderResourcesD3D11 class that populates D3DShaderResourceAttribs structures for every shader resource (see this page for more details). For the example above, the content of the ShaderResourcesD3D11 class will look like shown in the figure below:
When shader resource layout object is initialized, its internal structures will reference D3DShaderResourceAttribs instances in the ShaderResourcesD3D11. For the shader resources in the listing above, the shader resource layout structure will look like depicted in the following diagram:
Note that if texture SRV is not assigned a valid sampler (as in the case with texture g_Tex1 in the example above), then SamplerAttribs member references a static instance of D3DShaderResourceAttribs representing invalid sampler.
Shader Resource Layout Initialization
Shader resource layout initialization is performed by the ShaderResourceLayoutD3D11::Initialize() method. The method takes reference to the ShaderResourcesD3D11 class instance that contains list of shader resources, as well as the list of allowed variable types. When shader resource layout is initialized as part of the shader object to manage static variables, this list only allows static variables. In the other case if the layout is initialized as part of the SRB object, mutable and dynamic variables are allowed in the resource layout, but the cache is initialized to hold all resource types (static, mutable, and dynamic). Initialize() method takes the following steps:
- Counts number of resources of each type
- Allocates continuous chunk memory to hold all internal structures
- Iterates over resources and initializes internal structures
- Initializes shader resource cache if it is not yet initialized
- The cache will be initialized if it is part of the shade resource binding object and it will not be initialized if it is static shader resource cache comprised by the shader object
The source code of the function is given in the listing below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
void ShaderResourceLayoutD3D11::Initialize(const std::shared_ptr<const ShaderResourcesD3D11>& pSrcResources, const SHADER_VARIABLE_TYPE *VarTypes, Uint32 NumVarTypes, ShaderResourceCacheD3D11& ResourceCache, IMemoryAllocator& ResCacheDataAllocator, IMemoryAllocator& ResLayoutDataAllocator) { m_pResources = pSrcResources; m_pResourceCache = &ResourceCache; Uint32 AllowedTypeBits = GetAllowedTypeBits(VarTypes, NumVarTypes); // Count total number of resources of allowed types Uint32 NumCBs, NumTexSRVs, NumTexUAVs, NumBufSRVs, NumBufUAVs, NumSamplers; pSrcResources->CountResources(VarTypes, NumVarTypes, NumCBs, NumTexSRVs, NumTexUAVs, NumBufSRVs, NumBufUAVs, NumSamplers); // Initialize offsets m_TexAndSamplersOffset = 0 + static_cast<Uint16>( NumCBs * sizeof(ConstBuffBindInfo) ); m_TexUAVsOffset = m_TexAndSamplersOffset + static_cast<Uint16>( NumTexSRVs * sizeof(TexAndSamplerBindInfo) ); m_BuffUAVsOffset = m_TexUAVsOffset + static_cast<Uint16>( NumTexUAVs * sizeof(TexUAVBindInfo) ); m_BuffSRVsOffset = m_BuffUAVsOffset + static_cast<Uint16>( NumBufUAVs * sizeof(BuffUAVBindInfo) ); auto MemorySize = m_BuffSRVsOffset + NumBufSRVs * sizeof(BuffSRVBindInfo); // Allocate memory if( MemorySize ) { auto *pRawMem = ALLOCATE(ResLayoutDataAllocator, "Raw memory buffer for shader resource layout resources", MemorySize); m_ResourceBuffer.reset(pRawMem); } m_NumCBs = static_cast<Uint8>(NumCBs); m_NumTexSRVs = static_cast<Uint8>(NumTexSRVs); m_NumTexUAVs = static_cast<Uint8>(NumTexUAVs); m_NumBufSRVs = static_cast<Uint8>(NumBufSRVs); m_NumBufUAVs = static_cast<Uint8>(NumBufUAVs); // Current resource index for every resource type Uint32 cb = 0; Uint32 texSrv = 0; Uint32 texUav = 0; Uint32 bufSrv = 0; Uint32 bufUav = 0; Uint32 NumCBSlots = 0; Uint32 NumSRVSlots = 0; Uint32 NumSamplerSlots = 0; Uint32 NumUAVSlots = 0; pSrcResources->ProcessResources( VarTypes, NumVarTypes, [&](const D3DShaderResourceAttribs &CB) { // Initialize current CB in place, increment CB counter new (&GetCB(cb++)) ConstBuffBindInfo( CB, *this ); NumCBSlots = std::max(NumCBSlots, static_cast<Uint32>(CB.BindPoint + CB.BindCount)); }, [&](const D3DShaderResourceAttribs& TexSRV) { // Set reference to a special static instance representing invalid sampler // if no sampler is assigned to texture SRV const D3DShaderResourceAttribs& SamplerAttribs = TexSRV.IsValidSampler() ? pSrcResources->GetSampler(TexSRV.GetSamplerId()) : TexAndSamplerBindInfo::InvalidSamplerAttribs; // Initialize tex SRV in place, increment counter of tex SRVs new (&GetTexSRV(texSrv++)) TexAndSamplerBindInfo( TexSRV, SamplerAttribs, *this ); NumSRVSlots = std::max(NumSRVSlots, static_cast<Uint32>(TexSRV.BindPoint + TexSRV.BindCount)); if( SamplerAttribs.IsValidBindPoint() ) NumSamplerSlots = std::max(NumSamplerSlots, static_cast<Uint32>(SamplerAttribs.BindPoint + SamplerAttribs.BindCount)); }, [&](const D3DShaderResourceAttribs &TexUAV) { // Initialize tex UAV in place, increment counter of tex UAVs new (&GetTexUAV(texUav++)) TexUAVBindInfo( TexUAV, *this ); NumUAVSlots = std::max(NumUAVSlots, static_cast<Uint32>(TexUAV.BindPoint + TexUAV.BindCount)); }, [&](const D3DShaderResourceAttribs &BuffSRV) { // Initialize buff SRV in place, increment counter of buff SRVs new (&GetBufSRV(bufSrv++)) BuffSRVBindInfo( BuffSRV, *this ); NumSRVSlots = std::max(NumSRVSlots, static_cast<Uint32>(BuffSRV.BindPoint + BuffSRV.BindCount)); }, [&](const D3DShaderResourceAttribs &BuffUAV) { // Initialize buff UAV in place, increment counter of buff UAVs new (&GetBufUAV(bufUav++)) BuffUAVBindInfo( BuffUAV, *this ); NumUAVSlots = std::max(NumUAVSlots, static_cast<Uint32>(BuffUAV.BindPoint + BuffUAV.BindCount)); } ); if (!m_pResourceCache->IsInitialized()) { // NOTE that here we are using max bind points required to cache only the shader variables of allowed types! m_pResourceCache->Initialize(NumCBSlots, NumSRVSlots, NumSamplerSlots, NumUAVSlots, ResCacheDataAllocator); } } |
In the listing above, ProcessResources() is a template function that iterates over all resources in ShaderResources structure, and for every resource type calls specific handler provided as function argument. The function only processes resources whose types match one of the types passed into the function in VarTypes parameter. During initialization, Initialize() method computes total number of slots required for SRV, UAV, Constant Buffer, and Sampler registers that are used to initialize the resource cache. GetCB(), GetTexSRV(), GetTexUAV(), GetBufSRV(), and GetBufUAV() methods provide access to the corresponding shader resource layout objects. They use offsets initialized in the beginning of the method to access the raw memory. For example, GetTexSRV() method is defined as follows:
1 2 3 4 5 |
TexAndSamplerBindInfo& GetTexSRV(Uint32 t) { return reinterpret_cast<TexAndSamplerBindInfo*>( reinterpret_cast<Uint8*>( m_ResourceBuffer.get()) + m_TexAndSamplersOffset )[t]; } |
where m_ResourceBuffer is the pointer to the memory buffer. Notice that the method uses inplace new to create structures at the specified memory addresses as in the snippet below:
1 |
new (&GetCB(cb++)) ConstBuffBindInfo( CB, *this ); |
Resource initialized this way need to be explicitly destroyed when memory is released.
Read next: Shader Resource Cache.