# Untangling Direct3D 12 Memory Heap Types and Pools
Sat
26
Feb 2022
Those of you who follow my blog can say that I am boring, but I can't help it - somehow GPU memory allocation became my thing, rather than shaders and effects, like most graphics programmers do. Some time ago I've written an article "Vulkan Memory Types on PC and How to Use Them" explaining what memory heaps and types are available on various types of PC GPUs, as visible through Vulkan API. This article is a Direct3D 12 equivalent, in a way.
With expressing memory types as they exist in hardware, D3D12 differs greatly from Vulkan. Vulkan defines a 2-level hierarchy of memory "heaps" and "types". A heap represents a physical piece of memory of a certain size, while a type is a "view" of a specific heap with certain properties, like cached versus uncached. This gives a great flexibility in how different GPUs can express their memory, which makes it hard for the developer to ensure he selects the optimal one on any kind of GPU. Direct3D 12 offers a fixed set of memory types. When creating a buffer or a texture, it usually means selecting one of the 3 standard "heap types":
D3D12_HEAP_TYPE_DEFAULT
is intended for resources that are directly and frequently accessed by the GPU, so all render-target, depth-stencil textures, other textures, vertex and index buffers used for rendering etc. go there. It typically ends up in the memory of the graphics card.D3D12_HEAP_TYPE_UPLOAD
represents a memory that we can Map
and fill in from the CPU and then copy or directly read on the GPU. It must be created and stay in D3D12_RESOURCE_STATE_GENERIC_READ
. It ends up in system RAM and is uncached but write-combined, which means it should only be written, never read.D3D12_HEAP_TYPE_READBACK
represents the least frequently used type of memory that the GPU can write or copy to, while the CPU can Map
and read. It must be created in D3D12_RESOURCE_STATE_COPY_DEST
. It ends up in system RAM and is cached, which means random access from our CPU code is fine for it.So far, so good... D3D12 seems to simplify things compared to Vulkan. You can stop here and still develop a decent graphics program, but if you make a game with an open world and want to stream your content in runtime, so you need to check what memory budget is available to your app, or you want to take advantage of integrated graphics where memory is unified, you will find out that things are not that simple in this API. There are 4 different ways that D3D12 calls various memory types and they are not so obvious when we compare systems with discrete versus integrated graphics. The goal of this article is to explain and untangle all this complexity.