SSBOs, Images & Atomics
SSBOs vs UBOs: SSBOs are much larger (≥ 128 MB vs ~64 KB), writable, support unsized arrays and atomics, but UBO reads may be faster for small uniform data.
27.1 Shader Storage Buffer Objects
SSBOs vs UBOs: SSBOs are much larger (≥ 128 MB vs ~64 KB), writable, support unsized arrays and atomics, but UBO reads may be faster for small uniform data.
struct Particle { vec4 position; vec4 velocity; }; // vec4s keep std430 layout simple
layout (std430, binding = 0) buffer ParticleBuffer {
float deltaTime; // fixed-size members first
uint count;
Particle particles[]; // unsized array must be LAST
};
void main() {
uint i = gl_GlobalInvocationID.x;
if (i >= count) return;
particles[i].velocity.y -= 9.81 * deltaTime;
particles[i].position.xyz += particles[i].velocity.xyz * deltaTime;
}glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, size, data, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
// Use the same buffer as a vertex buffer for rendering after glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT)27.2 Image load/store
Fragment shaders can also write images/SSBOs (e.g., order-independent transparency, voxelization, GPU picking).
layout (r32f, binding = 0) uniform image2D uHeight; // format qualifier required for reading
float h = imageLoad(uHeight, ivec2(x, y)).r;
imageStore(uHeight, ivec2(x, y), vec4(h + 0.1));
imageSize(uHeight);
layout (r32ui, binding = 1) uniform uimage2D uCounter;
uint old = imageAtomicAdd(uCounter, ivec2(x, y), 1u); // atomic on image texels (r32i/r32ui)27.3 Atomic operations
layout (std430, binding = 2) buffer Stats { uint visibleCount; uint histogram[256]; };
atomicAdd(visibleCount, 1u);
atomicMin(...); atomicMax(...); atomicAnd(...); atomicOr(...); atomicXor(...);
atomicExchange(x, v); atomicCompSwap(x, compare, v);
// Floating-point atomics need extensions (GL_EXT_shader_atomic_float, NV_shader_atomic_float)
layout (binding = 0, offset = 0) uniform atomic_uint uCount; // atomic counter buffers
atomicCounterIncrement(uCount);27.4 Memory coherence rules
Writes from one invocation are not automatically visible to others: use coherent qualifiers and memoryBarrier*() within a dispatch; use glMemoryBarrier() (or Vulkan pipeline barriers) between dispatches/draws.