Skip to content

Tracking: WebGL 2 capabilities unblocked by the WebGL2-only baseline (#1509 scope C) #1556

Description

@obiot

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions