Understanding std430 vs std140 Layout in GLSL
In OpenGL Shading Language (GLSL), memory layouts dictate how data
inside Uniform Buffer Objects (UBOs) and Shader Storage Buffer Objects
(SSBOs) is aligned in GPU memory. This article explains how the
std430 layout specification optimizes memory usage compared
to std140, specifically focusing on how it eliminates
aggressive 16-byte structure and array padding to allow tighter, more
CPU-friendly memory packing.
The std140 Padding Problem
The std140 standard was introduced primarily for Uniform
Buffer Objects to ensure hardware-agnostic cross-platform alignment. To
guarantee efficient access across diverse GPU architectures,
std140 enforces a strict 16-byte (vec4) base
alignment rule on arrays and nested structures:
- Array Element Alignment: Every element in an
array—even an array of simple scalars like
floatorint—has its base alignment and array stride rounded up to the base alignment of avec4(16 bytes). - Structure Alignment: The size of any structure, as well as the stride between elements in an array of structures, is rounded up to a multiple of 16 bytes.
Under std140, an array declared as:
layout(std140) buffer DataBuffer {
float values[4];
};requires 64 bytes of memory instead of 16 bytes. Each
float takes 4 bytes of data followed by 12 bytes of dead
padding.
Similarly, an array of structures containing two floats:
struct Particle {
float mass;
float lifetime;
};
layout(std140) buffer ParticleBuffer {
Particle particles[2];
};requires 32 bytes total. Even though Particle only
contains 8 bytes of actual data, std140 pads each instance
to 16 bytes to satisfy the vec4 minimum stride
requirement.
How std430 Eliminates Structure and Array Padding
The std430 layout qualifier, available exclusively for
Shader Storage Buffer Objects (SSBOs), eliminates the mandatory 16-byte
round-up rule. Instead, it adopts alignment rules that closely mirror
standard C and C++ data structure alignment.
1. Natural Alignment for Scalar and Vector Arrays
In std430, the base alignment and array stride of an
array are set directly to the natural base alignment of the underlying
type, rather than rounding up to a vec4:
- An array of
floatorintvalues has an alignment and stride of 4 bytes. - An array of
vec2values has an alignment and stride of 8 bytes. - An array of
vec3orvec4values has an alignment and stride of 16 bytes.
Because the stride of float values[4] is 4 bytes in
std430, the array occupies exactly 16 contiguous bytes
without unused padding between elements.
2. Tighter Structure Stride
Under std430, the base alignment of a structure is equal
to the largest base alignment of any of its members, rather than being
forced to a minimum of 16 bytes. The size of the structure (and thus its
stride in an array) is simply rounded up to a multiple of its own base
alignment.
Using the previous Particle structure:
struct Particle {
float mass; // offset: 0, size: 4
float lifetime; // offset: 4, size: 4
};
layout(std430) buffer ParticleBuffer {
Particle particles[2]; // stride: 8 bytes
};- The largest member in
Particleis afloat(4-byte alignment). - The structure's base alignment becomes 4 bytes.
- The total size is 8 bytes, which is already a multiple of 4.
- The array stride becomes 8 bytes instead of being inflated to 16 bytes.
Practical Advantages of std430
- Reduced Memory Footprint: Eliminating redundant padding can reduce buffer memory consumption by up to 75% for scalar arrays and compact structures.
- Direct CPU-to-GPU Serialization: In C and C++,
tightly packed structs match the
std430memory layout natively. Developers can map or upload standard CPU structs directly viaglBufferDataorglBufferSubDatawithout writing custom serialization layers or inserting manual dummy padding fields. - Cache Efficiency: Packaged data improves GPU cache locality by preventing unused padding bytes from occupying cache lines during shader read and write operations.