Using Placed Resources in DirectX 12 Custom Heaps
In DirectX 12, placed resources provide explicit, low-level control
over GPU virtual memory by mapping directly into pre-allocated memory
heaps. By separating memory allocation from resource creation,
developers can bypass driver-side allocation overhead, implement
resource aliasing, and optimize memory layouts according to hardware
constraints. This article examines how placed resources leverage custom
ID3D12Heap instances, the architectural mechanics behind
offset mapping, and the specific requirements for alignment, resource
aliasing, and hardware tiers.
The Decoupling of Memory and Resources
Standard DirectX 12 resource allocation through
CreateCommittedResource combines the allocation of a memory
heap and the creation of a resource into a single call. While simple,
this approach forces the driver to manage memory boundaries and prevents
fine-grained spatial optimization.
Placed resources decouple these systems through
ID3D12Device::CreatePlacedResource. Instead of requesting
memory from the driver at resource creation, the developer allocates a
large chunk of physical or virtual memory upfront using
ID3D12Device::CreateHeap. Placed resources are then
instantiated inside that specific ID3D12Heap at explicit
byte offsets.
Creating and Configuring the Custom Heap
A custom heap is defined using the D3D12_HEAP_DESC
structure and allocated once, typically during application
initialization or scene loading:
D3D12_HEAP_DESC heapDesc = {};
heapDesc.SizeInBytes = totalHeapSize;
heapDesc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; // Or D3D12_HEAP_TYPE_CUSTOM
heapDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; // 64KB
heapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES;When using D3D12_HEAP_TYPE_CUSTOM, developers can
explicitly set CPU page properties
(D3D12_CPU_PAGE_PROPERTY) and memory pools
(D3D12_MEMORY_POOL). This is particularly useful for
optimizing access patterns on Unified Memory Architecture (UMA) systems,
such as APUs or consoles, or tailoring cache coherency across
non-uniform memory architectures.
Mapping Placed Resources to Offsets
Once the heap exists, placed resources are mapped into it without
triggering kernel-mode memory allocations. The call requires the target
heap, the byte offset, a resource description
(D3D12_RESOURCE_DESC), and an initial state:
device->CreatePlacedResource(
pHeap,
offsetInBytes,
&resourceDesc,
D3D12_RESOURCE_STATE_COMMON,
nullptr,
IID_PPV_ARGS(&pResource)
);Because memory allocation is isolated to the initial heap creation, creating and destroying placed resources incurs near-zero runtime CPU overhead. The runtime merely validates parameters and instantiates the resource interface pointing to the pre-reserved address range.
Memory Aliasing and Footprint Reduction
The primary architectural advantage of leveraging pre-allocated heaps with placed resources is resource aliasing. Two or more resources with non-overlapping lifetimes can occupy the exact same physical byte range within a heap.
For example, a high-resolution transient render target used exclusively in an early depth pass can share the same memory range as a post-processing buffer used at the end of the frame. To ensure data integrity when reusing memory:
- The developer must place an aliasing barrier
(
D3D12_RESOURCE_ALIASING_BARRIER) into the command list. - The barrier informs the GPU driver that the memory layout is changing usage contexts, flushing relevant caches and handling metadata transitions.
This technique reduces the peak Video RAM (VRAM) footprint of a rendering pipeline to only the maximum memory required by concurrently active resources, rather than the sum of all resources.
Alignment Requirements and Heap Tiers
DirectX 12 imposes strict hardware alignment constraints when placing resources within a custom heap:
- Buffers and Standard Textures: Must be aligned to
64 KB (
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT). - Multi-Sampled (MSAA) Textures: Must be aligned to 4
MB (
D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT). - Small Textures: Certain textures with dimensions that fit within small footprints can use 4 KB alignment if explicitly configured.
Additionally, the hardware's supported Resource Heap Tier dictates what resource types can coexist within the same custom heap:
- Resource Heap Tier 1: Imposes categorization
restrictions. Buffers, non-render-target/depth-stencil textures, and
render-target/depth-stencil textures must reside in separate heaps or
distinct, non-interleaved memory categories governed by
D3D12_HEAP_FLAGS. - Resource Heap Tier 2: Removes categorization
restrictions. Developers can arbitrarily place buffers, standard
textures, and render targets within the same heap using
D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES, enabling optimal memory packing and aliasing across all pipeline stages.