Skip to content

Latest commit

 

History

History
275 lines (192 loc) · 11.5 KB

README.md

File metadata and controls

275 lines (192 loc) · 11.5 KB

Ldx12 — DirectX 12

Ldx12

Prototype Direct3D 12 bindless renderers quickly with a modern, lightweight API and low overhead.

Ldx12 is a C++20 static library that removes repetitive Direct3D 12 setup while keeping rendering explicit. It follows modern design patterns through bindless resources, typed generational handles, reusable command buffers and GPU-safe deferred destruction.

Its philosophy is conceptually inspired by lightweightvk: a small, modern and bindless-oriented graphics API. Ldx12 applies that spirit to Direct3D 12 through an independent design and implementation.

It is intended for graphics experiments, tools and renderer prototypes—not as a full game engine.

Minimal setup

Initialize Ldx12 from an existing Win32 window (hwnd):

#include "Ldx12/Ldx12.hpp"

using namespace ldx12;

ContextDesc contextDesc{};

SwapchainDesc swapchainDesc{};
swapchainDesc.window = MakeWin32WindowHandle( hwnd );
swapchainDesc.width = 1280;
swapchainDesc.height = 720;
swapchainDesc.vsync = true;

DeviceManager& manager = DeviceManager::Initialize( contextDesc, swapchainDesc );
RenderDevice& device = *manager.GetRenderDevice();

With the triangle pipeline, render pass and framebuffer prepared, record and submit the draw:

CommandBuffer& commands = device.AcquireCommandBuffer();

commands.CmdBeginRendering( renderPass, framebuffer );
commands.CmdBindRenderPipeline( pipeline );
commands.CmdDraw( 3 );
commands.CmdEndRendering();

device.Submit( commands, backbuffer );

Highlights

  • Compact command recording and explicit submission.
  • Bindless CBV, SRV and UAV resource access.
  • Automatic resource-state transitions and command-list reuse.
  • Runtime HLSL compilation with Shader Model 6.6.
  • Typed resource handles instead of exposed ownership.
  • Optional access to native D3D12 objects when required.

Bindless: pass indices, not resource bindings

Before: binding resources

With conventional descriptor tables, selecting a texture and a buffer can look like this (illustrative native D3D12):

commandList->SetGraphicsRootDescriptorTable( 0, textureDescriptor );
commandList->SetGraphicsRootDescriptorTable( 1, bufferDescriptor );

The shader uses fixed registers matched by the root signature. Here the sampler is configured as a static sampler at s0:

Texture2D<float4> texture : register(t0);
StructuredBuffer<float4> colors : register(t1);
SamplerState linearClamp : register(s0);

float4 PSMain(float2 uv : TEXCOORD0) : SV_Target0
{
    return texture.Sample(linearClamp, uv) * colors[0];
}

After: bindless with Ldx12

With Ldx12, pass their indices instead. Here texture is an existing sampled texture and buffer is a structured buffer of float4 colors:

const uint32_t indices[] =
{
    device.GetBindlessIndex( texture ),
    device.GetBindlessIndex( buffer )
};

commands.CmdPushConstants( indices, sizeof( indices ) );

The shader reads both directly from the shared heap:

cbuffer Resources : register(b0) { uint textureIndex; uint bufferIndex; }

float4 PSMain(float2 uv : TEXCOORD0) : SV_Target0
{
    Texture2D<float4> texture = ResourceDescriptorHeap[textureIndex];

    StructuredBuffer<float4> colors = ResourceDescriptorHeap[bufferIndex];

    SamplerState linearClamp = SamplerDescriptorHeap[0]; // Built into Ldx12.

    return texture.Sample(linearClamp, uv) * colors[0];
}

Changing either resource means changing an index, not binding another resource table. Ldx12 configures the heaps and root signature for you. The snippets assume a prepared render pass, pipeline and resource states; bindless does not remove draws or synchronization.

Origin and license

Ldx12 began inside IFNITY and later became a standalone project.

Ldx12 is available under the MIT License. Third-party attribution is documented in THIRD_PARTY_NOTICES.md.

Bindless layout

Ldx12 bindless layout

Get started

Requirements: Windows 10/11, Visual Studio 2022 with Desktop development with C++, CMake 3.24+, the Windows SDK with DXC, and an x64 target.

NuGet

Ldx12 0.4.0 is available on NuGet.org:

Install-Package Ldx12 -Version 0.4.0

The package includes the public Ldx12 and Ldx12Utils headers and automatically selects their Debug or Release static libraries.

Build the repository

Run:

GenerateSolution.bat

Then open build\Ldx12.sln. It contains the library, tests and numbered samples, with 01_Triangle as the startup project.

CMake

include(FetchContent)
FetchContent_Declare(
    Ldx12
    GIT_REPOSITORY https://github.com/alfonsmagd/LightDX12.git
    GIT_TAG v0.4.0
)
FetchContent_MakeAvailable(Ldx12)

target_link_libraries(MyApplication PRIVATE Ldx12::Ldx12)

The snippet targets the v0.4.0 release tag. The NuGet command above installs the matching 0.4.0 package.

When used as a subproject, Ldx12 builds only the core library by default. Installation with find_package is demonstrated in examples/InstalledLdx12.

CMake options
Option Top-level As a subproject
LDX12_BUILD_APP ON OFF
LDX12_BUILD_EXAMPLES ON OFF
LDX12_BUILD_TESTS ON OFF
LDX12_BUILD_UTILS OFF OFF
LDX12_INSTALL ON OFF

Features

  • Win32 HWND swapchains with VSync and tearing configuration.
  • Color and depth rendering, viewport, scissor, vertex/index buffers, instancing and indirect indexed draws.
  • Typed handles for buffers, 2D/3D textures and swapchains.
  • Buffer and texture uploads, 2D texture downloads and mip generation.
  • Fixed or dynamic bindless descriptors and push constants.
  • Submission batches, fences, waits and deferred GPU-safe destruction.
  • Debug layer, GPU labels, optional PIX capture attachment and native D3D12 access.
  • Optional Ldx12::Utils renderer with indirectly batched cubes, spheres and colored arrows.

Normal rendering only requires Ldx12.hpp. Advanced integrations can include Ldx12Native.hpp and call GetNative() to obtain borrowed D3D12 objects.

Technical capacities

These are Ldx12 software capacities, not resources allocated immediately by the GPU.

Resource storage is a fixed contiguous array sized at compile time. Select one profile for both the library and its consumers:

Profile define Buffers + textures Shared CBV/SRV/UAV RTV DSV Tracked buffers/textures per command buffer
LDX12_SMALL_RESOURCES 256 256 16 4 16 per type
LDX12_MEDIUM_RESOURCES 1,024 1,024 32 8 64 per type
LDX12_HIGH_RESOURCES (default) 4,096 4,096 64 12 256 per type

With CMake, configure -DLDX12_RESOURCE_PROFILE=SMALL, MEDIUM or HIGH. The Ldx12::Ldx12 target propagates the selected define, including installed packages. For manual builds, use the same profile define in every library and application translation unit. Selecting more than one profile is a compilation error.

CBV, SRV and UAV descriptors share one heap. Index 0 is invalid, indices 1-25 are predefined and the dynamic portion starts at index 26: 230 slots for SMALL, 998 for MEDIUM and 4,070 for HIGH. ContextDesc can reduce heap capacities, but cannot exceed the compiled profile.

Buffers and textures share the resource limit. Imported textures and swapchain backbuffers also count. A sampled render target uses one resource slot, one SRV and one RTV; descriptor limits count all allocated views, including views retained for deferred GPU cleanup. All CPU resource and descriptor bookkeeping arrays have static storage; there are no resource pages.

The following maxima describe the default HIGH profile:

API capacity Maximum
Live buffers and textures 4,096 resources combined
Live swapchains 16 swapchains
Backbuffers per swapchain 2-3 backbuffers
Color attachments per render pass 8 attachments
Vertex input elements per pipeline 16 elements
Acquired command buffers awaiting submission 64 command buffers
Command buffers per submission batch 4 command buffers
Texture states tracked per command buffer 256 textures
Push constants 62 × 32-bit values (248 bytes)

The predefined descriptor positions are conveniences, not resource limits. Applications can use five CBV, five SRV and three UAV predefined positions; other resources receive dynamic descriptor indices.

Requirements

Windows 10/11, Direct3D 12 feature level 12.0, Resource Binding Tier 3 and Shader Model 6.6.

No ray tracing or mesh shaders yet.

See the tests documentation, technical reference and CMake guide for more details.

Samples

Sample
1. Triangle
Triangle
2. ViewportScissor
ViewportScissor
3. CBSRVCubes
CBSRVCubes
5. Z-buffer + MSAA x4
Z-buffer and MSAA x4
6. TexturedCube
TexturedCube
7. TextureSamplers
TextureSamplers
8. Ldx12 + Dear ImGui
Ldx12 + Dear ImGui
9. WorldGeometry
WorldGeometry
10. CubeMap
CubeMap
11. Texture2DArray
Texture2DArray
12. Transparency
Transparency
13. CookbookChapter02
14. ImGuiDemoNative
15. DepthPass (depth buffer)
Depth buffer visualization
19. MultiDrawIndirect glTF
MultiDrawIndirect glTF
20. TriplanarMapping
Triplanar mapping
21. ConstantBufferRings
Constant buffer rings