State & Resource Management
This page documents the WebGL state management and GPU resource management systems in Three.js. These systems minimize redundant GPU state changes and manage the lifecycle of GPU resources (textures, buffers, framebuffers) to optimize rendering performance.
For information about shader programs and compilation, see Shader Programs & Compilation. For geometry buffer management specifically, see Geometry System.
Overview
The state and resource management layer sits between the high-level renderer and the WebGL API. Its primary responsibilities are:
- State Tracking: Cache current WebGL state to avoid redundant
gl.*calls - Texture Management: Upload, cache, and share texture data on the GPU
- Resource Lifecycle: Allocate, track, and dispose of GPU resources
- Capability Detection: Query GPU limits and extension availability
- Format Conversion: Translate Three.js constants to WebGL enums
WebGLState Architecture
The WebGLState class maintains a shadow copy of WebGL state to eliminate redundant state changes. It exposes methods that compare requested state against cached state before issuing WebGL commands.
State Buffers
Three specialized buffer classes manage render target state:
| Buffer | Purpose | Key State Variables |
|---|---|---|
| ColorBuffer | Color write mask and clear color | currentColorMask, currentColorClear |
| DepthBuffer | Depth testing and writing | currentDepthFunc, currentDepthMask, currentReversed |
| StencilBuffer | Stencil testing and operations | currentStencilFunc, currentStencilFail, currentStencilZPass |
State Tracking Variables
The WebGLState instance maintains cached state for numerous WebGL parameters:
| State Category | Cached Variables | Purpose |
|---|---|---|
| Blending | currentBlending, currentBlendEquation, currentBlendSrc, currentBlendDst, currentBlendColor, currentBlendAlpha | Track blending mode and parameters |
| Culling | currentFlipSided, currentCullFace | Track face culling direction |
| Textures | currentTextureSlot, currentBoundTextures | Track active texture unit and bindings |
| Framebuffers | currentBoundFramebuffers, currentDrawbuffers | Track framebuffer bindings |
| Program | currentProgram | Track active shader program |
| Viewport | currentScissor, currentViewport | Track scissor and viewport rectangles |
| Polygon Offset | currentPolygonOffsetFactor, currentPolygonOffsetUnits | Track depth offset parameters |
State Change Flow
Example: The setBlending function compares requested blending state against cached state:
Sources: src/renderers/webgl/WebGLState.js620-763
Material State Application
The setMaterial function translates material properties to WebGL state:
Implementation Details:
- Maps
material.side(DoubleSide/BackSide/FrontSide) togl.CULL_FACEenable/disable - Translates
material.blendingtogl.blendFuncandgl.blendEquation - Applies depth function, test, and write mask
- Configures stencil operations when
material.stencilWriteis enabled - Handles reversed depth buffers via
EXT_clip_controlextension
Texture Binding Optimization
The texture binding system tracks which textures are bound to which texture units to avoid redundant gl.bindTexture calls:
The currentBoundTextures object maps texture slots to { type, texture } objects. Empty textures are created at initialization to avoid binding null.
Texture Resource Management
The WebGLTextures class manages texture uploads, caching, and lifecycle. It implements a source-based caching system where multiple Texture objects sharing the same Source can reuse the same WebGL texture.
Texture Caching Architecture
Cache Key Generation: The getTextureCacheKey function creates a unique key from texture parameters:
cacheKey = [wrapS, wrapT, wrapR, magFilter, minFilter, anisotropy,
internalFormat, format, type, generateMipmaps,
premultiplyAlpha, flipY, unpackAlignment, colorSpace].join()Reference Counting: Each WebGL texture tracks usedTimes to support sharing. When a texture changes parameters, its cache key changes, triggering:
- Decrement old texture's
usedTimes - Increment new texture's
usedTimes(or create new texture) - Delete old texture if
usedTimesreaches 0
Texture Upload Pipeline
Key Upload Functions:
| Function | Purpose | Line Reference |
|---|---|---|
| uploadTexture | Main upload coordinator | src/renderers/webgl/WebGLTextures.js859-1313 |
| initTexture | Initialize WebGL texture and manage cache | src/renderers/webgl/WebGLTextures.js670-748 |
| updateTexture | Partial texture updates via update ranges | src/renderers/webgl/WebGLTextures.js756-857 |
| setTextureParameters | Set texture filtering and wrapping | src/renderers/webgl/WebGLTextures.js623-668 |
| getInternalFormat | Determine internal format from format/type/colorSpace | src/renderers/webgl/WebGLTextures.js128-229 |
Texture Type Specializations
The upload pipeline branches based on texture type:
| Texture Type | Upload Method | Special Handling |
|---|---|---|
| DepthTexture | texStorage2D or texImage2D | Uses getInternalDepthFormat for depth/stencil formats |
| DataTexture | texImage2D or texSubImage2D | Handles manual mipmaps, supports updateRanges for partial updates |
| CompressedTexture | compressedTexImage2D/3D or compressedTexSubImage2D/3D | Supports layer updates for array textures |
| DataArrayTexture | texImage3D or texSubImage3D | 3D upload with layer update support |
| Data3DTexture | texImage3D or texSubImage3D | 3D volume texture upload |
| Regular Texture | texStorage2D + texSubImage2D | Uses texStorage2D for immutable storage when supported |
Partial Texture Updates: The updateTexture function supports incremental updates via texture.updateRanges, merging adjacent ranges to minimize gl.texSubImage2D calls.
Texture Lifecycle Management
Dispose Handling: Textures register a dispose event listener in initTexture that triggers deallocateTexture, which decrements reference counts and deletes GPU resources when no longer needed.
Render Target Disposal
Render targets manage multiple GPU resources (framebuffers, renderbuffers, depth textures):
Capability Detection
The WebGLCapabilities class queries GPU limits and extension support at renderer initialization.
Capabilities Object Structure
Precision Selection: The system attempts to use the requested precision (default 'highp') but falls back to lower precision if unsupported by the GPU.
Reversed Depth Buffer: Enabled when EXT_clip_control extension is available, providing better depth precision by reversing the depth range from [0,1] to [1,0].
Extension Management
The WebGLExtensions class provides a centralized interface for querying and caching WebGL extensions.
Extension Initialization
Extension Access Pattern:
extensions.has(name): Returnstrueif extension is supportedextensions.get(name): Returns extension object ornull, logs warning if unsupported
Common extensions include:
EXT_color_buffer_float: Float render targetsEXT_texture_filter_anisotropic: Anisotropic filteringWEBGL_compressed_texture_*: Compressed texture formats (S3TC, PVRTC, ETC, ASTC, BPTC, RGTC)WEBGL_multi_draw: Multi-draw commands for instancingEXT_clip_control: Reversed depth buffers
Format Conversion Utilities
The WebGLUtils class converts Three.js constants to WebGL enums, handling color space and compression formats.
Conversion Categories
| Category | Three.js Constants | WebGL Enums |
|---|---|---|
| Data Types | UnsignedByteType, FloatType, HalfFloatType, IntType, etc. | gl.UNSIGNED_BYTE, gl.FLOAT, gl.HALF_FLOAT, gl.INT, etc. |
| Formats | RGBAFormat, RGBFormat, RedFormat, DepthFormat, etc. | gl.RGBA, gl.RGB, gl.RED, gl.DEPTH_COMPONENT, etc. |
| Compressed Formats | RGBA_S3TC_DXT5_Format, RGBA_ASTC_4x4_Format, etc. | Extension-specific enums (e.g., extension.COMPRESSED_RGBA_S3TC_DXT5_EXT) |
Color Space Handling: The convert function accepts an optional colorSpace parameter. For compressed formats in sRGB color space, it retrieves the corresponding SRGB variant from the extension (e.g., COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT instead of COMPRESSED_RGBA_S3TC_DXT5_EXT).
State Reset and Initialization
Initialization Sequence
At renderer creation, the state system is initialized with default values:
colorBuffer.setClear(0, 0, 0, 1)
depthBuffer.setClear(1)
stencilBuffer.setClear(0)
enable(gl.DEPTH_TEST)
depthBuffer.setFunc(LessEqualDepth)
setFlipSided(false)
setCullFace(CullFaceBack)
enable(gl.CULL_FACE)
setBlending(NoBlending)Reset Function
The reset() function restores WebGL to a known initial state, used when the context is lost or when switching renderers:
Actions Performed:
- Disable all state flags (BLEND, CULL_FACE, DEPTH_TEST, etc.)
- Reset blend functions and equations
- Reset color mask, depth mask, stencil mask
- Reset clear colors
- Reset framebuffer bindings
- Reset program binding
- Reset texture bindings
- Reset viewport and scissor
- Clear all internal state caches
Memory Tracking
The info object tracks GPU memory usage:
info.memory.textures++ // Incremented when WebGL texture created
info.memory.textures-- // Decremented when WebGL texture deletedTexture creation occurs in initTexture and render target setup. Deletion occurs in deleteTexture and deallocateRenderTarget.
Performance Optimizations
State Change Minimization
Every state-modifying function compares the requested state against the cached state before issuing WebGL calls:
if (currentValue !== newValue) {
gl.someStateFunction(newValue);
currentValue = newValue;
}This pattern appears in:
setBlending: Compares 8+ blending parametersbindTexture: Compares texture type and object per slotuseProgram: Compares program objectbindFramebuffer: Compares framebuffer per target
Texture Storage vs Texture Image
Modern code paths prefer gl.texStorage2D (immutable storage) over gl.texImage2D:
Benefits:
- Allocates all mipmap levels in one call
- Allows more efficient
gl.texSubImage2Dupdates - Prevents accidental format changes
The system uses texStorage2D when texture.isVideoTexture !== true and only allocates memory once per source.
Update Range Merging
The updateTexture function merges adjacent or overlapping update ranges before issuing gl.texSubImage2D calls, reducing GPU command overhead:
// Before merging: [{start: 0, count: 100}, {start: 100, count: 100}]
// After merging: [{start: 0, count: 200}]Integration with Rendering Pipeline
The state and resource management systems are called throughout the render loop, ensuring minimal redundant state changes while maintaining correct rendering state.