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:

  1. 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
  2. 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:

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:

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:

D3D11ShaderResourcesA

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:

D3D11ResourceLayoutA

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:

  1. Counts number of resources of each type
  2. Allocates continuous chunk memory to hold all internal structures
  3. Iterates over resources and initializes internal structures
  4. 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:

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:

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:

Resource initialized this way need to be explicitly destroyed when memory is released.

 

Read next: Shader Resource Cache.