Skip to content

Extract renderer-agnostic buffer classes from WebGL layer#1414

Merged
obiot merged 8 commits intomasterfrom
refactor/buffer-abstraction
Apr 23, 2026
Merged

Extract renderer-agnostic buffer classes from WebGL layer#1414
obiot merged 8 commits intomasterfrom
refactor/buffer-abstraction

Conversation

@obiot
Copy link
Copy Markdown
Member

@obiot obiot commented Apr 22, 2026

Summary

  • VertexArrayBuffer: moved from video/webgl/buffer/ to video/buffer/ — zero GL dependency, pure typed array management. Usable by a future WebGPU batcher.
  • IndexBuffer: split into renderer-agnostic IndexBuffer base class (data accumulation, quad index patterns) and WebGLIndexBuffer subclass (GL buffer creation, bind, upload).

Part of #1410. The TextureCache unit management refactoring is deferred pending investigation of a rendering regression with per-sprite shader effects.

Test plan

  • 236 tests pass (vertexBuffer, drawVertices, texture, renderable, camera)
  • Platformer example renders correctly
  • Shader effects example renders correctly
  • No rendering regressions

🤖 Generated with Claude Code

obiot and others added 7 commits April 21, 2026 16:35
…et architecture (#1396)

Replace the single `shader` property on Renderable with a `postEffects` array
supporting multiple shader effects applied in sequence via FBO ping-pong.
Single-effect renderables use a zero-overhead customShader fast path (no FBO).

Introduce an abstract `RenderTarget` base class with `WebGLRenderTarget` and
`CanvasRenderTarget` implementations, and a renderer-agnostic `RenderTargetPool`
using a factory pattern — ready for future WebGPU support.

Extract direct GL state calls from the post-effect pipeline into renderer methods
(setViewport, clearRenderTarget, enableScissor, disableScissor, setBlendEnabled),
all no-ops on the base Renderer, implemented on WebGLRenderer.

Fix WebGL texture unit corruption during FBO resize by explicitly using TEXTURE0.
Fix projection matrix not being saved/restored across post-effect passes.
Fix Canvas renderer not syncing customShader in save/restore.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Clear customShader when no enabled effects or entering FBO path (prevents shader leak to children)
- Reset _activeBase/_previousBase in RenderTargetPool.destroy()
- Guard against nested sprite post-effect passes in RenderTargetPool.begin()
- Handle null blob in toBlob() callbacks (reject instead of resolving null)
- Restore toImageBitmap() fast path on CanvasRenderTarget using createImageBitmap(canvas)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a public `colorMatrix` property to Camera2d — a built-in ColorMatrix
that is always applied as the final post-processing pass, after any effects
added via addPostEffect(). Zero overhead when identity (default).

The effect is transient: pushed to postEffects before beginPostEffect and
removed after endPostEffect each frame. Camera2d uses only the public
ColorMatrixEffect API (reset + multiply), no internal shader knowledge.

Also fix FileReader error handling in RenderTarget.toDataURL().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Save/restore active texture unit in WebGLRenderTarget constructor and resize()
  to keep the batcher's currentTextureUnit cache in sync (TEXTURE0 fix preserved)
- Handle null 2d context in RenderTarget.toBlob() fallback paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolve conflicts: keep colorMatrix property, Copilot review fixes
(active texture save/restore, null context handling).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
onloadend fires on success, error, and abort — could resolve with null.
onload only fires on success. Also handle onabort explicitly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move VertexArrayBuffer from video/webgl/buffer/ to video/buffer/
  (zero GL dependency — pure typed array management)
- Split IndexBuffer into renderer-agnostic IndexBuffer base class
  (data accumulation, quad patterns) and WebGLIndexBuffer subclass
  (GL buffer creation, bind, upload)
- Update all imports in batchers and tests

Part of #1410 (TextureCache + Batcher abstraction). The TextureCache
unit management refactoring is deferred pending investigation of a
rendering regression with per-sprite shader effects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 22, 2026 07:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR advances the renderer-agnostic rendering architecture by extracting typed-array buffer management out of the WebGL layer, while also adding a built-in camera color-grading matrix and tightening some render target / image-export edge cases.

Changes:

  • Moved VertexArrayBuffer out of video/webgl/ into a renderer-agnostic video/buffer/ location and updated call sites/tests.
  • Split index buffering into a renderer-agnostic IndexBuffer (data accumulation/patterns) and a WebGLIndexBuffer (GL bind/upload), and updated the WebGL batcher to use it.
  • Added Camera2d.colorMatrix (implemented via a transient ColorMatrixEffect post-effect) and improved WebGL render target texture-unit state preservation and RenderTarget blob/dataURL error handling.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/melonjs/tests/vertexBuffer.spec.js Updates VertexArrayBuffer import path to new renderer-agnostic location.
packages/melonjs/tests/drawVertices.spec.js Updates VertexArrayBuffer import path to new renderer-agnostic location.
packages/melonjs/tests/camera.spec.js Adds tests around Camera2d.colorMatrix lifecycle and interaction with user postEffects.
packages/melonjs/src/video/webgl/buffer/index.js Converts WebGL index buffer into WebGLIndexBuffer subclass of renderer-agnostic IndexBuffer.
packages/melonjs/src/video/webgl/batchers/batcher.js Updates imports and instantiation to use new buffer locations/classes.
packages/melonjs/src/video/rendertarget/webglrendertarget.js Preserves/restores active texture unit during texture creation/resizing to reduce GL state desync.
packages/melonjs/src/video/rendertarget/rendertarget.ts Improves null-context handling and FileReader error/abort handling for toBlob/toDataURL.
packages/melonjs/src/video/buffer/vertex.js Updates docstring for renderer-agnostic vertex array buffer.
packages/melonjs/src/video/buffer/index.js Introduces renderer-agnostic IndexBuffer for index data accumulation/pattern generation.
packages/melonjs/src/camera/camera2d.ts Adds colorMatrix and transient internal ColorMatrixEffect integration in draw() + cleanup in destroy().
packages/melonjs/CHANGELOG.md Documents new Camera.colorMatrix and the buffer refactor.
packages/examples/src/examples/platformer/play.ts Updates platformer example to use viewport.colorMatrix instead of adding a ColorMatrixEffect.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/melonjs/src/video/webgl/buffer/index.js
Comment thread packages/melonjs/src/camera/camera2d.ts
Comment thread packages/melonjs/src/camera/camera2d.ts
Comment thread packages/melonjs/src/camera/camera2d.ts
Comment thread packages/melonjs/CHANGELOG.md
The dynamic flag was stored but never used — upload() always used
STREAM_DRAW regardless. Removed dead code per Copilot review.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@obiot obiot merged commit d920c9f into master Apr 23, 2026
6 checks passed
@obiot obiot deleted the refactor/buffer-abstraction branch April 23, 2026 00:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants