DirectX 12 CPU and iGPU Cache Coherency
In DirectX 12, cache coherency between the CPU and an integrated GPU (iGPU) determines how updates to shared physical memory are synchronized between both processing units. Because iGPUs physically reside on the same die or package as the CPU and share system RAM, DirectX 12 exposes low-level architecture queries, memory heap definitions, and explicit synchronization models to manage whether the hardware automatically synchronizes caches or requires software-driven mitigation to avoid stale data.
The Unified Memory Architecture (UMA) Distinction
Integrated GPUs operate under Unified Memory Architecture (UMA), eliminating the physical separation between CPU system memory and GPU video memory. However, sharing physical RAM does not automatically guarantee shared, coherent caches.
DirectX 12 exposes this hardware capability through the
D3D12_FEATURE_DATA_ARCHITECTURE query via two boolean
properties: UMA and CacheCoherentUMA.
- Non-Coherent UMA (
UMA = TRUE,CacheCoherentUMA = FALSE): The CPU and iGPU share system RAM, but their internal caches are not automatically synchronized by hardware. If the CPU writes data to its local L1/L2/L3 caches, the iGPU reading from system memory will see stale data unless the CPU caches are explicitly bypassed or flushed. - Cache-Coherent UMA
(
CacheCoherentUMA = TRUE): The hardware features bidirectional hardware snooping or a shared Last-Level Cache (LLC) / System-Level Cache (SLC). When the iGPU requests data, the interconnect queries or invalidates the CPU caches automatically, ensuring both processors see the most recent write without explicit software intervention.
Heap Types and CPU Cache Properties
To maintain performance and prevent data hazards across varying hardware, DirectX 12 uses predefined heap types and CPU page properties that determine how the CPU cache interacts with shared buffers:
- Upload Heaps (
D3D12_HEAP_TYPE_UPLOAD): By default, upload heaps are mapped with Write-Combined (WC) CPU caching semantics. Write-combining bypasses the CPU’s L1/L2/L3 data caches, buffering writes in internal CPU store buffers before committing them directly to main memory. Because data is never placed in standard CPU cache lines, the iGPU can read the modified memory directly from RAM without requiring manual cache invalidation, even on non-coherent systems. - Readback Heaps
(
D3D12_HEAP_TYPE_READBACK): These heaps are configured for CPU reading and are typically marked as uncached or write-back, optimized for the CPU to drain data generated by the GPU. - Custom Heaps (
D3D12_HEAP_TYPE_CUSTOM): WhenCacheCoherentUMAis supported, developers can create custom heaps withD3D12_CPU_PAGE_PROPERTY_WRITE_BACK. This enables the CPU to cache reads and writes with standard L1–L3 cache lines. On coherent hardware, the iGPU can read this data directly from the CPU's cache or via snoop cycles, eliminating the performance penalty of uncached or write-combined access.
Software Synchronization and Explicit API Contracts
Even with hardware cache coherency, DirectX 12 enforces a split-barrier model to govern execution order and memory visibility:
- Memory Mapping (
Map/Unmap): DirectX 12 does not require calls toUnmapto make CPU writes visible to the GPU. Instead, the developer specifies aD3D12_RANGEduring mapping and unmapping. On non-coherent systems, the driver uses these ranges to determine which regions require explicit cache flushing. On cache-coherent systems, these ranges serve primarily as hints for internal driver tracking. - Resource Barriers: While CPU-to-GPU cache
synchronization is handled by the memory controller, snooping, or
write-combining buffers, the GPU’s internal caches (such as its L1/L2
texture and render target caches) are independent. Developers must issue
ID3D12GraphicsCommandList::ResourceBarriertransitions to flush and invalidate internal GPU caches when transitioning resources between writable and readable states. - Execution Synchronization: Hardware coherency
guarantees that memory operations are eventually visible, but it does
not guarantee execution order. Developers must use
ID3D12Fenceobjects to ensure the CPU has finished writing to a buffer before the iGPU's command queue begins executing workloads that depend on that data.