Diligent Core Documentation

repository·master·Indexed 20 days ago

https://github.com/diligentgraphics/diligentcore

A cross-platform, low-level graphics API providing a unified interface for modern rendering backends including Vulkan, Direct3D12, Direct3D11, WebGPU, and OpenGL/GLES. The library supports interoperability by allowing users to retrieve native API objects, wrap existing native resources into Diligent Engine objects, and attach the engine to existing device contexts.

Tokens
45K
Snippets
126
Records
177
Agent score
72%

What's inside Diligent Core

  1. Overview of Diligent Core

    master

    Diligent Core is a modern, cross-platform low-level graphics API that serves as the foundation for the Diligent Engine. It provides high-performance rendering backends for multiple APIs, allowing developers to write graphics code that works across various platforms and hardware.

    Supported Rendering Backends:

    • Direct3D11
    • Direct3D12
    • OpenGL
    • OpenGLES
    • Vulkan
    • WebGPU
    • Metal (available for commercial clients)

    Diligent Core is fully self-contained and can be built independently of the Diligent Engine.

  2. Manage explicit resource state transitions (v2.4+)

    master

    Starting from version 2.4, Diligent Core supports explicit resource state transitions to better leverage modern APIs like D3D12 and Vulkan.

    Key components:

    • RESOURCE_STATE enum: Defines the current state of a resource.
    • RESOURCE_STATE_TRANSITION_MODE enum: Controls how transitions are handled.
    • StateTransitionDesc structure: Describes a resource state transition barrier.
    • IDeviceContext::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers): The primary method to execute transitions.

    Resources (Buffers and Textures) can track their own state using IBuffer::SetState(), IBuffer::GetState(), ITexture::SetState(), and ITexture::GetState().

    // Example concept of state transition
    StateTransitionDesc barriers[1];
    barriers[0].pResource = pMyBuffer;
    barriers[0].NewState = RESOURCE_STATE_VERTEX_BUFFER;
    // ... set OldState and other members
    
    deviceContext->TransitionResourceStates(1, barriers);
  3. Manage Command Queues and Fences

    master

    In version 2.5, fence query methods (like GetNextFenceValue, GetCompletedFenceValue, and IsFenceSignaled) were moved from IRenderDeviceD3D12 and IRenderDeviceVk to the ICommandQueue interface.

    To manage synchronization, use the ICommandQueue interface. Additionally, IDeviceContext now provides LockCommandQueue and UnlockCommandQueue methods. For fence operations, IFence::Reset was renamed to IFence::Signal, and a new IFence::Wait method was added.

  4. How the HLSL to GLSL Converter works

    master
    The HLSL2GLSL Converter Lib allows developers to author shaders in HLSL (DirectX) and automatically convert them into GLSL (OpenGL) source code. This enables cross-platform shader development without maintaining two separate versions of every shader. The converter supports HLSL 5.0 and various shader types including vertex, geometry, pixel, domain, hull, and compute shaders.
  5. How shader resource binding works in Diligent Engine

    master

    Diligent Engine uses a three-tier grouping model for shader variables to optimize performance and resource management:

    1. Static Variables: Expected to be set only once (e.g., global constants like camera attributes). They are bound directly to the Pipeline State Object (PSO).
    2. Mutable Variables: Can be set once per instance of a Shader Resource Binding (SRB). They are bound via an IShaderResourceBinding object.
    3. Dynamic Variables: Can be set multiple times. These are more expensive and introduce runtime overhead. They are also bound via an IShaderResourceBinding object.

    Performance Tip: Use Static or Mutable variables whenever possible. Avoid Dynamic variables unless necessary to minimize runtime overhead.

    // Static binding (directly to PSO)
    m_pPSO->GetStaticShaderVariable(SHADER_TYPE_PIXEL, "g_tex2DShadowMap")->Set(pShadowMapSRV);
    
    // Mutable/Dynamic binding (via SRB)
    m_pSRB->GetVariable(SHADER_TYPE_PIXEL, "tex2DDiffuse")->Set(pDiffuseTexSRV);
  6. Configure combined samplers in Pipeline State

    master

    The behavior of combined samplers depends on whether you use default or explicit resource signatures when creating a PipelineState via PipelineStateCreateInfo.

    Using Default Resource Signatures

    If ppResourceSignatures is null, the decision to use combined samplers is driven by the UseCombinedTextureSamplers member in the ShaderCreateInfo of the shaders included in the pipeline.

    Important Constraints:

    • You can mix shaders that use combined samplers with those that don't. In this case, some texture+sampler pairs will be accessed as a single object, while others remain separate resources.
    • Suffix Consistency: If a shader defines a combined sampler suffix, it must match any other suffix used by other shaders in the same pipeline. Mixing shaders with different suffixes in one pipeline will result in an error.

    Using Explicit Resource Signatures

    If ppResourceSignatures is not null, the UseCombinedTextureSamplers values in ShaderCreateInfo are ignored. The resource binding behavior is strictly governed by the provided explicit resource signatures.

  7. Spatial vs Temporal Upscaling

    master

    When choosing an upscaling method, understand the difference in input requirements:

    Spatial Upscaling

    Operates on a single frame. It only requires the low-resolution color texture as input. It does not require motion vectors, depth buffers, or jitter patterns.

    Temporal Upscaling

    Accumulates information from multiple frames to reconstruct detail. In addition to the color texture, it requires:

    • Depth buffer: For reprojection and disocclusion detection.
    • Motion vectors: Per-pixel 2D motion in pixel space.
    • Jitter offset: A sub-pixel offset applied to the projection matrix each frame.

    Optional Temporal Inputs:

    • Exposure texture: A 1x1 texture with the exposure scale value in the R channel (ignored if SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE is set).
    • Reactive mask: A per-pixel value [0, 1] controlling temporal accumulation strength. Values near 1.0 reduce reliance on history (useful for particles or alpha-blended objects). It is recommended to clamp this to ~0.9.
    • Ignore history mask: A binary per-pixel mask where non-zero values force the upscaler to discard temporal history for that pixel (e.g., for newly revealed areas).
  8. How combined texture samplers work

    master

    Combined samplers merge a texture and a sampler into a single shader object. This is the native way to sample textures in OpenGL. Diligent Engine emulates this behavior in Direct3D11, Direct3D12, and Metal using texture + sampler pairs.

    Key Rules for Emulation:

    1. Naming: The sampler name is derived by appending a suffix (default is _sampler) to the texture name (e.g., g_Texture + _sampler = g_Texture_sampler).
    2. Binding: You cannot access the sampler directly via GetVariableByName. Instead, you must set the sampler inside the ITextureView and then bind that view to the texture variable.
    3. Requirement: Every combined sampler must be associated with a texture. An unassigned sampler is an error.
    // HLSL Emulated Combined Sampler
    Texture2D    g_Texture;
    SamplerState g_Texture_sampler;
    
    float4 Color = g_Texture.Sample(g_Texture_sampler, UV);
    // C++ Binding for Combined Samplers
    // Note: You bind the view to the texture variable, which carries the sampler
    pTexView->SetSampler(pSampler);
    
    // This sets both the texture and the emulated sampler
    pPSO->GetStaticVariableByName(SHADER_TYPE_PIXEL, "g_StaticTexture")->Set(pTexView);
  9. Optimize Shader Resource Variable types

    master

    Diligent Engine categorizes shader resource variables into three types. Choosing the correct type is critical for minimizing overhead during Shader Resource Binding (SRB) commits.

    • Static variables: Can be set only once per Pipeline State Object (PSO) or Pipeline Resource Signature. Once bound, they cannot be changed.
    • Mutable variables: Can be set only once per shader resource binding instance. Once bound, they cannot be changed.
    • Dynamic variables: Can be bound any number of times.

    Performance Tip: Static and mutable variables are implemented similarly and have lower overhead. Dynamic variables introduce overhead every time an SRB is committed. Prefer static or mutable variables whenever possible.

  10. Configure Pipeline Resource Layout

    master

    The Pipeline Resource Layout defines how shader resource variables are used and categorized by their update frequency. This allows the engine to optimize bindings.

    Variable Classifications

    • Static variables (SHADER_RESOURCE_VARIABLE_TYPE_STATIC): Expected to be set once (e.g., global camera or light constants). The binding must not change once set, though the resource content can.
    • Mutable variables (SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE): Expected to change per-material (e.g., diffuse textures).
    • Dynamic variables (SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC): Expected to change frequently and randomly.

    Immutable Samplers

    You can permanently assign immutable samplers to textures within the PSO. If an immutable sampler is assigned, it will always be used instead of the sampler initialized in the texture's shader resource view. It is highly recommended to use immutable samplers whenever possible. These can be assigned to any variable type, allowing the texture binding to change at runtime while the sampler remains fixed.

    To define these, populate PSODesc.ResourceLayout.Variables and PSODesc.ResourceLayout.ImmutableSamplers.

    // Define variable types
    ShaderResourceVariableDesc ShaderVars[] =
    {
        {SHADER_TYPE_PIXEL, "g_StaticTexture",  SHADER_RESOURCE_VARIABLE_TYPE_STATIC},
        {SHADER_TYPE_PIXEL, "g_MutableTexture", SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE},
        {SHADER_TYPE_PIXEL, "g_DynamicTexture", SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}
    };
    PSODesc.ResourceLayout.Variables           = ShaderVars;
    PSODesc.ResourceLayout.NumVariables        = _countof(ShaderVars);
    PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC;
    
    // Define immutable samplers
    ImmutableSamplerDesc ImtblSampler;
    ImtblSampler.ShaderStages   = SHADER_TYPE_PIXEL;
    ImtblSampler.Desc.MinFilter = FILTER_TYPE_LINEAR;
    ImtblSampler.Desc.MagFilter = FILTER_TYPE_LINEAR;
    ImtblSampler.Desc.MipFilter = FILTER_TYPE_LINEAR;
    ImtblSampler.TextureName    = "g_MutableTexture";
    PSODesc.ResourceLayout.NumImmutableSamplers = 1;
    PSODesc.ResourceLayout.ImmutableSamplers    = &ImtblSampler;
  11. Convert HLSL textures and samplers to GLSL

    master

    The converter maps HLSL texture dimensions and component types to GLSL sampler types. To distinguish between regular and shadow samplers, the converter looks for a sampler variable named <Texture Name>_sampler.

    Mapping Rules:

    • Texture2D $\rightarrow$ sampler2D (or sampler2DShadow if a comparison sampler is found)
    • TextureCube $\rightarrow$ samplerCube
    • Texture3D<uint4> $\rightarrow$ usampler3D
    • Texture2DArray<int2> $\rightarrow$ isampler2DArray

    Image Formats (RW Textures): For GLSL images (rw textures) that require a format specification, use a special comment inside the HLSL declaration.

    // Shadow sampler example
    Texture2D g_ShadowMap;
    SamplerComparisonState g_ShadowMap_sampler;
    
    // Regular sampler example
    Texture2D g_Tex2D;
    SamplerState g_Tex2D_sampler;
    
    // RW Texture with format specification
    RWTexture2D<float /* format=r32f */ > Tex2D;