Summary
Tracking issue for the WebGL 2 features that became available once #1509 made the renderer WebGL 2 only. Kept as one ticket rather than five, because some of these are concrete cleanups and others enable capabilities we have not decided to build — splitting one out when it is actually picked up keeps the tracker honest about which is which.
Already split out
| Status |
Item |
Ticket |
| ⬜ open |
Mesh instancing |
#1508 |
| ✅ done (20.0) |
Static-mesh VBO caching |
#1507 |
| ✅ done (20.0, #1564) |
Mipmapped minification + anisotropic filtering |
#1511 |
| ✅ done (20.0) |
Lighting uniform buffer (raise MAX_LIGHTS) |
#1552 |
| 🔶 half done |
Shared frame-globals uniform buffer — the WebGPU backend ships this shape (bind-group-0 frame globals). The WebGL half is blocked on a compatibility promise, not merely unfinished: GL uniform blocks need GLSL ES 3.00 while user shaders are contractually ES 1.00 — written up in #1568, deliberately not scheduled |
#1555 / #1568 |
| ✅ done (20.0, #1566) |
Text / gradient texture sizing (fixed-resolution gradient ramps + 32px text buckets) — glyph atlas follow-up: #1565 |
#1554 |
| ✅ done (20.0) |
Backend-neutral vertex formats + topologies |
#1551 |
Concrete, no design question — ✅ both done (20.0, #1567)
texStorage2D immutable textures + sized internal formats. Allocate once with texStorage2D, update with texSubImage2D. Immutable storage lets drivers skip per-upload completeness validation, and sized formats (RGBA8 etc.) remove format-inference guesswork. Touches MaterialBatcher.createTexture2D and therefore every upload path — compressed textures, FBO attachments, and the video re-upload path added in 19.9.1 — so it is a texture-pipeline change rather than an addition.
Done in #1567. Every non-resource texture allocates immutable sized storage once and updates through texSubImage2D. The payoff turned out to be larger than the driver-validation saving this entry anticipated: a same-size content update (ticking Text, Gradient re-bake, video frame) was creating a fresh texture object every time, because CanvasRenderTarget.invalidate dropped the batcher's binding record and sent the next upload down the allocate path. Invalidation now marks the unit content-dirty instead, so with the #1554 size buckets the steady state of dynamic text and gradients allocates nothing at all.
MSAA framebuffers via blitFramebuffer. renderbufferStorageMultisample + resolve-blit gives antialiased post-effect passes, which WebGL 1 could not do at all. Currently antiAlias only affects the default framebuffer, so any scene using post-effects loses edge AA. Changes what post-effect FBOs produce, so it needs visual re-baselining.
Done in #1567, on both GPU backends — it became a paired change once WebGPU shipped, since the same gap existed there. Post-effect capture targets are multisampled (4× color + depth-stencil renderbuffers resolved via blitFramebuffer on WebGL; a per-target multisampled texture resolved by the render pass on WebGPU); ping-pong intermediates stay 1×, since effect blits are screen-aligned quads with no geometric edges to antialias. The WebGPU multisampled half is per-target rather than shared, because nested effect brackets interleave passes and a mid-frame load-back would otherwise read another target's stored samples. toFrameTexture() resolves an active multisampled target before copying and rebinds it afterwards.
The visual re-baselining this entry called for was done with a headed edge probe on both backends: with an effect active, MSAA now produces the identical intermediate-coverage signature as the no-effect control (3 distinct levels — the 4× quantization), while antiAlias: false measures a hard step. Cost is documented in the CHANGELOG: roughly 28 B/px extra on WebGL (~55 MB at 1080p) and ~16 B/px on WebGPU, allocated only when antiAlias is on.
Speculative — enables features not yet decided
Multiple Render Targets (MRT). drawBuffers writing colour + normal + depth in one pass. The enabler for deferred lighting and G-buffer effects; only worth doing if we want those, since the current forward path is fine for 2D and light 3D.
Texture arrays / 3D textures. TEXTURE_2D_ARRAY would let the GPU tilemap sample one array instead of juggling several atlases, and would relieve the texture-unit pressure that TextureCache works around today. Interacts with #1410 (renderer-agnostic texture cache) — worth designing together rather than separately.
Transform feedback. Capture vertex-shader output into a buffer; the groundwork for GPU skinning and GPU particle simulation. Note #1404 already covers GPU-instanced particles by a different route.
What is left
With both concrete items done, this tracker holds only: #1508 (mesh instancing), the #1568 GL frame-globals variant (deferred by decision), and the three speculative items below — none of which are scheduled, and two of which (texture arrays, MRT) are worth designing against #1410 / the WebGPU backend rather than in isolation.
Notes
Unblocked by #1509.
Summary
Tracking issue for the WebGL 2 features that became available once #1509 made the renderer WebGL 2 only. Kept as one ticket rather than five, because some of these are concrete cleanups and others enable capabilities we have not decided to build — splitting one out when it is actually picked up keeps the tracker honest about which is which.
Already split out
Static-mesh VBO cachingMipmapped minification + anisotropic filteringLighting uniform buffer (raiseMAX_LIGHTS)Text / gradient texture sizing (fixed-resolution gradient ramps + 32px text buckets)— glyph atlas follow-up: #1565Backend-neutral vertex formats + topologiesConcrete, no design question — ✅ both done (20.0, #1567)
. Allocate once withtexStorage2Dimmutable textures + sized internal formatstexStorage2D, update withtexSubImage2D. Immutable storage lets drivers skip per-upload completeness validation, and sized formats (RGBA8etc.) remove format-inference guesswork. TouchesMaterialBatcher.createTexture2Dand therefore every upload path — compressed textures, FBO attachments, and the video re-upload path added in 19.9.1 — so it is a texture-pipeline change rather than an addition.MSAA framebuffers via
blitFramebuffer.renderbufferStorageMultisample+ resolve-blit gives antialiased post-effect passes, which WebGL 1 could not do at all. CurrentlyantiAliasonly affects the default framebuffer, so any scene using post-effects loses edge AA. Changes what post-effect FBOs produce, so it needs visual re-baselining.Speculative — enables features not yet decided
Multiple Render Targets (MRT).
drawBufferswriting colour + normal + depth in one pass. The enabler for deferred lighting and G-buffer effects; only worth doing if we want those, since the current forward path is fine for 2D and light 3D.Texture arrays / 3D textures.
TEXTURE_2D_ARRAYwould let the GPU tilemap sample one array instead of juggling several atlases, and would relieve the texture-unit pressure thatTextureCacheworks around today. Interacts with #1410 (renderer-agnostic texture cache) — worth designing together rather than separately.Transform feedback. Capture vertex-shader output into a buffer; the groundwork for GPU skinning and GPU particle simulation. Note #1404 already covers GPU-instanced particles by a different route.
What is left
With both concrete items done, this tracker holds only: #1508 (mesh instancing), the #1568 GL frame-globals variant (deferred by decision), and the three speculative items below — none of which are scheduled, and two of which (texture arrays, MRT) are worth designing against #1410 / the WebGPU backend rather than in isolation.
Notes
Unblocked by #1509.