DirectX 12 Constant Buffer Alignment Requirements

In DirectX 12, managing memory manually requires strict adherence to hardware-defined alignment specifications to prevent crashes and undefined behavior. This article details the mandatory 256-byte alignment rule for constant buffers, outlines the relevant Direct3D 12 API constants, and demonstrates how to correctly align buffer sizes and memory offsets in application code.

The Minimum Byte Alignment Requirement

In DirectX 12, the minimum byte alignment requirement for constant buffers is 256 bytes.

Any memory address used as the start of a constant buffer, as well as the allocated size declared in a Constant Buffer View (CBV), must be an exact multiple of 256 bytes. This requirement is strictly enforced by the Direct3D 12 runtime and GPU hardware. If a constant buffer view is created with an offset or size that is not 256-byte aligned, the DirectX debug layer will report an error, and descriptor creation will fail.

API Definition

The Direct3D 12 API defines this requirement through the following constant:

D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT = 256;

When defining a D3D12_CONSTANT_BUFFER_VIEW_DESC structure:

  • BufferLocation: The GPU virtual address (D3D12_GPU_VIRTUAL_ADDRESS) must be aligned to a multiple of 256 bytes.
  • SizeInBytes: The buffer size specified in the view must be a multiple of 256 bytes.

Why 256 Bytes Is Required

Modern GPU architectures use SIMD (Single Instruction, Multiple Data) pipelines and dedicated constant cache systems. Fetching data from constant memory requires cache-line boundary alignment to ensure optimal memory bandwidth and avoid cross-boundary memory reads. Rather than allowing variable hardware-specific alignments, DirectX 12 standardizes this across all compliant hardware at 256 bytes.

Calculating 256-Byte Alignment

Because HLSL structures are typically smaller than 256 bytes, structures must be padded when calculating byte offsets and buffer allocation sizes.

You can compute the 256-byte aligned size using standard bitwise arithmetic:

constexpr UINT AlignConstantBufferSize(UINT byteSize)
{
    return (byteSize + 255) & ~255;
}

Or by using the standard alignment helper macro:

constexpr UINT AlignConstantBufferSize(UINT byteSize)
{
    return (byteSize + (D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1)) 
           & ~(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1);
}

Practical Application

When allocating a sub-allocated upload heap or ring buffer for per-frame data:

  1. Calculate the raw size of your C++ data structure.
  2. Pass that size to the alignment function to get the actual stride in bytes.
  3. Advance upload heap offsets by the aligned stride rather than the raw structure size.
  4. Pass the aligned value to D3D12_CONSTANT_BUFFER_VIEW_DESC::SizeInBytes.