GL_EXT_shader_16bit_storage SSBO Memory Layout
The GL_EXT_shader_16bit_storage extension allows shaders
to directly access 16-bit data types, such as half-precision
floating-point values, within Shader Storage Buffer Objects (SSBOs)
without requiring manual bitfield unpacking. This article outlines how
the extension defines alignment, size, and layout rules for 16-bit
floats under standard layout qualifiers (std430 and
std140) to ensure proper CPU-GPU memory
interoperability.
Enabling 16-Bit Types and Storage
Using half-precision floats in SSBOs requires both the storage extension and the explicit arithmetic type extension in GLSL:
#extension GL_EXT_shader_16bit_storage : require
#extension GL_EXT_shader_explicit_arithmetic_types_float16 : requireWith these enabled, the shader can use native 16-bit types: scalar
float16_t, vectors f16vec2,
f16vec3, and f16vec4, as well as corresponding
matrices.
Base Alignment and Size for 16-Bit Floats
Under GL_EXT_shader_16bit_storage, the memory footprint
and base alignment of half-float types are scaled down proportionally to
their 32-bit counterparts:
float16_t: Size is 2 bytes; base alignment is 2 bytes.f16vec2: Size is 4 bytes; base alignment is 4 bytes.f16vec3: Size is 6 bytes; base alignment is 8 bytes (aligned to the size of a 4-component vector of the base scalar type).f16vec4: Size is 8 bytes; base alignment is 8 bytes.
Layout Rules: std430 vs. std140
The memory packing behavior inside an SSBO depends strictly on the layout qualifier assigned to the buffer block.
std430 Layout (Recommended for SSBOs)
The std430 qualifier eliminates unnecessary array
padding, allowing optimal packing for 16-bit floats:
- Scalar Arrays: An array of
float16_tvalues has an array stride equal to the base scalar alignment (2 bytes). Elements are placed contiguously with no padding between them. - Vector Arrays:
f16vec2[]has a stride of 4 bytes.f16vec4[]has a stride of 8 bytes.f16vec3[]has an 8-byte stride because the base alignment of a 3-component vector rounds up to the size of a 4-component vector, resulting in 2 bytes of implicit padding per element.
layout(std430, binding = 0) buffer DataBuffer {
float16_t scalarArray[]; // Stride = 2 bytes (tightly packed)
f16vec2 vec2Array[]; // Stride = 4 bytes
f16vec4 vec4Array[]; // Stride = 8 bytes
};std140 Layout
If an SSBO uses std140, legacy uniform buffer alignment
rules apply unless overridden by additional scalar layout
extensions:
- Array elements and structure members have their stride rounded up to
a multiple of 16 bytes (the size of a standard 32-bit
vec4). - A
float16_t[]array inside astd140block consumes 16 bytes per element, with 14 bytes of padding between each value, negating the memory-saving benefits of 16-bit data.
Matrices and Structs
- Matrices: Matrices are treated as arrays of vectors
(columns by default). In
std430, a column-majorf16mat2x2consists of twof16vec2columns, requiring 8 bytes total (4 bytes per column). Af16mat4x4requires 32 bytes (8 bytes per column). - Structures: The base alignment of a struct containing 16-bit members is equal to the largest base alignment of any member inside the struct. The struct's total size is padded to a multiple of its base alignment.