Committing Shader Resources to the GPU Pipeline

Before D3D11 draw or dispatch compute command can be invoked, all required resources bound to the Shader Resource Binding object and kept in its internal shader resource caches must be committed to the graphics pipeline. This is done explicitly by calling IDeviceContext::CommitShaderResources(IShaderResourceBinding *pShaderResourceBinding, Uint32 Flags)  API function. The function takes pointer to the SRB object whose resources are to be committed and flags indicating if resources need to be transitioned to correct states. In D3D11 implementation, transitioning an object to a correct state means unbinding it from certain pipeline stages. For instance, before a texture can be bound as a shader resource view, it must first be unbound from all render target slots.To facilitate resource state management, every buffer and texture object in D3D11 implementation tracks its current state. The state of a buffer object is described by  D3D11BufferState enum:

The states of a texture object is represented by  D3D11TextureState enum:

Some states can be combined. For instance, a buffer can be bound as shader resource and as constant buffer. However, shader resource state is incompatible with unordered access state.

To avoid redundant state changes,  DeviceContextD3D11Impl class keeps track of all D3D11 resources committed to different GPU pipeline stages. Specifically, it tracks the following states:

  • Constant buffers, for every shader stage
  • SRVs, for every shader stage
  • Samplers, for every shader stage
  • UAVs, for every shader stage
  • Vertex buffers, for every input slot
  • Index buffer
  • Input layout
  • Shader objects, for every shader stage
  • Primitive topology
  • Render targets

To transition resources and commit them to the GPU pipeline, D3D11 implementation uses a template function defined as follows:

The two template parameters define the mode in which the function should operate. The arguments are template rather than actual bool parameters for performance reasons. If all shader stages contain no resources or only static resources, pShaderResourceBinding argument may be null. In this case, the function uses internal SRB object. The first time SRB object is committed, the function copies all resource references from the shaders’ static resource caches into the caches of the SRB object. It then function goes through all active shader stages in the SRB object, and for every shader stage performs the following operations:

  • Obtains reference to the resource cache of the current active shader stage
  • Obtains pointers to the internal arrays containing resource data (refer to the section on shader cache for more details)
    • Recall that the cache maintains four arrays of internal structures that represent constant buffers ( CachedCB), SRVs ( CachedResource), Samplers ( CachedSampler), and UAVs ( CachedResource), as well as four arrays containing raw pointers to D3D11 objects ( ID3D11Buffer*, ID3D11ShaderResourceView*, ID3D11SamplerState*, and ID3D11UnorderedAccessView*)
    • All arrays are indexed by the bind point of the corresponding resource type
  • Transitions and commits Constant Buffers:
    • Iterates over all constant buffers in the cache, and for every buffer:
      • If TransitionResources is set to true:
        • If D3D11BufferState::ConstantBuffer flag is not set in the buffer’s state:
          • If D3D11BufferState::UnorderedAccess flag is set in the buffer’s state, unbinds the buffer from the UAV and clears the flag
          • Sets  D3D11BufferState::ConstantBuffer flag in the buffer’s state
      • If CommitResources is set to true:
        • Checks if the same D3D11 buffer is already bound to the same slot for this shader stage, and if it is not:
          • Updates array of new constant buffers to be bound to this shader stage
    • If CommitResources is set to true and there is at least one new buffer to be bound:
      • Binds all new constant buffers for this shader stage
  • Transitions and commits SRVs:
    • Iterates over all SRVs in the cache, and for every resource:
      • If TransitionResources is set to true:
        •  If this SRV is a texture SRV ( SRVRes.pTexture is not null):
          • If D3D11TextureState::ShaderResource flag is not set in the textures’s state:
            • Checks if any of D3D11TextureState::UnorderedAccess, D3D11TextureState::RenderTarget, or D3D11TextureState::DepthStencil flags is set in the texture’s state, unbinds the texture from the corresponding output slot and clears the flags
            • Sets the  D3D11TextureState::ShaderResource flag in the texture’s state
        • If this SRV is a buffer SRV ( SRVRes.pBuffer is not null):
          • If D3D11BufferState::ShaderResource flag is not set in the buffer’s state:
            • If D3D11BufferState::UnorderedAccess flag is set in the buffer’s state, unbinds the buffer from the UAV and clears the flag
            • Sets  D3D11BufferState::ShaderResource flag in the buffer’s state
      • If CommitResources is set to true:
        • Checks if the same D3D11 SRV is already bound to the same slot for this shader stage, and if it is not:
          • Updates array of new SRVs to be bound to this shader stage
    • If CommitResources is set to true and there is at least one new SRV to be bound:
      • Binds all new SRVs for this shader stage
  • Commits Samplers. If CommitResources is set to true:
    • Iterates over all samplers in the cache, and  for every sampler:
      • Checks if the same D3D11 sampler is already bound to the same slot for this shader stage, and if it is not:
        • Updates array of new samplers to be bound to this shader stage
      • If there is at least one new sampler to be bound:
        • Binds all new samplers for this shader stage
  • Transitions and commits UAVs:
    • Iterates over all UAVs in the cache, and for every resource:
      • If TransitionResources is set to true:
        •  If this UAV is a texture UAV ( UAVRes.pTexture is not null):
          • If D3D11TextureState::UnorderedAcces flag is not set in the textures’s state:
            • If D3D11TextureState::ShaderResource is set in the texture’s state, unbinds the texture from all input slots, and clears the flag
            • Sets  D3D11TextureState::UnorderedAcces flag in the texture’s state
        •  If this UAV is a buffer UAV ( UAVRes.pBuffer is not null):
          • If  D3D11BufferState::UnorderedAccess flag is not set in the buffer’s state:
            • Unbinds the buffer from any possible input (shader resource, index buffer, vertex buffer, constant buffer) and clears all input flags
          • Sets  D3D11BufferState::UnorderedAccess flag in the buffer’s state
      • If CommitResources is set to true:
        • Checks if the same D3D11 UAV is already bound to the same slot for this shader stage, and if it is not:
          • Updates array of new UAVs to be bound to this shader stage
    • If CommitResources is set to true and there is at least one new UAV to be bound:
      • Binds all new UAVs for this shader stage

TransitionAndCommitShaderResources() function implements three different modes: transitioning resources only ( IDeviceContext::TransitionShaderResources() API function), committing resource only ( IDeviceContext::CommitShaderResources()) or transitioning and committing resource at the same time ( IDeviceContext::CommitShaderResources() with COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag), as shown in the following listing:

For better performance, resource transitioning should be avoided when it is known that resources are already in correct states.

Draw and Dispatch Compute Commands

When draw command is invoked, DeviceContextD3D11Impl::Draw() is called which performs the following operations:

  • Compares committed D3D11 input layout with the one currently bound in D3D11 device context. If the layouts are not the same, sets the new layout
  • Commits vertex buffers
    • Iterates over all vertex buffer slots, and for every slot:
      • If D3D11BufferState::UnorderedAccess flag is set in the buffer’s state, unbinds the buffer from the UAV slots and clears the flag
      • Sets  D3D11BufferState::VertexBuffer flag
      • Checks if the same D3D11 buffer is already bound to the same slot, and if it is not, updates the array of buffers to be bound
    • If there is at least one new buffer to be bound, binds all new vertex buffers
  • For indexed draw command, commits index buffer
    • If D3D11BufferState::UnorderedAccess flag is set in the buffer’s state, unbinds the buffer from the UAV slots and clears the flag
    • Sets  D3D11BufferState::IndexBuffer flag
    • If the buffer does not match currently bound one, binds the buffer to the D3D11 device context
  • Compares primitive topology with the one set in D3D11 device context. If the topology is not the same, bind the new one
  • Runs the appropriate D3D11 draw command (draw[indexed][instanced][indirect])

Dispatch compute command does not perform any additional operations and simply calls dispatch command on the D3D11 device context.