WebGL2-only: max simultaneous framebuffer color attachments (multiple-render-target/deferred rendering).
WebGL2-only: max layers in a TEXTURE_2D_ARRAY (used by this engine's TextureArray/terrain atlasing).
Merged (Math.max()'d) across whichever of WebGL1/WebGL2 the probes in init() found --
informational only. A renderer doing an actual bounds-check against the units it can really
bind must use its own WEBGL1_.../WEBGL2_... variant below instead: WebGL2/GLES3 guarantees
more units than WebGL1/GLES2, so on a device where WebGL2 reports more, this merged value can
silently exceed what an actually-active WebGL1 context supports.
There is deliberately no WEBGPU_MAX_TEXTURE_IMAGE_UNITS sibling: "texture image units" (a
flat set of global slots bound via gl.activeTexture()) is a WebGL-only concept. WebGPU's
equivalent per-stage texture budget is WEBGPU_MAX_SAMPLED_TEXTURES_PER_STAGE below --
named after its own spec limit (maxSampledTexturesPerShaderStage) rather than this one,
since WebGPU's binding model (separate texture/sampler/bind-group/binding budgets) doesn't
map onto WebGL's texture-unit model.
WebGPU's own per-fragment-stage sampled-texture budget (maxSampledTexturesPerShaderStage)
-- the WebGPU counterpart to WEBGL1_.../WEBGL2_MAX_TEXTURE_IMAGE_UNITS above, deliberately
named and tracked separately rather than folded into MAX_TEXTURE_IMAGE_UNITS: that field is
Math.max()'d across WebGL1/WebGL2 probes taken unconditionally at init(), regardless of
which renderer ends up active, so a higher WebGL number can silently mask a lower real WebGPU
one (exactly how a 20-texture WebGPU bind group went undetected on a device whose WebGL2
context happened to report 32 units).
Supported numeric limits for hardware detection.