DirectX 12 Memory Copies on UMA Systems
In systems utilizing Unified Memory Architecture (UMA)—such as integrated APUs, game consoles, and mobile chipsets—executing DirectX 12 memory copies behaves fundamentally differently under the hood compared to discrete GPU environments. While discrete architectures require explicit staging copies across the PCIe bus to move resources from system memory to dedicated VRAM, UMA systems host both CPU and GPU workloads within a single, shared physical DRAM pool. This article explains the underlying hardware behavior when DirectX 12 copy commands are executed on UMA systems, the architectural implications for memory bandwidth, and the texture layout transformations that may still require physical transfers.
Physical Memory Routing and the Copy Engine
On a discrete GPU (NUMA), a resource copy typically moves data from a
CPU-visible upload heap (D3D12_HEAP_TYPE_UPLOAD) across the
PCIe bus into a fast, GPU-exclusive local heap
(D3D12_HEAP_TYPE_DEFAULT).
When this same operation is initiated on a UMA system using
CopyBufferRegion or CopyTextureRegion:
- Both the source heap and destination heap reside in the exact same physical system RAM.
- The GPU's direct memory access (DMA) or copy engine issues read transactions to system memory and immediately issues write transactions back to another address range within the same system memory.
- No PCIe bus traversal occurs. The transfer takes place entirely across the internal system fabric or memory crossbar.
Because CPU and GPU cores compete for the exact same physical memory channels, these copy operations can lead to significant memory bus contention. Instead of accelerating access, performing a memory-to-memory copy consumes dual-bandwidth overhead (simultaneous reads and writes) on a memory bus that is already typically narrower than dedicated GDDR or HBM interfaces.
Buffers vs. Textures: When the Copy Still Matters
The utility of a copy command on UMA systems depends entirely on the resource type being transferred.
Linear Buffers
For structured buffers, vertex buffers, and constant buffers, memory layout is linear. Performing a GPU-side copy from an upload heap to a default heap on UMA is functionally redundant. Reading from an upload buffer mapped to system RAM yields virtually identical GPU read performance compared to reading from a default buffer in system RAM. On UMA hardware, buffer-to-buffer copies typically waste execution cycles and bandwidth with no structural gain.
Textures and Swizzling
For textures, the copy operation performs an essential data reorganization step. Textures generated by the CPU or loaded from disk are stored in linear (row-major) order. GPUs, however, access textures using multi-dimensional spatial layouts (often referred to as tiled, swizzled, or Morton order) to maximize texture cache hit rates during bilinear or trilinear sampling.
Even on a UMA device:
- The GPU copy engine reads the linear layout from the upload heap.
- The engine hardware-swizzles the pixel data into the proprietary, tiled micro-tiling format required by the GPU sampler.
- The swizzled data is written back to the destination texture in system memory.
Unless the application can generate pre-swizzled textures or the driver supports CPU-tiled formats, texture copies remain a necessary step on UMA architectures.
Cache Coherency and Heap Configuration
UMA architectures interact differently with CPU caches depending on
hardware implementation, which DirectX 12 exposes through the
D3D12_FEATURE_ARCHITECTURE query:
- Standard UMA (
UMA = TRUE,CacheCoherentUMA = FALSE): The GPU and CPU share physical memory, but their caches are not coherent. Upload heaps default to write-combined (WC) CPU memory properties to avoid cache pollution. Executing a copy command on the GPU ensures that CPU caches are flushed or bypassed, allowing the GPU to read the finalized data safely without manual invalidation protocols. - Cache-Coherent UMA
(
CacheCoherentUMA = TRUE): The CPU and GPU maintain snoop-based cache coherence. In these architectures, CPU writes to standard write-back cacheable memory are immediately visible to the GPU. Copy commands are even less necessary here, as data written by the CPU can be consumed directly by GPU shaders without intermediate synchronization or cache-flushing copies.
Optimizing DirectX 12 Workloads for UMA
DirectX 12 allows engines to detect UMA configurations at runtime and adjust allocation strategies accordingly:
- Bypass Buffer Staging: Check
D3D12_FEATURE_DATA_ARCHITECTURE::UMA. If true, bypass traditional staging pipelines for static and dynamic buffers. Allocate buffers directly inD3D12_HEAP_TYPE_UPLOADor custom heaps using write-combined or write-back CPU page properties, and bind them directly as Shader Resource Views (SRVs) or Vertex Buffer Views (VBVs). - Conserve Memory Bandwidth: Eliminating redundant buffer copies preserves shared memory throughput for compute shaders, pixel shaders, and display controllers.
- Isolate Texture Uploads: Maintain the copy queue primarily for texture resources where hardware tiling yields a net performance benefit during sampling, rather than treating all GPU resource allocations uniformly.