Skip to content

状态与资源管理

本文档记录 Three.js 中的 WebGL 状态管理和 GPU 资源管理系统。这些系统最小化冗余的 GPU 状态更改并管理 GPU 资源(纹理、缓冲区、帧缓冲区)的生命周期,以优化渲染性能。

有关着色器程序和编译的信息,请参阅着色器程序与编译。关于几何体缓冲区管理,请参阅几何体系统


概述

状态与资源管理层位于高级渲染器与 WebGL API 之间。其主要职责包括:

  • 状态跟踪:缓存当前 WebGL 状态以避免冗余的 gl.* 调用
  • 纹理管理:在 GPU 上上传、缓存和共享纹理数据
  • 资源生命周期:分配、跟踪和释放 GPU 资源
  • 能力检测:查询 GPU 限制和扩展可用性
  • 格式转换:将 Three.js 常量转换为 WebGL 枚举

WebGLState 架构

WebGLState 类维护 WebGL 状态的阴影副本,以消除冗余的状态更改。它公开的方法在发出 WebGL 命令之前会对比请求的状态与缓存状态。

State Buffers

Three specialized buffer classes manage render target state:

SVG
100%
BufferPurposeKey State Variables
ColorBufferColor write mask and clear colorcurrentColorMask, currentColorClear
DepthBufferDepth testing and writingcurrentDepthFunc, currentDepthMask, currentReversed
StencilBufferStencil testing and operationscurrentStencilFunc, currentStencilFail, currentStencilZPass

状态跟踪变量

WebGLState 实例维护大量 WebGL 参数的缓存状态:

State CategoryCached VariablesPurpose
BlendingcurrentBlending, currentBlendEquation, currentBlendSrc, currentBlendDst, currentBlendColor, currentBlendAlphaTrack blending mode and parameters
CullingcurrentFlipSided, currentCullFaceTrack face culling direction
TexturescurrentTextureSlot, currentBoundTexturesTrack active texture unit and bindings
FramebufferscurrentBoundFramebuffers, currentDrawbuffersTrack framebuffer bindings
ProgramcurrentProgramTrack active shader program
ViewportcurrentScissor, currentViewportTrack scissor and viewport rectangles
Polygon OffsetcurrentPolygonOffsetFactor, currentPolygonOffsetUnitsTrack depth offset parameters

状态更改流程

SVG
100%

示例:setBlending 函数对比请求的混合状态与缓存状态:

Sources: src/renderers/webgl/WebGLState.js620-763

材质状态应用

setMaterial 函数将材质属性转换为 WebGL 状态:

SVG
100%

Implementation Details:

  • Maps material.side (DoubleSide/BackSide/FrontSide) to gl.CULL_FACE enable/disable
  • Translates material.blending to gl.blendFunc and gl.blendEquation
  • Applies depth function, test, and write mask
  • Configures stencil operations when material.stencilWrite is enabled
  • Handles reversed depth buffers via EXT_clip_control extension

纹理绑定优化

纹理绑定系统跟踪哪些纹理绑定到哪些纹理单元,以避免冗余的 gl.bindTexture 调用:

SVG
100%

The currentBoundTextures object maps texture slots to { type, texture } objects. Empty textures are created at initialization to avoid binding null.

纹理资源管理

WebGLTextures 类管理纹理上传、缓存和生命周期。它实现了基于源的缓存系统,多个共享同一 SourceTexture 对象可以重用同一个 WebGL 纹理。

纹理缓存架构

SVG
100%

缓存键生成getTextureCacheKey 函数从纹理参数创建唯一键:

cacheKey = [wrapS, wrapT, wrapR, magFilter, minFilter, anisotropy, 
            internalFormat, format, type, generateMipmaps, 
            premultiplyAlpha, flipY, unpackAlignment, colorSpace].join()

引用计数:每个 WebGL 纹理跟踪 usedTimes 以支持共享。当纹理更改参数时,其缓存键会更改,触发:

  1. Decrement old texture's usedTimes
  2. Increment new texture's usedTimes (or create new texture)
  3. Delete old texture if usedTimes reaches 0

纹理上传管线

SVG
100%

关键上传函数

FunctionPurposeLine Reference
uploadTextureMain upload coordinatorsrc/renderers/webgl/WebGLTextures.js859-1313
initTextureInitialize WebGL texture and manage cachesrc/renderers/webgl/WebGLTextures.js670-748
updateTexturePartial texture updates via update rangessrc/renderers/webgl/WebGLTextures.js756-857
setTextureParametersSet texture filtering and wrappingsrc/renderers/webgl/WebGLTextures.js623-668
getInternalFormatDetermine internal format from format/type/colorSpacesrc/renderers/webgl/WebGLTextures.js128-229

纹理类型特化

上传管线根据纹理类型分支:

Texture TypeUpload MethodSpecial Handling
DepthTexturetexStorage2D or texImage2DUses getInternalDepthFormat for depth/stencil formats
DataTexturetexImage2D or texSubImage2DHandles manual mipmaps, supports updateRanges for partial updates
CompressedTexturecompressedTexImage2D/3D or compressedTexSubImage2D/3DSupports layer updates for array textures
DataArrayTexturetexImage3D or texSubImage3D3D upload with layer update support
Data3DTexturetexImage3D or texSubImage3D3D volume texture upload
Regular TexturetexStorage2D + texSubImage2DUses texStorage2D for immutable storage when supported

部分纹理更新updateTexture 函数通过 texture.updateRanges 支持增量更新,合并相邻范围以最小化 gl.texSubImage2D 调用。

纹理生命周期管理

SVG
100%

Dispose 处理:纹理在 initTexture 中注册 dispose 事件监听器,该监听器触发 deallocateTexture,后者在不再需要时递减引用计数并删除 GPU 资源。

渲染目标释放

渲染目标管理多个 GPU 资源(帧缓冲区、渲染缓冲区、深度纹理):

SVG
100%

能力检测

WebGLCapabilities 类在渲染器初始化时查询 GPU 限制和扩展支持。

能力对象结构

SVG
100%

精度选择:系统尝试使用请求的精度(默认 'highp'),但如果 GPU 不支持则回退到较低精度。

反转深度缓冲区:当 EXT_clip_control 扩展可用时启用,通过将深度范围从 [0,1] 反转为 [1,0] 提供更好的深度精度。

扩展管理

WebGLExtensions 类提供查询和缓存 WebGL 扩展的集中接口。

扩展初始化

SVG
100%

扩展访问模式

  • extensions.has(name):如果支持扩展则返回 true
  • extensions.get(name):返回扩展对象或 null,如果不支持则记录警告

常见扩展包括:

  • EXT_color_buffer_float:浮点渲染目标
  • EXT_texture_filter_anisotropic:各向异性过滤
  • WEBGL_compressed_texture_*:压缩纹理格式(S3TC、PVRTC、ETC、ASTC、BPTC、RGTC)
  • WEBGL_multi_draw:实例化的多重绘制命令
  • EXT_clip_control:反转深度缓冲区

格式转换工具

WebGLUtils 类将 Three.js 常量转换为 WebGL 枚举,处理色彩空间和压缩格式。

转换类别

CategoryThree.js ConstantsWebGL Enums
Data TypesUnsignedByteType, FloatType, HalfFloatType, IntType, etc.gl.UNSIGNED_BYTE, gl.FLOAT, gl.HALF_FLOAT, gl.INT, etc.
FormatsRGBAFormat, RGBFormat, RedFormat, DepthFormat, etc.gl.RGBA, gl.RGB, gl.RED, gl.DEPTH_COMPONENT, etc.
Compressed FormatsRGBA_S3TC_DXT5_Format, RGBA_ASTC_4x4_Format, etc.Extension-specific enums (e.g., extension.COMPRESSED_RGBA_S3TC_DXT5_EXT)

色彩空间处理convert 函数接受可选的 colorSpace 参数。对于 sRGB 色彩空间中的压缩格式,它从扩展中检索相应的 SRGB 变体(例如,使用 COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 而不是 COMPRESSED_RGBA_S3TC_DXT5_EXT)。

状态重置和初始化

初始化序列

在渲染器创建时,状态系统使用默认值进行初始化:

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() 函数将 WebGL 恢复到已知的初始状态,在上下文丢失或切换渲染器时使用:

Actions Performed:

  1. Disable all state flags (BLEND, CULL_FACE, DEPTH_TEST, etc.)
  2. Reset blend functions and equations
  3. Reset color mask, depth mask, stencil mask
  4. Reset clear colors
  5. Reset framebuffer bindings
  6. Reset program binding
  7. Reset texture bindings
  8. Reset viewport and scissor
  9. Clear all internal state caches

内存跟踪

info 对象跟踪 GPU 内存使用:

info.memory.textures++  // Incremented when WebGL texture created
info.memory.textures--  // Decremented when WebGL texture deleted

纹理创建发生在 initTexture 和渲染目标设置中。删除发生在 deleteTexturedeallocateRenderTarget 中。

性能优化

状态更改最小化

每个状态修改函数在发出 WebGL 调用之前,都会将请求的状态与缓存状态进行对比:

if (currentValue !== newValue) {
    gl.someStateFunction(newValue);
    currentValue = newValue;
}

此模式出现在:

  • setBlending:对比 8+ 个混合参数
  • bindTexture:对比每个槽位的纹理类型和对象
  • useProgram:对比程序对象
  • bindFramebuffer:对比每个目标的帧缓冲区

纹理存储与纹理图像

现代代码路径优先使用 gl.texStorage2D(不可变存储)而不是 gl.texImage2D

优势

  • 在一次调用中分配所有 mipmap 级别
  • 允许更高效的 gl.texSubImage2D 更新
  • 防止意外的格式更改

系统在 texture.isVideoTexture !== true 时使用 texStorage2D,并且为每个源只分配一次内存。

更新范围合并

updateTexture 函数在发出 gl.texSubImage2D 调用之前合并相邻或重叠的更新范围,从而减少 GPU 命令开销:

// Before merging: [{start: 0, count: 100}, {start: 100, count: 100}]
// After merging:  [{start: 0, count: 200}]

与渲染管线的集成

SVG
100%

状态和资源管理系统在整个渲染循环中被调用,确保在保持正确渲染状态的同时实现最小的冗余状态更改。