状态与资源管理
本文档记录 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:
| 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 |
状态跟踪变量
WebGLState 实例维护大量 WebGL 参数的缓存状态:
| 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 |
状态更改流程
示例:setBlending 函数对比请求的混合状态与缓存状态:
Sources: src/renderers/webgl/WebGLState.js620-763
材质状态应用
setMaterial 函数将材质属性转换为 WebGL 状态:
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
纹理绑定优化
纹理绑定系统跟踪哪些纹理绑定到哪些纹理单元,以避免冗余的 gl.bindTexture 调用:
The currentBoundTextures object maps texture slots to { type, texture } objects. Empty textures are created at initialization to avoid binding null.
纹理资源管理
WebGLTextures 类管理纹理上传、缓存和生命周期。它实现了基于源的缓存系统,多个共享同一 Source 的 Texture 对象可以重用同一个 WebGL 纹理。
纹理缓存架构
缓存键生成:getTextureCacheKey 函数从纹理参数创建唯一键:
cacheKey = [wrapS, wrapT, wrapR, magFilter, minFilter, anisotropy,
internalFormat, format, type, generateMipmaps,
premultiplyAlpha, flipY, unpackAlignment, colorSpace].join()引用计数:每个 WebGL 纹理跟踪 usedTimes 以支持共享。当纹理更改参数时,其缓存键会更改,触发:
- Decrement old texture's
usedTimes - Increment new texture's
usedTimes(or create new texture) - Delete old texture if
usedTimesreaches 0
纹理上传管线
关键上传函数:
| 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 | 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 |
部分纹理更新:updateTexture 函数通过 texture.updateRanges 支持增量更新,合并相邻范围以最小化 gl.texSubImage2D 调用。
纹理生命周期管理
Dispose 处理:纹理在 initTexture 中注册 dispose 事件监听器,该监听器触发 deallocateTexture,后者在不再需要时递减引用计数并删除 GPU 资源。
渲染目标释放
渲染目标管理多个 GPU 资源(帧缓冲区、渲染缓冲区、深度纹理):
能力检测
WebGLCapabilities 类在渲染器初始化时查询 GPU 限制和扩展支持。
能力对象结构
精度选择:系统尝试使用请求的精度(默认 'highp'),但如果 GPU 不支持则回退到较低精度。
反转深度缓冲区:当 EXT_clip_control 扩展可用时启用,通过将深度范围从 [0,1] 反转为 [1,0] 提供更好的深度精度。
扩展管理
WebGLExtensions 类提供查询和缓存 WebGL 扩展的集中接口。
扩展初始化
扩展访问模式:
extensions.has(name):如果支持扩展则返回trueextensions.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 枚举,处理色彩空间和压缩格式。
转换类别
| 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) |
色彩空间处理: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:
- 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
内存跟踪
info 对象跟踪 GPU 内存使用:
info.memory.textures++ // Incremented when WebGL texture created
info.memory.textures-- // Decremented when WebGL texture deleted纹理创建发生在 initTexture 和渲染目标设置中。删除发生在 deleteTexture 和 deallocateRenderTarget 中。
性能优化
状态更改最小化
每个状态修改函数在发出 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}]与渲染管线的集成
状态和资源管理系统在整个渲染循环中被调用,确保在保持正确渲染状态的同时实现最小的冗余状态更改。