perf(webgl): skip SDF buffer upload when text content is unchanged#91
Closed
chiefcll wants to merge 1 commit into
Closed
perf(webgl): skip SDF buffer upload when text content is unchanged#91chiefcll wants to merge 1 commit into
chiefcll wants to merge 1 commit into
Conversation
render() re-uploaded the entire used SDF vertex buffer via bufferData on every frame where any text existed, even when every text node took the cache-hit path and rewrote byte-identical data at identical offsets. On a text-heavy TV screen that is a guaranteed multi-hundred-KB driver copy per frame paid during every animation that doesn't touch text. The skip is safe because the dirty signal is derivable inside the renderer: the cache-hit path (addSdfCachedQuads) produces identical bytes as long as visit order and glyph counts are unchanged. Upload is forced when: - any cache-miss write ran (addSdfQuads: layout/transform/color/alpha change) - the render list was rebuilt (write order changed) - an RTT pass ran (RTT glyphs occupy the front of the shared buffer) - the backing buffer grew (storage replaced) - the used size differs from the last upload (contributor set changed) Context loss needs no handling: the engine's documented recovery is a full app reload (no webglcontextrestored path). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
|
Requires most nodes not to change. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Skips the per-frame
bufferDataupload of the shared SDF vertex buffer inrender()when the buffer's content is guaranteed identical to what the GPU already holds.Why
render()re-uploaded the entire used SDF buffer on every frame where any text existed — on a TV screen, that's every frame. A screen with a few hundred visible glyphs re-uploads tens-to-hundreds of KB at 60fps even when every text node is static, andbufferData(orphan-and-reallocate semantics) is the expensive call on the embedded driver stacks this engine targets. Any frame where images fade, focus rings animate, or colors pulse — but text holds still — paid this for nothing.How
The dirty signal is derived inside the renderer, with no scene-graph invalidation hooks: the cache-hit text path (
addSdfCachedQuads) writes byte-identical data at identical offsets as long as visit order and glyph counts are unchanged. A newsdfBufferChangedflag forces upload when any of these occur:addSdfQuads— layout/transform/color/alpha changed)invalidateQuadBuffer— write order changed)The decision is isolated in
shouldUploadSdfBuffer()for unit testing. Context loss needs no handling: the engine's documented recovery is a full app reload (nowebglcontextrestoredpath exists).The per-frame memcpys and
SdfRenderOprebuilds are unchanged — only the GL transfer is elided, which is where the cost lives. Canvas2D backend untouched (no SDF path).Testing
WebGlRenderer.sdfUpload.test.ts): first-frame upload, skip on unchanged content + matching size, forced upload on cache-miss write / size mismatch, growth and render-list invalidation hooks (tested viaObject.create(WebGlRenderer.prototype)— no GL context needed).pnpm buildclean; webgl + CoreNode suites 83/83.text-alignrenders crisp SDF paragraphs (skip path);stress-single-level-textanimates text continuously with intact glyphs (cache-miss re-upload path).🤖 Generated with Claude Code