GLSL Switch Evaluation Without Break Statements
In the OpenGL Shading Language (GLSL), the switch
statement controls program flow by matching an integer selector against
constant integer case labels. When a developer omits break
statements between these labels, GLSL exhibits standard fall-through
behavior identical to C and C++. This article explains the exact
execution mechanics of uninhibited fall-through, clarifying how the GPU
evaluates subsequent case labels, transfers execution control, and
ultimately resolves statement blocks in shader code.
The Initial Evaluation and Jump
The switch statement accepts a scalar expression that
evaluates to an integer (int or uint). During
execution, GLSL evaluates this expression exactly once. The runtime then
compares the result against the compile-time constant expressions
provided in each case label.
Once a matching integer label is found, the GPU directly jumps
program control to the first statement following that label. If no case
matches and a default label exists, execution jumps
directly to the default block.
Fall-Through Mechanics and Label Ignorance
When a break statement is omitted, execution does not
stop at the end of the matched case block. Instead, it enters a state
known as fall-through:
- Subsequent Labels Are Not Evaluated: Once the
initial match is made, the GPU does not evaluate or compare any
remaining
caselabels against the selector variable. In GLSL, case labels are purely compile-time jump targets (entry points) rather than runtime conditions. - Linear Execution Continues: The shader program
continues executing subsequent instructions linearly down the switch
body, passing right through any subsequent
caseordefaultmarkers as if they were nonexistent. - Termination Conditions: Fall-through execution
continues uninterrupted until the control flow encounters an explicit
exit statement—such as a
break,return, ordiscard—or until it reaches the closing brace (}) of the switch block.
Code Demonstration
Consider the following GLSL code snippet:
int mode = 1;
int outputValue = 0;
switch (mode) {
case 0:
outputValue += 1;
break;
case 1:
outputValue += 10;
// break omitted intentionally
case 2:
outputValue += 100;
break;
default:
outputValue += 1000;
}In this example:
- The expression
modeevaluates to1. - Control jumps directly to
case 1:, adding10tooutputValue. - Because there is no
break, execution continues directly intocase 2:. The labelcase 2:is not re-checked againstmode. - The statement
outputValue += 100;executes, makingoutputValueequal to110. - Control then encounters the
break;statement inside thecase 2section, successfully terminating the switch construct and bypassing thedefaultblock.
Compiler and Hardware Considerations
While fall-through is valid in GLSL (from version 1.30 and ESSL 3.00
onward), hardware implementations flatten or unroll these control flows
into branch-and-jump instructions at the machine code level. Omitting
break statements intentionally can be useful for grouping
multiple values that share common logic, but doing so accidentally can
result in unexpected state modifications and divergent thread execution
across a warp or wavefront.