Understanding D3D12_CPU_PAGE_PROPERTY in DirectX 12
In DirectX 12, memory management is exposed directly to the
developer, requiring precise control over how resources are allocated
and cached across the CPU and GPU. The
D3D12_CPU_PAGE_PROPERTY enumeration is a specialized tool
within custom heap configurations that dictates the CPU cache policies
for physical memory pages. By fine-tuning CPU page properties, graphics
engineers can balance CPU access latency, bandwidth usage, and cache
coherency based on the specific read/write patterns of a resource.
The Role of Custom Heaps
DirectX 12 provides high-level heap
types—D3D12_HEAP_TYPE_DEFAULT,
D3D12_HEAP_TYPE_UPLOAD, and
D3D12_HEAP_TYPE_READBACK—which internally assign default
CPU page properties. However, when developers define a
D3D12_HEAP_TYPE_CUSTOM heap via
D3D12_HEAP_PROPERTIES, they must manually declare the
CPUPageProperty member.
Selecting the proper property prevents performance hazards, such as CPU cache pollution, read-stall penalties, and inefficient cache coherency traffic over the interconnect bus (such as PCIe).
Enumeration Values and Caching Mechanisms
The D3D12_CPU_PAGE_PROPERTY enum defines four distinct
states:
D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE
The CPU cannot access the memory allocated in this heap. The memory is not mapped into the CPU's virtual address space, eliminating any CPU cache overhead. This is the optimal setting for GPU-exclusive resources (textures, render targets, depth buffers) living in discrete VRAM.D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE(WC)
CPU access is configured to bypass the L1/L2/L3 caches. Writes are accumulated in internal CPU write-combining buffers and burst-written to system memory in cache-line-sized chunks.- Use Case: Highly efficient for write-only CPU
buffers, such as per-frame dynamic vertex buffers, instance buffers, and
constant buffers.
- Performance Implication: Prevents CPU writes from evicting useful cached application data. However, reading from Write-Combine memory incurs an extreme performance penalty because every read must fetch directly from system memory without cache acceleration.
- Use Case: Highly efficient for write-only CPU
buffers, such as per-frame dynamic vertex buffers, instance buffers, and
constant buffers.
D3D12_CPU_PAGE_PROPERTY_WRITE_BACK(WB)
Memory allocations utilize full CPU caching. Reads and writes are cached across the CPU's cache hierarchy (L1, L2, L3) and written back to main memory as lines are evicted.- Use Case: Critical for resources where the CPU must
read data generated by the GPU (such as occlusion query results, compute
readbacks, or staging memory), or for resources that the CPU reads and
modifies iteratively before the GPU consumes them.
- Performance Implication: Greatly improves read performance for the CPU. On the GPU side, the hardware must either invalidate CPU caches or utilize hardware snooping to maintain coherency, which can add overhead on discrete systems.
- Use Case: Critical for resources where the CPU must
read data generated by the GPU (such as occlusion query results, compute
readbacks, or staging memory), or for resources that the CPU reads and
modifies iteratively before the GPU consumes them.
D3D12_CPU_PAGE_PROPERTY_UNKNOWN
A default/invalid value indicating that the page property is uninitialized or not applicable to standard heaps.
Optimizing for UMA and NUMA Architectures
The effectiveness of D3D12_CPU_PAGE_PROPERTY heavily
depends on the memory architecture:
Unified Memory Architecture (UMA):
On systems where the CPU and GPU share physical RAM (such as APUs, mobile chips, and modern consoles),WRITE_BACKcombined withD3D12_MEMORY_POOL_L0allows the GPU to read directly from CPU-cached memory without redundant transfer copies. This enables zero-copy resource updates with minimal latency.Non-Unified Memory Architecture (NUMA):
On systems with discrete GPUs, memory pools are strictly divided between system RAM (L0) and dedicated video memory (L1). AssigningWRITE_COMBINEto upload buffers residing in system memory ensures that high-speed CPU writes stream over PCIe without polluting the CPU cache or triggering unneeded cache-line write-backs.
Best Practices
- Never read from
WRITE_COMBINEmemory: Even a single accidental read operation from a mapped WC buffer stalls the CPU pipeline while waiting for non-cached memory access. - Default to
NOT_AVAILABLEwhen possible: If the CPU never maps or touches a resource after creation, keeping CPU pages unmapped maximizes GPU access performance and saves virtual address space. - Use
WRITE_BACKsparingly for uploads: Unless the CPU reads back values from the buffer prior to submission,WRITE_BACKintroduces unnecessary cache invalidation and eviction costs on write-only streams.