DirectX 12 Multi-Adapter Cross-Node Sharing
This article provides an overview of cross-node sharing in DirectX 12 multi-adapter resource management. It explains how linked graphics processing units (GPUs) operate under a single device context, how resources are allocated and mapped across individual hardware nodes, and the synchronization mechanisms required to efficiently share data between multiple GPUs for high-performance rendering.
Understanding Multi-Adapter Nodes in DirectX 12
DirectX 12 introduces explicit multi-adapter support, enabling developers to harness the compute and graphics capabilities of multiple GPUs. Multi-adapter systems are categorized into two models: unlinked adapters (separate physical graphics cards with independent drivers and memory) and linked adapters (identical GPUs linked through technologies like SLI or CrossFire, governed by a single driver).
In a linked-adapter configuration, the operating system exposes the
combined hardware as a single ID3D12Device. Within this
unified device, each individual physical GPU is represented as a
node. Cross-node sharing refers to the management,
access, and transfer of resources (such as textures, buffers, and render
targets) between these distinct hardware nodes.
How Cross-Node Sharing Works
In a multi-node architecture, each GPU node typically possesses its own dedicated local video memory (VRAM). Cross-node sharing enables one node to read from, write to, or duplicate memory residing on another node.
Node Masks
DirectX 12 manages resource locality using bitmasks:
- CreationNodeMask: Specifies the node where the resource primarily resides and where physical memory is allocated.
- VisibleNodeMask: Specifies which nodes have visibility into that resource. By setting multiple bits in the visible mask, multiple GPUs can reference the same resource descriptor.
When a resource is marked visible to multiple nodes, the graphics driver determines whether to enable direct remote access over a high-speed bus (such as NVLink or PCIe) or to manage transparent synchronization behind the scenes.
Cross-Node Resource Copies
When direct remote access is inefficient or unsupported, data must be
explicitly transferred between the local memory spaces of the nodes.
Developers use standard command list methods, such as
CopyResource, CopyBufferRegion, or
CopyTextureRegion, executed on a command queue configured
for a specific node.
DirectX 12 allows a command list targeting Node A to copy data directly from a resource on Node A to a resource on Node B, provided the appropriate node visibility flags are configured on the destination or shared resource.
Synchronization Mechanisms
Because each node processes commands independently via its own command queues, cross-node operations require explicit synchronization to avoid race conditions.
- Multi-Engine Fences: Monitored fences
(
ID3D12Fence) can be shared across nodes. A command queue on Node 0 can signal a fence upon completing a render pass, while a command queue on Node 1 waits on that same fence before reading the resulting data. - Resource Barriers: Transitions must be coordinated
to ensure caches are flushed and resources are in the correct state
(e.g., transitioning from
D3D12_RESOURCE_STATE_RENDER_TARGETtoD3D12_RESOURCE_STATE_COPY_SOURCE) before a secondary node attempts to read or copy them.
Common Use Cases
Cross-node sharing is essential for several advanced rendering techniques:
- Alternate Frame Rendering (AFR): Node 0 renders even frames while Node 1 renders odd frames. Cross-node sharing transfers shared assets, temporal anti-aliasing buffers, and previous-frame motion vectors between nodes.
- Split-Frame Rendering (SFR): Multiple GPUs render different viewports or tiles of a single frame simultaneously. Cross-node sharing gathers the rendered tiles onto the primary node that drives the display output.
- Dedicated Compute Offloading: One node executes heavy compute operations (such as physics, ray tracing acceleration structure updates, or fluid simulations), and the results are transferred to the primary graphics node via cross-node sharing for final compositing.