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:

  1. The developer must place an aliasing barrier (D3D12_RESOURCE_ALIASING_BARRIER) into the command list.
  2. 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.