How Three.js Handles WebGL2 and WebGL1 Fallback

This article explores how Three.js manages graphics rendering contexts behind the scenes, focusing on its automatic initialization of WebGL2 and its internal fallback mechanism to WebGL1. You will learn how the engine detects browser capabilities, negotiates context creation with the HTML5 canvas, and maintains feature and shader compatibility across different hardware and browser generations.

The Context Creation Lifecycle

When you instantiate a WebGLRenderer in Three.js, the engine immediately begins the process of acquiring a rendering context from the provided or newly created <canvas> element.

Under the hood, Three.js prioritizes WebGL2. The initialization sequence follows a strict hierarchy during context acquisition:

  1. WebGL2 Attempt: The renderer first calls canvas.getContext( 'webgl2', attributes ). If the browser and hardware support WebGL2, this returns a WebGL2RenderingContext, and the initialization succeeds.
  2. WebGL1 Fallback: If the WebGL2 call returns null, Three.js catches the failure and falls back to WebGL1 by calling canvas.getContext( 'webgl', attributes ).
  3. Legacy Fallback: If standard WebGL1 is unavailable, it attempts to query canvas.getContext( 'experimental-webgl', attributes ) to support older browsers.
  4. Failure Handling: If all attempts return null, Three.js throws an error, and the renderer fails to initialize. Developers can detect this using utility classes like WebGL.isWebGLAvailable().

Feature Detection and WebGLCapabilities

Once a context is successfully acquired, Three.js queries the context to determine its version and properties. It creates an internal WebGLCapabilities instance, which acts as a central repository of GPU limits and supported features.

Within WebGLCapabilities, Three.js sets a boolean flag: isWebGL2. This flag is crucial because the engine queries it constantly during the rendering loop. If isWebGL2 is true, Three.js unlocks native WebGL2 features such as:

If isWebGL2 is false, Three.js gracefully downgrades. It attempts to load the equivalent WebGL1 extensions. If the extensions are missing, the associated features are disabled or simulated via software workarounds.

Shader Compilation and GLSL Translation

One of the most complex aspects of the WebGL2 to WebGL1 fallback is shader compatibility. WebGL2 uses GLSL ES 3.00, while WebGL1 is restricted to GLSL ES 1.00.

To prevent developers from having to write two versions of every shader, Three.js handles shader translation automatically inside the WebGLProgram class:

Texture and Parameter Mapping

WebGL2 introduces stricter internal texture formats and coordinate wrapping rules. When falling back to WebGL1, Three.js adjusts its internal state machine to prevent WebGL errors: