How Does gl_LocalInvocationID Work in GLSL?
In GLSL compute shaders, gl_LocalInvocationID is a
built-in input variable that uniquely identifies the position of an
executing thread relative to its immediate local workgroup. Because
compute workloads are divided hierarchically into workgroups and
individual invocations, each invocation requires a distinct coordinate
within its group to compute data offsets, index into shared memory, and
coordinate execution with neighbor threads.
The Structure of Local Invocations
Compute shaders organize threads into three-dimensional grids called local workgroups. When writing a compute shader, the layout qualifier defines the local dimensions:
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;Inside this defined grid, gl_LocalInvocationID is
declared as a three-component unsigned integer vector
(uvec3). Its components correspond to the spatial
coordinates of the current thread:
gl_LocalInvocationID.x: Spans from0togl_WorkGroupSize.x - 1.gl_LocalInvocationID.y: Spans from0togl_WorkGroupSize.y - 1.gl_LocalInvocationID.z: Spans from0togl_WorkGroupSize.z - 1.
Even if a compute shader operates on 1D or 2D data, the variable
remains a uvec3, with unused dimensions defaulting to an
index of 0 and a size of 1.
Local Coordinates vs. Global Indexing
Understanding how gl_LocalInvocationID locates a thread
requires looking at the compute shader execution hierarchy. A dispatch
call distributes work across multiple workgroups, creating three levels
of identification:
gl_WorkGroupID: Identifies the position of the entire workgroup in the global dispatch grid.gl_LocalInvocationID: Identifies the thread's local position within its specific workgroup.gl_GlobalInvocationID: Identifies the thread across the entire global dispatch.
The relationship between local and global positioning is calculated by the hardware using the following formula:
\[\text{gl\_GlobalInvocationID} = \text{gl\_WorkGroupID} \times \text{gl\_WorkGroupSize} + \text{gl\_LocalInvocationID}\]
While gl_GlobalInvocationID determines which absolute
data element in a storage buffer or texture to process,
gl_LocalInvocationID isolates actions that are scoped
strictly to the local group.
1D Flattening with gl_LocalInvocationIndex
For operations requiring a flat one-dimensional array index rather
than 3D coordinates—such as indexing into linear shared
memory arrays—GLSL provides gl_LocalInvocationIndex. This
is the flattened scalar equivalent of gl_LocalInvocationID,
derived as follows:
\[\text{index} = \text{ID.z} \cdot (\text{Size.x} \cdot \text{Size.y}) + \text{ID.y} \cdot \text{Size.x} + \text{ID.x}\]
Primary Use Cases in Shader Programming
gl_LocalInvocationID is essential for tasks that involve
intra-workgroup cooperation:
- Shared Memory Access: Threads in the same workgroup
share high-speed on-chip memory (
shared).gl_LocalInvocationIDmaps each thread to its assigned slot in shared data structures. - Local Reductions: Parallel reduction algorithms (such as finding minimums, maximums, or sums) rely on local IDs to determine which threads stay active during each step of the reduction tree.
- Tiled Computations: Image processing filters, such as blurs or convolutions, use local coordinates to load pixel neighborhoods into local cache before evaluating convolution kernels.