DirectX 12 Placed vs Committed Resources
DirectX 12 gives developers explicit control over GPU memory, replacing the automatic resource management found in older graphics APIs. This article provides a concise breakdown of two primary resource creation methods in DirectX 12: committed resources and placed resources. You will learn the mechanics behind each approach, how they interact with GPU memory heaps, their specific use cases, and how choosing the right method impacts runtime performance and memory efficiency.
The Foundation: GPU Memory Heaps
In DirectX 12, physical and virtual GPU memory is represented by heap
objects (ID3D12Heap). A resource, such as a texture or a
vertex buffer, is essentially a structured view over a range of bytes
located within a heap. The fundamental difference between committed and
placed resources lies in how closely the resource object is bound to its
underlying memory allocation.
Committed Resources
A committed resource couples the resource metadata and its underlying
heap allocation into a single unified operation using
ID3D12Device::CreateCommittedResource.
When you allocate a committed resource, the DirectX 12 runtime and graphics driver simultaneously create an implicit heap large enough to contain the resource and bind the resource directly to it.
Characteristics of Committed Resources:
- Simplicity: It requires the least amount of
boilerplate code. You do not need to create or manage an explicit
ID3D12Heap. - Isolated Lifetimes: The heap's lifetime is tied directly to the resource. Releasing the resource automatically frees the underlying memory.
- Driver Optimization: Certain hardware and driver architectures can optimize dedicated allocations for specific, persistent assets, such as large render targets, swap chain buffers, or primary depth-stencil surfaces.
- Inflexibility: Memory cannot be shared, overlapped, or repurposed for other resources. This can lead to increased memory consumption and fragmentation if overused for temporary or transient assets.
Placed Resources
A placed resource decouples the memory allocation from the resource
object. To use placed resources, you first explicitly allocate an
ID3D12Heap via ID3D12Device::CreateHeap. You
then create individual resources within that heap at specific byte
offsets using ID3D12Device::CreatePlacedResource.
Characteristics of Placed Resources:
- Memory Aliasing: Multiple resources can occupy the same physical memory space within a heap at overlapping offsets. For example, a temporary render target used exclusively in a shadow pass can share memory with a post-processing buffer used later in the frame, dramatically lowering overall VRAM usage.
- Manual Synchronization: Aliased resources require
explicit synchronization. You must use resource aliasing barriers
(
D3D12_RESOURCE_BARRIER_TYPE_ALIASING) to inform the GPU driver when memory is transitioning from one resource view to another to avoid race conditions and cache corruption. - Strict Alignment Rules: Placed resources must strictly adhere to hardware alignment requirements (typically 64 KB for standard buffers and textures, or 4 MB for multi-sample anti-aliasing textures).
- Efficiency: Creating and destroying placed resources is lightweight compared to committed resources because it does not involve OS-level memory allocations—only the creation of a resource descriptor over existing memory.
Key Differences Summary
| Feature | Committed Resources | Placed Resources |
|---|---|---|
| Heap Creation | Implicit (handled by driver) | Explicit
(ID3D12Device::CreateHeap) |
| API Method | CreateCommittedResource |
CreatePlacedResource |
| Memory Aliasing | Not supported | Fully supported |
| Allocation Cost | Slower (allocates OS/GPU memory) | Fast (maps over existing heap) |
| Complexity | Low | High (requires barrier & offset management) |
When to Use Each
Use committed resources for long-lived, high-priority assets that remain active throughout the application's lifecycle, such as back buffers, static environment geometry, UI buffers, and primary depth buffers.
Use placed resources for transient, frame-graph-driven workloads. They are best suited for scratch buffers, intermediate render passes, compute buffers, and dynamic asset streaming systems where memory reuse and strict limits on total VRAM consumption are critical.