Shader Optimization Techniques

Published on October 28, 2024

Shader performance can make or break a 3D experience. Here are battle-tested techniques for optimizing your GLSL shaders.

Branch Elimination

GPUs execute shaders in parallel, and branches can cause divergence:

// Bad: Branch causes divergence
if (condition) {
  color = texture(tex1, uv);
} else {
  color = texture(tex2, uv);
}

// Good: Both textures sampled, result selected
vec4 c1 = texture(tex1, uv);
vec4 c2 = texture(tex2, uv);
color = mix(c1, c2, float(condition));

Precision Qualifiers

Use the minimum precision needed:

// Full precision only when needed
highp float worldPosition;
mediump vec3 normal;
lowp vec4 color;

Precompute Constants

Move calculations out of loops and into uniforms when possible:

// Bad: Computed every fragment
float radius = sqrt(resolution.x * resolution.x + resolution.y * resolution.y);

// Good: Precomputed on CPU, passed as uniform
uniform float uDiagonalLength;

Texture Atlasing

Reduce texture switches by combining textures:

  • Pack multiple images into one atlas
  • Use channels efficiently (roughness in alpha, etc.)
  • Consider array textures for similar-sized images

Measuring Performance

Use browser dev tools’ GPU profiler and:

  • Test on target hardware
  • Profile both vertex and fragment stages
  • Watch for texture bandwidth bottlenecks
← Back to Articles