Summary
Prepare the texture cache and batcher systems for a future WebGPU backend by extracting renderer-agnostic parts from the current WebGL-specific implementations.
Completed
Buffer extraction (PR #1414)
- VertexArrayBuffer: moved from
video/webgl/buffer/ to video/buffer/ — zero GL dependency, pure typed array management
- IndexBuffer: split into renderer-agnostic
IndexBuffer base class (data accumulation, quad index patterns) and WebGLIndexBuffer subclass (GL buffer bind/upload)
Deferred — TextureCache unit management
Moving units/usedUnits/allocateTextureUnit/etc. from TextureCache to MaterialBatcher was attempted but causes rendering regressions.
Root causes identified
-
boundTextures is per-batcher, but GL texture units are global. When unit management lives on the batcher, each batcher (QuadBatcher, MeshBatcher, PrimitiveBatcher) independently allocates units. MeshBatcher assigns a texture to unit 0, then QuadBatcher also assigns a different texture to unit 0 — they conflict because GL units are shared.
-
blitTexture and beginPostEffect bypass unbindTexture2D. They do raw delete this.boundTextures[0] which desyncs the source→unit map from the unit→GLTexture map. Fixed by routing through unbindTexture2D, but the global vs per-batcher issue (point 1) remains.
-
The cache's units Map must be shared across all batchers. This is by design — cache.units maps texture sources to GL units at the renderer level, while batcher.boundTextures tracks which GL texture object is bound to each unit within that batcher. These are different levels of abstraction that cannot be merged.
Correct approach (future)
The source→unit mapping should stay on a shared object (renderer or cache). Options:
- Rename
cache.units/usedUnits to something clearer (e.g. textureBindings) and keep on cache
- Create a dedicated
TextureUnitAllocator on the renderer that both the cache and batchers access
- Keep the current architecture but document the intentional coupling between cache and batcher
Not planned (wait for WebGPU)
GLShader / ShaderEffect — GLSL vs WGSL is too fundamental to abstract without the actual WebGPU implementation
WebGLRenderer itself — 2000+ lines of direct GL, would be a parallel WebGPURenderer
- Specific batchers (
QuadBatcher, PrimitiveBatcher, MeshBatcher) — depend on the batcher base
Already done (prior PRs)
Summary
Prepare the texture cache and batcher systems for a future WebGPU backend by extracting renderer-agnostic parts from the current WebGL-specific implementations.
Completed
Buffer extraction (PR #1414)
video/webgl/buffer/tovideo/buffer/— zero GL dependency, pure typed array managementIndexBufferbase class (data accumulation, quad index patterns) andWebGLIndexBuffersubclass (GL buffer bind/upload)Deferred — TextureCache unit management
Moving
units/usedUnits/allocateTextureUnit/etc. from TextureCache to MaterialBatcher was attempted but causes rendering regressions.Root causes identified
boundTexturesis per-batcher, but GL texture units are global. When unit management lives on the batcher, each batcher (QuadBatcher, MeshBatcher, PrimitiveBatcher) independently allocates units. MeshBatcher assigns a texture to unit 0, then QuadBatcher also assigns a different texture to unit 0 — they conflict because GL units are shared.blitTextureandbeginPostEffectbypassunbindTexture2D. They do rawdelete this.boundTextures[0]which desyncs the source→unit map from the unit→GLTexture map. Fixed by routing throughunbindTexture2D, but the global vs per-batcher issue (point 1) remains.The cache's
unitsMap must be shared across all batchers. This is by design —cache.unitsmaps texture sources to GL units at the renderer level, whilebatcher.boundTexturestracks which GL texture object is bound to each unit within that batcher. These are different levels of abstraction that cannot be merged.Correct approach (future)
The source→unit mapping should stay on a shared object (renderer or cache). Options:
cache.units/usedUnitsto something clearer (e.g.textureBindings) and keep on cacheTextureUnitAllocatoron the renderer that both the cache and batchers accessNot planned (wait for WebGPU)
GLShader/ShaderEffect— GLSL vs WGSL is too fundamental to abstract without the actual WebGPU implementationWebGLRendereritself — 2000+ lines of direct GL, would be a parallelWebGPURendererQuadBatcher,PrimitiveBatcher,MeshBatcher) — depend on the batcher baseAlready done (prior PRs)
RenderTargetabstract base class withWebGLRenderTarget/CanvasRenderTarget(Add multi-pass post-effect chaining with renderer-agnostic RenderTarget architecture #1408)RenderTargetPoolwith factory pattern (Add multi-pass post-effect chaining with renderer-agnostic RenderTarget architecture #1408)RenderState— already renderer-agnosticTextureAtlas— already renderer-agnostic