You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(webgl)!: WebGL 2 only renderer + Vertex Array Objects (#1509)
Phase 0 of the WebGPU groundwork: drop the WebGL 1 path and give every
batcher an immutable vertex state, so the layout description stops being
re-issued per draw and starts looking like a pipeline descriptor.
BREAKING: the WebGL renderer now requires WebGL 2.
- `video.AUTO` falls back to the Canvas renderer on WebGL-1-only devices;
`video.WEBGL` throws there
- `preferWebGL1` setting and the `#webgl1` URL flag removed
- `device.isWebGLSupported()` probes for WebGL 2 — it now agrees with what
renderer construction actually requests (it probed WebGL 1 before, so
the gate and the context could disagree)
- `renderer.type` is always "WebGL2"; `renderer.WebGLVersion` deprecated
- corrections on ex-WebGL-1 configs: NPOT `repeat` genuinely tiles,
darken/lighten use true MIN/MAX, `createPattern()` accepts NPOT
- user shaders need NO changes: GLSL ES 1.00 compiles on WebGL 2 contexts
Vertex Array Objects:
- new `WebGLVertexState` (buffer/vertexstate.js, sibling of
WebGLIndexBuffer) owns the VAO lifecycle; its binding save/restore is
private, so no caller can half-apply the protocol
- built from a {attributes, stride, buffer, indexBuffer} descriptor — a
GPUVertexBufferLayout + arrayStride, so #1492 becomes a class swap
- batcher switches cost one bindVertexArray; steady-state frames issue
zero attribute-specification calls (19 at startup, 0 per frame after)
- the attribute-leak machinery is gone: state is swapped, not disabled
- custom shaders on a built-in batcher must declare that batcher's
attributes first, in layout order — warns once per shader on mismatch
- TMX GPU tilemap eligibility now uses `renderer.supportsShaderTileLayers`
(a backend capability flag) instead of a WebGL-version check
Tests: 6 new specs (vertex-state units, VAO state/call-counts/recreation/
contract/adversarial, teardown), the attribute-leak spec retired and its
invariant re-expressed, 4888 passing.
Closes#1509
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JvxaXQRgQn5AoR8DNkv6Wg
Copy file name to clipboardExpand all lines: packages/melonjs/CHANGELOG.md
+14Lines changed: 14 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,19 @@
1
1
# Changelog
2
2
3
+
## [20.0.0] (melonJS 2) - _unreleased_
4
+
5
+
### Changed (breaking)
6
+
-**The WebGL renderer is now WebGL 2 only** ([#1509](https://github.com/melonjs/melonJS/issues/1509)) — the WebGL 1 fallback path is removed. `renderer: video.AUTO` falls back to the Canvas renderer on WebGL-1-only devices; `renderer: video.WEBGL` throws there. **User shaders need no changes** — `ShaderEffect` bodies and raw `GLShader` sources (GLSL ES 1.00) compile unchanged on WebGL 2 contexts.
7
+
-`preferWebGL1` setting and the `#webgl1` URI flag are removed (`#webgl` / `#webgl2` are synonyms)
8
+
-`device.isWebGLSupported()` now probes for a WebGL **2** context — it finally agrees with what renderer construction actually requests (the gate probed WebGL 1 before, so the two could disagree)
9
+
-`renderer.type` is always `"WebGL2"` for the WebGL renderer; `renderer.WebGLVersion` is deprecated (always `2`)
10
+
- behavior corrections on ex-WebGL-1 configs: `repeat` wrap now genuinely tiles non-power-of-two textures (was clamp + warning), `"darken"` / `"lighten"` blend modes use true MIN/MAX equations (were silently downgraded to `"normal"`), and `createPattern()` accepts non-power-of-two sources (threw before)
11
+
- TMX GPU tilemap eligibility is now advertised through `renderer.supportsShaderTileLayers` (a backend capability flag) instead of a WebGL-version check
12
+
-**each `Batcher` now owns an immutable Vertex Array Object** built at init ([#1509](https://github.com/melonjs/melonJS/issues/1509)): vertex attribute layout is frozen once built, batcher switches cost a single `bindVertexArray` (steady-state frames issue zero attribute-specification calls, measured), and `Batcher.unbind()` no longer disables attribute arrays. Custom batchers inheriting `Batcher.init()`/`bind()` need no changes. Custom shaders hosted by a built-in batcher must declare that batcher's attributes first, in layout order (ShaderEffect-generated vertex shaders already comply) — a console warning fires on mismatch. `GLShader.setVertexAttributes` is no longer called by the engine (still public)
13
+
14
+
### Performance
15
+
-**Vertex Array Objects for every batcher** ([#1509](https://github.com/melonjs/melonJS/issues/1509)) — vertex attribute layout is specified once at init rather than on every batcher switch and every mesh flush, so steady-state frames issue **zero** attribute-specification calls. How much GL traffic this saves depends on how often a scene alternates batchers: a scene that stays on one batcher saves about 2 calls per frame, one mixing sprites, meshes and primitives about 40 — in both cases well under a millisecond. The structural benefit is the larger one: attribute-state leaks between batchers become impossible by construction.
* GPU tilemap) silently stop working under the Canvas fallback —
@@ -74,14 +75,20 @@ export type ApplicationSettings = {
74
75
scaleTarget: HTMLElement;
75
76
76
77
/**
77
-
* if true the renderer will only use WebGL 1
78
-
* @default false
79
-
*/
80
-
preferWebGL1: boolean;
81
-
82
-
/**
83
-
* a hint to the user agent indicating what configuration of GPU is suitable for the WebGL context. To be noted that Safari and Chrome (since version 80) both default to "low-power" to save battery life and improve the user experience on these dual-GPU machines.
84
-
* @default default
78
+
* A hint to the user agent about which GPU to use on multi-GPU systems
79
+
* (discrete vs integrated). Browsers generally favour the low-power GPU
80
+
* unless asked otherwise, to preserve battery life.
81
+
*
82
+
* - `"default"` — no hint; let the user agent decide.
83
+
* - `"low-power"` — prefer the integrated GPU.
84
+
* - `"high-performance"` — prefer the discrete GPU. Note that browsers
85
+
* only honour this for pages that handle context loss, since switching
86
+
* GPU can drop the context; melonJS registers those handlers itself,
87
+
* so the request is respected.
88
+
*
89
+
* The same hint (and the same values, minus `"default"`) is used by
90
+
* WebGPU's adapter request, so this setting is backend-neutral.
91
+
* @default "default"
85
92
*/
86
93
powerPreference: PowerPreference;
87
94
@@ -166,7 +173,7 @@ export type ApplicationSettings = {
166
173
* When `true` (default), eligible layers render via a single quad per
167
174
* tileset + a fragment shader doing per-fragment GID lookup, bypassing
168
175
* the per-tile draw loop entirely. Layers that don't qualify
// — emitted from the first TMX layer that hits it, so apps with
410
410
// no tilemap loaded stay quiet.
411
411
if(gpuAllowed){
412
-
if(elig.reason==="no-webgl2-renderer"){
413
-
if(!_warnedNoWebGL2Once){
414
-
_warnedNoWebGL2Once=true;
412
+
if(elig.reason==="no-gpu-renderer"){
413
+
if(!_warnedNoGpuTileSupportOnce){
414
+
_warnedNoGpuTileSupportOnce=true;
415
415
console.warn(
416
-
"melonJS: gpuTilemap is enabled but the active renderer is not WebGL 2 — falling back to the legacy tile renderer for every tile layer",
416
+
"melonJS: gpuTilemap is enabled but the active renderer has no GPU tile-layer support — falling back to the legacy tile renderer for every tile layer",
0 commit comments