The DirectX Graphics resource management subsystem provides developers with a set of APIs to create, bind, and destroy GPU resources such as buffers, textures, and shaders. Proper management of these resources is essential for achieving high performance and minimizing GPU memory fragmentation.
| Feature | Description |
| Resource Types | Buffers, Textures, Samplers, Views |
| Lifetime | Explicit creation & release, reference counting |
| Memory Heaps | Default, Upload, Readback, Custom |
| Debug Layer | Runtime validation of resource usage |
DirectX defines several core resource classes. Each class maps to a specific GPU object type.
- ID3D12Resource – Base class for buffers and textures.
- ID3D12DescriptorHeap – Stores descriptors for SRVs, UAVs, CBVs, etc.
- ID3D12PipelineState – Encapsulates compiled shaders and state objects.
Resources are created with ID3D12Device::CreateCommittedResource or ID3D12Device::CreatePlacedResource, depending on whether they are allocated from a heap or placed within a pre‑allocated heap.
Resource lifetimes must be carefully coordinated with command queue execution. The typical pattern is:
- Create resource.
- Record commands that use the resource.
- Signal a fence after submitting the command list.
- Release the resource only after the fence is signaled.
Using the ComPtr smart pointer simplifies reference counting:
Microsoft::WRL::ComPtr<ID3D12Resource> vertexBuffer;
device->CreateCommittedResource(
&heapProperties,
D3D12_HEAP_FLAG_NONE,
&resourceDesc,
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER,
nullptr,
IID_PPV_ARGS(&vertexBuffer));
Choosing the right heap type directly impacts performance:
- Default Heap – GPU‑only memory; fast access for rendering.
- Upload Heap – CPU‑visible, write‑combined; ideal for uploading dynamic data.
- Readback Heap – CPU‑visible, cached; used for retrieving GPU results.
For large static assets, consider using a custom heap to reduce fragmentation and improve allocation speed.
The following example demonstrates creating a vertex buffer, uploading data, and issuing a draw call.
#include <d3d12.h>
#include <dxgi1_4.h>
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
struct Vertex { float x, y, z; float r, g, b, a; };
void CreateVertexBuffer(ID3D12Device* device, ID3D12GraphicsCommandList* cmdList)
{
// Vertex data
Vertex vertices[] = {
{ 0.0f, 0.5f, 0.0f, 1,0,0,1 },
{ 0.5f, -0.5f, 0.0f, 0,1,0,1 },
{-0.5f, -0.5f, 0.0f, 0,0,1,1 },
};
const UINT vertexBufferSize = sizeof(vertices);
// Create upload heap for the vertex data
ComPtr<ID3D12Resource> vertexBufferUpload;
D3D12_HEAP_PROPERTIES uploadHeapProps = {};
uploadHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
D3D12_RESOURCE_DESC bufferDesc = {};
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
bufferDesc.Width = vertexBufferSize;
bufferDesc.Height = 1;
bufferDesc.DepthOrArraySize = 1;
bufferDesc.MipLevels = 1;
bufferDesc.SampleDesc.Count = 1;
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
device->CreateCommittedResource(
&uploadHeapProps,
D3D12_HEAP_FLAG_NONE,
&bufferDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&vertexBufferUpload));
// Copy data to the upload heap
void* pVertexDataBegin;
D3D12_RANGE readRange = {}; // We do not intend to read from this resource on the CPU.
vertexBufferUpload->Map(0, &readRange, &pVertexDataBegin);
memcpy(pVertexDataBegin, vertices, vertexBufferSize);
vertexBufferUpload->Unmap(0, nullptr);
// Create default heap (GPU‑only) buffer
ComPtr<ID3D12Resource> vertexBufferGPU;
D3D12_HEAP_PROPERTIES defaultHeapProps = {};
defaultHeapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
device->CreateCommittedResource(
&defaultHeapProps,
D3D12_HEAP_FLAG_NONE,
&bufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&vertexBufferGPU));
// Copy from upload heap to default heap
cmdList->CopyBufferRegion(vertexBufferGPU.Get(), 0, vertexBufferUpload.Get(), 0, vertexBufferSize);
// Transition to VERTEX_AND_CONSTANT_BUFFER state
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = vertexBufferGPU.Get();
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
cmdList->ResourceBarrier(1, &barrier);
// Create a vertex buffer view
D3D12_VERTEX_BUFFER_VIEW vbView = {};
vbView.BufferLocation = vertexBufferGPU->GetGPUVirtualAddress();
vbView.SizeInBytes = vertexBufferSize;
vbView.StrideInBytes = sizeof(Vertex);
cmdList->IASetVertexBuffers(0, 1, &vbView);
}
Compile with /EHsc /std:c++17 and link against d3d12.lib and dxgi.lib.