DirectX 12 Explicit Multi-Adapter Explained
DirectX 12's Explicit Multi-Adapter API shifts multi-GPU management from closed, driver-level abstraction directly into the hands of game developers. By exposing the physical hardware adapters directly to the application, DirectX allows developers to manage memory allocation, work scheduling, and inter-adapter synchronization independently. This architectural shift enables fine-grained control over how rendering tasks are partitioned across multiple identical or disparate graphics cards, improving efficiency and eliminating the synchronization bottlenecks inherent in older multi-GPU systems.
The Shift from Implicit to Explicit
Prior to DirectX 12, multi-GPU configurations like NVIDIA SLI or AMD CrossFire relied on implicit support through hardware drivers. The operating system and driver presented the hardware as a single virtual GPU, commonly forcing Alternate Frame Rendering (AFR), where GPUs took turns rendering full frames. While simple for developers, AFR introduced latency, frame pacing issues, and poor scaling.
DirectX 12 changes this by treating each physical GPU as an
independent adapter (ID3D12Device). The developer decides
what each GPU does, how resources are duplicated or transferred, and how
frame pacing is maintained.
Execution Modes: Linked vs. Unlinked Adapters
The API categorizes multi-GPU configurations into two main configurations:
- Linked Multi-Adapter (LMA): Designed for systems running multiple identical or near-identical GPUs that share a specialized physical connection or unified driver infrastructure. In this mode, the API exposes a single device instance containing multiple "nodes." The GPUs share an identical driver context, allowing them to mirror resources automatically or access memory across cards with minimal overhead. Developers use node masks to dispatch commands to specific GPUs while treating memory heaps as largely unified.
- Unlinked Multi-Adapter (UMA): Designed to harness
heterogeneous hardware, such as pairing a discrete GPU with a CPU's
integrated graphics or combining GPUs from different manufacturers. Each
GPU is initialized as a completely separate
ID3D12Devicewith independent memory budgets, command queues, and execution pipelines.
Data Sharing via Cross-Adapter Resources
Because discrete GPUs reside on separate PCIe buses with dedicated VRAM, moving data between them requires explicit coordination. DirectX 12 facilitates this through cross-adapter heaps and shared textures.
To share data, a developer creates a resource on the secondary GPU
within a cross-adapter-capable heap (typically stored in system memory
via the PCIe bus). The primary GPU then writes or reads from this shared
buffer. To maintain data integrity across asynchronous engines, DirectX
uses shared fences (ID3D12Fence). A GPU signals the fence
upon finishing its computational work, allowing the target GPU to wait
until the resource is ready before reading or displaying it.
Workload Partitioning Strategies
Explicit Multi-Adapter enables rendering architectures beyond standard alternate frame rendering:
- Split-Frame Rendering (SFR): Dividing a single frame spatially, where each GPU renders a specific horizontal or vertical portion of the screen simultaneously.
- Asymmetric Compute Offloading: Assigning the primary discrete card to heavy geometry and rasterization workloads, while the secondary or integrated GPU handles asynchronous compute tasks such as ambient occlusion, particle physics, audio processing, or user interface composition.
- Predictive Pipeline Rendering: Offloading pre-pass data, such as shadow map generation or depth buffers, to a secondary adapter one frame ahead of the main render pass.