Skip to content

feat: upload tilemap and text vertices only when they change - #66

Draft
maurocristy87 wants to merge 1 commit into
mainfrom
feature/webgl-vertex-buffer-cache
Draft

maurocristy87 wants to merge 1 commit into
mainfrom
feature/webgl-vertex-buffer-cache

Conversation

@maurocristy87

Copy link
Copy Markdown
Member

Rendering

Vertex buffers per render data — TilemapRenderer and TextRenderer no longer share a single pair of buffers re-uploaded on every draw. Each render data owns its position and texture buffers, kept in a WeakMap keyed by the render data, so drawing the same tilemap chunk or text again (every frame, or once per camera) reuses the vertices already on the GPU. The attributes are bound on every draw, since consecutive draws of the same renderer now use different buffers.

Vertices are regenerated only when their inputs change — the inputs are compared by value against a snapshot taken when the vertices were generated:

  • Tilemap: the tileset, its texture data, the tilemap width, and every tile id (the engine reuses the same render data and tiles can be edited in place). Animated tiles are compared only for the chunks that contain them, so chunks without animated tiles stay untouched while the animation plays. The tile snapshot is a Float64Array, so Tiled ids carrying the flip flags in their high bits are stored exactly.
  • Text: the text, font, font size, letter spacing, line height, alignment, bounding box size and font atlas. Color, opacity, position, rotation, flip and shadow do not affect the vertices and do not trigger a rebuild. The shadow is drawn with the vertices of the main text.

No per-frame allocation for the vertices — they are written into scratch Float32Arrays that grow only when needed, and uploaded with subarray instead of wrapping a new Float32Array on every draw.

GPU memory is released when the render data is collected — a FinalizationRegistry deletes the buffers of a render data once it is garbage collected. The release happens whenever the browser collects, not right when the entity is removed.

Texts with nothing to draw — a text whose layout produces no glyph returns without drawing, like an empty tilemap pass, instead of issuing a draw call with zero vertices.

Measurements

bufferData calls per frame in a static scene, before and after:

Scene Before After
demos/dev, tilemap 12 0
demos/dev, text 4 0 (only when the FPS text changes)
Test scene, 3 tilemap chunks, 2 cameras 24 0
Test scene, 3 texts (one with shadow) 6 0

Animated tiles, runtime tile edits, text content, font size and alignment changes upload once and go back to zero. Screenshots of the test scene match the previous renderer in every step, on WebGL2 and on the legacy WebGL1 path.

@coderabbitai

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Base automatically changed from release/2.4.0 to main October 3, 2026 15:38
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.

1 participant