D3D12

This page provides an overview of the main classes constituting D3D12-based implementation of Diligent Engine.

The following articles give detailed description of the key system components:

Buffers and Buffer Views

  • BufferD3D12Impl – implementation of a buffer object ( IBuffer interface)
    • Buffers are created by the render device ( RenderDeviceD3D12Impl::CreateBuffer() method)
    • Buffers can be bound to the pipeline as a constant or uniform buffer (CBV), as a shader resource (SRV) or an unordered access view (UAV), or can be used as vertex or index buffers for draw commands
    • If USAGE_DYNAMIC flag is not specified, the object constructor allocates space in GPU memory by calling ID3D12Device::CreateCommittedResource method
    • If USAGE_DYNAMIC flag is specified, the GPU memory is allocated by the Map() method from the GPU ring buffer. Dynamic buffers must be mapped and unmapped within boundaries of a single frame
      • Buffer object maintains a vector of dynamic allocations, one for every device context
    • If the buffer can be bound as a uniform buffer ( BIND_UNIFORM_BUFFER flag is specified), the class initialized one-descriptor allocation ( m_CBVDescriptorAllocation member) for storing CBV descriptor
    • BufferD3D12Impl inherits D3D12ResourceBase class that provides D3D12 resource state tracking functionality
  • BufferViewD3D12Impl – implementation of a buffer resource view ( IBufferView interface)
    • Buffer views are created by the BufferD3D12Impl::CreateViewInternal() method
    • The class holds one-descriptor allocation ( m_DescriptorHandle member) in a CPU descriptor heap that contains the view descriptor (SRV or UAV; CBV descriptor is maintained by the buffer object)
      • The descriptor is allocated by the BufferD3D12Impl::CreateViewInternal() and initialized by BufferD3D12Impl::CreateSRV() or BufferD3D12Impl::CreateUAV() method

Textures and Texture Views

  • TextureD3D12Impl – implementation of a texture object ( ITexture interface)
    • Textures are created by the render device ( RenderDeviceD3D12Impl::CreateTexture() method)
    • Textures can be bound to the graphics pipeline as a shader resource (SRV), render target (RTV), depth-stencil (DSV) or unordered access view (UAV)
    • The class provides two constructors. The first one allocates space for a new texture object with the specified attributes by calling ID3D12Device::CreateCommittedResource method. The second one attaches to an existing texture represented by ID3D12Resource. The second constructor is used to manage back buffer from the swap chain
    • If MISC_TEXTURE_FLAG_GENERATE_MIPS is specified,  TextureD3D12Impl object initializes UAV for every subresource to facilitate mipmap generation ( m_SubresUAVs member)
    • TextureD3D12Impl inherits D3D12ResourceBase class that provides D3D12 resource state tracking functionality
  • TextureViewD3D12Impl  – implementation of a texture view ( ITextureView interface)
    • Texture views are created by TextureD3D12Impl::CreateViewInternal() method
    • The class holds one-descriptor allocation ( m_DescriptorHandle member) in a CPU descriptor heap that contains the view descriptor (SRV, RTV, DSV or UAV)
      • The descriptor is allocated by the TextureD3D12Impl::CreateViewInternal() and initialized by TextureD3D12Impl::CreateSRV(), TextureD3D12Impl::CreateRTV(), TextureD3D12Impl::CreateDSV(), or TextureD3D12Impl::CreateUAV() method

Samplers

  • SamplerD3D12Impl – implementation of a sampler object ( ISampler interface)
    • Samplers are created by the render device ( RenderDeviceD3D12Impl::CreateSampler() method)
    • Samplers can be set in a texture view if the view type is SRV
    • The class holds one-descriptor allocation ( m_Descriptor member) in a CPU descriptor heap that contains the sampler descriptor

Shaders

  • ShaderD3D12Impl – implementation of a shader object ( IShader interface)
    • Shaders are created by the render device ( RenderDeviceD3D12Impl::CreateShader() method)
    • Shaders are part of the Pipeline State
    • The object constructor performs the following operations:

Related articles:

Descriptor Heaps

Descriptor heap management system provides storage for descriptors representing resource views (SRV, RTV, DSV, UAV, and CBV) as well as samplers. When a new resource view is created, its descriptor is allocated in one of the four CPU-only descriptor heaps maintained by the render device. Device also maintains two shader-visible descriptor heaps, where descriptors are copied to be available for draw commands. The system consists of five main classes:

  • DescriptorHeapAllocation is a helper class that represents descriptor heap allocation, which is simply a range of descriptors
  • DescriptorHeapAllocationManager is the main workhorse class that manages allocations in D3D12 descriptor heap using variable-size GPU allocations manager
  • CPUDescriptorHeap implements CPU-only descriptor heap that is used as a storage of resource view descriptor handles
  • GPUDescriptorHeap implements shader-visible descriptor heap that holds descriptor handles used by the GPU commands
  • DynamicSuballocationsManager is responsible for allocating short-living dynamic descriptor handles used in the current frame only

Main article: Managing Descriptor Heaps

Shader Resource Management System

Shader resource management system consists of a number of components. Shader Resource Layout ( ShaderResourceLayoutD3D12 class) defines how shader registers are mapped to descriptors in descriptor tables. Shader Resource Cache ( ShaderResourceCacheD3D12 class) provides storage for resource references. Shader resource layouts and caches are used by the following system components:

  1. Every pipeline state object ( PipelineStateD3D12Impl class) maintains shader resource layout for every active shader stage
    • These resource layouts are not bound to a resource cache and are used as reference layouts for shader resource binding objects
  2. Every shader object ( ShaderD3D12Impl class) contains shader resource layout that facilitates management of static shader resources
    • The resource layout defines artificial layout and is bound to a resource cache that actually holds references to resources set by the application
  3. Every shader resource binding object ( ShaderResourceBindingD3D12Impl class) encompasses shader resource layout for every active shader stage in the parent pipeline state
    • Resource layouts are initialized by clonning reference layouts from the pipeline state object and are bound to the resource cache that holds references to resources bound by the application

Main articles:

Pipeline State and Root Signature

  • PipelineStateD3D12Impl – implementation of a pipeline state object ( IPipelineState interface)
    • PSOs are created by the render device ( RenderDeviceD3D12Impl::CreatePipelineState() method)
    • Pipeline state encapsulates almost all attributes of the GPU pipeline (all active shader stages, rasterizer state, blend state, depth-stencil state etc.)
    • PipelineStateD3D12Impl class maintains shader resource layout for every active shader stage that is initialized during the object construction
    • PipelineStateD3D12Impl class encapsulates Root Signature object that is initialized together with the resource layouts
    • Pipeline state objects contains two fixed-block allocators that are used to facilitate memory management for internal shader resource layout and shader resource cache structures. If PipelineStateDesc::SRBAllocationGranularity member of the pipeline initialization structure is set to value other than 1, then the allocators are used and the value defines the allocator block size. If default value is left unchanged, then standard raw allocator is used. Using special allocators improves locality of CPU memory access dramatically. Consider rendering a crowd of animated characters. All characters share the same geometry, but use different textures, so there will be one SRB object for every character. If special memory allocators are not used, then internal data of every SRB object (resource layout and shader cache structures) will be scattered around CPU memory. If, however, space for these structures is allocated through allocators, all data will be organized into continuous chunks of memory improving access pattern dramatically.
  • RootSignature is a helper class that encapsulates root signature and provides crucial functionality:
    • Allocating resource slots in root tables and root views during the shader resource layout initialization
    • Binding shader resources to the GPU pipeline

Related articles:

Render Device

  • RenderDeviceD3D12Impl – implementation of a render deivce ( IRenderDevice interface)
    • Render device is responsible for creating most of the engine objects: buffers ( RenderDeviceD3D12Impl::CreateBuffer() ), textures ( RenderDeviceD3D12Impl::CreateTexture() ), samplers ( RenderDeviceD3D12Impl::CreateSampler()), shaders ( RenderDeviceD3D12Impl::CreateShader()), pipeline states ( RenderDeviceD3D12Impl::CreatePipelineState())
    • Render device synchronizes access to the command queue (with m_CmdQueueMutex) and submits completed command lists for execution
    • Render device maintains four CPU-only descriptor heaps ( m_CPUDescriptorHeaps) that provide storage for resource view descriptors, and two GPU-visible descriptor heaps ( m_GPUDescriptorHeaps) that are used to make descriptors available to GPU commands
    • Render device maintains a GPU-memory ring buffer for uploading data to textures and buffers and providing space for dynamic buffers
    • Render device safely releases D3D12 resources by maintaining a release queue
    • Render device manages command lists used by the command contexts

Related articles:

Device Context

  • DeviceContextD3D12Impl – implementation of a device context ( IDeviceContext interface)
    • The class provides methods to configure different parts of the pipeline (set pipeline state, vertex and index buffers, blend factors, etc.)
    • The class implements draw and dispatch compute command implementations
    • The class tracks currently bound states to avoid redundant state changes
    • Device context maintains command list being recorded
    • Device context may be immediate, in which case it submits completed command lists directly for execution through render device ( RenderDeviceD3D12Impl::CloseAndExecuteCommandContext()), or deferred. Deferred contexts are intended to record command lists in parallel to the main thread. When commands are recorded, completed command list is retrieved from the context by FinishCommandList() method and can be executed from the immediate context by ExecuteCommandList().
  • CommandListD3D12Impl – implementation of a command list ( ICommandList interface)
    • Command list object is created when  FinishCommandList() method is called on a deferred context. Finished command list can be submitted for execution by the ExecuteCommandList() method.
    • CommandListD3D12Impl keeps pointer to the instance of CommandContext class that hold D3D12 command list object
  • CommandContext is a wrapper over D3D12 Command List object
    • Command contexts are managed by the render device. Render device contains command list manager ( CommandListManager class). Device context ( DeviceContextD3D12Impl class) requests a command context from the render device and starts recording commands. When command context is finished, it is returned to the command list manager, which makes it available to other device contexts as soon as GPU completes all commands from the context
    • Command contexts contain two dynamic suballocation managers ( DynamicSuballocationsManager class) that are responsible for allocating dynamic descriptors from SRV/CBV/UAV and Sampler shader-visible descriptor heaps
    • Command context accumulates resource barriers and executes them when draw or compute command is invoked
    • Command context keeps track of the bound root signatures and descriptor heaps