Add multi-texture batching for WebGL renderer (#1376)#1389
Add multi-texture batching for WebGL renderer (#1376)#1389
Conversation
- Change failIfMajorPerformanceCaveat default to false — allows WebGL on machines with blocklisted GPU drivers, matching PixiJS/Phaser - Guard getSupportedCompressedTextureFormats() against null GL context - Fix compressed textures example text rendering (Text.draw standalone removed in 19.0) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates melonJS’ WebGL initialization defaults and improves robustness around compressed texture format detection, along with an example update and a package version/changelog bump.
Changes:
- Guard
WebGLRenderer.getSupportedCompressedTextureFormats()against missing GL context. - Change default
failIfMajorPerformanceCaveattofalseinCanvasRenderTargetattributes. - Bump
melonjspackage version to19.1.0and add19.1.0changelog entries; update the compressed textures example to thesetText()+preDraw/draw/postDrawpattern.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/melonjs/src/video/webgl/webgl_renderer.js | Adds a null/undefined GL context guard for compressed texture extension probing. |
| packages/melonjs/src/video/rendertarget/canvasrendertarget.js | Changes default WebGL context creation attribute failIfMajorPerformanceCaveat. |
| packages/melonjs/package.json | Version bump to 19.1.0. |
| packages/melonjs/CHANGELOG.md | Adds 19.1.0 entry describing the WebGL changes and example fix. |
| packages/examples/src/examples/compressedTextures/ExampleCompressedTextures.tsx | Updates text rendering to explicit setText() + renderable draw lifecycle calls. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| font.setText(text); | ||
| font.pos.set(x, y); | ||
| font.preDraw(renderer); | ||
| font.draw(renderer); | ||
| font.postDraw(renderer); |
There was a problem hiding this comment.
drawText() calls font.setText() on every draw, which forces a full re-measure, canvas re-render, and WebGL texture invalidation even when the text hasn’t changed. For an example that redraws every frame, consider caching the last text/position per Text instance and only calling setText() (and rebaking) when the string or coordinates change, or restructure this as persistent Text children updated in update().
| const gl = this.gl; | ||
| if (typeof gl === "undefined" || gl === null) { | ||
| // WebGL context not available | ||
| return super.getSupportedCompressedTextureFormats(); |
There was a problem hiding this comment.
getSupportedCompressedTextureFormats() now falls back to super.getSupportedCompressedTextureFormats() when this.gl is unavailable, but the base implementation returns null values. hasSupportedCompressedFormats() (both here and in the base Renderer) iterates with for..in over each entry and will throw if any are null. Consider returning an object with empty objects instead of nulls for the fallback, and/or guard in hasSupportedCompressedFormats() by skipping falsy entries before iterating.
| return super.getSupportedCompressedTextureFormats(); | |
| supportedCompressedTextureFormats = { | |
| astc: {}, | |
| bptc: {}, | |
| s3tc: {}, | |
| s3tc_srgb: {}, | |
| pvrtc: {}, | |
| etc1: {}, | |
| etc2: {}, | |
| }; | |
| return supportedCompressedTextureFormats; |
| stencil: true, | ||
| blendMode: "normal", | ||
| failIfMajorPerformanceCaveat: true, | ||
| failIfMajorPerformanceCaveat: false, |
There was a problem hiding this comment.
Changing defaultAttributes.failIfMajorPerformanceCaveat here won’t change the default behavior for normal engine initialization because defaultApplicationSettings.failIfMajorPerformanceCaveat is still true and is passed into CanvasRenderTarget via Renderer options. Either update the application defaults as well (and any related docs), or keep this attribute consistent to avoid a misleading/ineffective default.
| failIfMajorPerformanceCaveat: false, | |
| failIfMajorPerformanceCaveat: true, |
| ## [19.1.0] (melonJS 2) - _2026-04-15_ | ||
|
|
||
| ### Changed | ||
| - WebGL: `failIfMajorPerformanceCaveat` default changed from `true` to `false` — allows WebGL context creation on machines with blocklisted GPU drivers or software renderers, matching PixiJS and Phaser behavior |
There was a problem hiding this comment.
The changelog claims the default failIfMajorPerformanceCaveat changed from true to false, but in this PR only CanvasRenderTarget defaults changed—defaultApplicationSettings.failIfMajorPerformanceCaveat remains true, so typical Application initialization will still request true. Either update the application default (and/or device docs) to match, or adjust this changelog entry to describe the actual behavior change (e.g., only affects direct CanvasRenderTarget creation without explicit options).
| - WebGL: `failIfMajorPerformanceCaveat` default changed from `true` to `false` — allows WebGL context creation on machines with blocklisted GPU drivers or software renderers, matching PixiJS and Phaser behavior | |
| - WebGL: direct `CanvasRenderTarget` creation now defaults `failIfMajorPerformanceCaveat` to `false` when not explicitly provided — allows WebGL context creation on machines with blocklisted GPU drivers or software renderers; `Application` initialization behavior is unchanged unless this option is set explicitly |
| ## [19.1.0] (melonJS 2) - _2026-04-15_ | ||
|
|
There was a problem hiding this comment.
PR title/description and linked issue describe multi-texture WebGL batching changes, but the changes shown in this PR are a version bump + WebGL context option default + compressed texture support/example fixes. Please reconcile the PR metadata (title/description) with the actual changes, or ensure the batching-related commits/files are included.
Summary
Multi-texture batching allows up to 16 textures to be drawn in a single batch/draw call, eliminating flushes on texture changes.
Changes
shaders/multitexture.js— dynamically generates vertex/fragment shaders with per-texture sampler uniforms and if/else selection chainbuffer/vertex.js— newpushTextured(x, y, u, v, tint, textureId)method (6 floats per vertex)material_batcher.js— newuploadTextureMulti/bindTexture2DMultinon-flushing methodsquad_batcher.js— uses generated multi-texture shaders, embeds texture unit index in vertex data, falls back to single-texture when custom ShaderEffect is activeBackward compatible
drawImage()API unchangedShaderEffect/GLShader— when active, single-texture fallback kicks in automaticallySpineBatcher,MeshBatcher,PrimitiveBatcher— unaffectedquad.vert/quad.frag— unchanged (used by ShaderEffect fallback)Test plan
Closes #1376
🤖 Generated with Claude Code