Skip to content

Fix one-frame latency when a canvas texture feeds a same-frame consumer#1777

Merged
bghgary merged 3 commits into
BabylonJS:masterfrom
bghgary:viz-gui-unicode-await-revisions
Jul 13, 2026
Merged

Fix one-frame latency when a canvas texture feeds a same-frame consumer#1777
bghgary merged 3 commits into
BabylonJS:masterfrom
bghgary:viz-gui-unicode-await-revisions

Conversation

@bghgary

@bghgary bghgary commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Context

The two GUI unicode viz tests were pinned to old playground revisions with renderCount: 50 settle frames. BabylonJS/Babylon.js#18506 re-saved them as awaiting #1 revisions and dropped the settle frames on the Babylon.js side. Adopting the #1 revisions on Native isn't enough to drop renderCount — the settle frames masked a Native rendering bug, independent of #18506.

Root cause

updateDynamicTexture flushes a GUI AdvancedDynamicTexture's NativeCanvas (nanovg), then copies the canvas render target into the ADT texture via NativeEngine::CopyTexture (a bgfx::blit). The fullscreen ADT layer samples that texture during the scene/backbuffer render.

CopyTexture scheduled the blit on PeekNextViewId(), which — once the backbuffer view was already acquired — placed the blit on a view id after the view that samples the destination. bgfx runs blits in numeric view-id order, so the layer sampled the previous frame's canvas: a one-frame latency (blank first frame; for Parse, red buttons + broken emoji). renderCount: 50 just rendered past it.

Trace of one ADT frame, before: canvas view 0-7, backbuffer + layer view 8, blit view 9 — blit runs after the layer.

Fix

Context::Flush reserves the blit's view id right after the canvas draws (before the scene render is recorded) and hands it to the source texture; CopyTexture uses it. Non-canvas copies keep the PeekNextViewId() fallback (preserves #1683).

After: canvas view 0-7, blit view 8, backbuffer + layer view 9 — same-frame. General to Native GUI, not just these two tests.

Changes

  • NativeEngine.cpp, Context.cpp, Canvas.{h,cpp}, Texture.h: reserve and thread the blit view id.
  • config.json: adopt #YS93KY#1 / #ERVGT5#1, drop renderCount from both.

Both tests pass at the default renderCount: 1 on Win32 D3D11, including the ASAN sanitizer viz run.

[Created by Copilot on behalf of @bghgary]

Follow-up to BabylonJS/Babylon.js#18506, which fixed the two GUI unicode
visualization playgrounds to return Promise<Scene> from createScene (the old
revisions fire-and-forget parseFromSnippetAsync / parseFromURLAsync, racing the
screenshot), re-saved them as new revisions, and dropped the renderCount: 50
settle-frame workaround on the Babylon.js side.

The Native viz runner already awaits the promise returned by createScene, so move
to the awaiting revisions and drop the same workaround here:
- Load GUI snippet with unicode: #YS93KY#0 -> #YS93KY#1
- Parse GUI json with unicode:   #ERVGT5#0 -> #ERVGT5#1
- Remove renderCount: 50 from both (no longer needed now that setup is awaited)

Same playground content, so the reference images are unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 21:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates Babylon Native’s Playground validation configuration to use the newer GUI Unicode visualization playground revisions that properly return Promise<Scene> from createScene, allowing the native runner to wait for scene setup and removing the need for a frame-settle workaround.

Changes:

  • Bump the two GUI Unicode visualization tests to newer playground revisions (#0#1).
  • Remove the renderCount: 50 workaround from those two tests.

bghgary and others added 2 commits July 9, 2026 16:44
CI showed the "Load GUI snippet with unicode" viz test fails without the settle
frames: that GUI includes an async color-emoji image load that Babylon Native
does not finish within a single frame (the button colors also haven't settled),
so the emoji renders broken and the buttons render red. Babylon.js completes it
fast enough, which is why #18506 could drop the settle frames there.

Retain renderCount on that test; the "Parse GUI json with unicode" test has no
image load and passes with the awaiting revision and no settle frames.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeEngine::CopyTexture scheduled the canvas->texture blit on
PeekNextViewId(). Once the scene/backbuffer view had already been acquired,
that placed the copy on a view id AFTER the view that samples the
destination. bgfx processes blits in numeric view-id order, so a fullscreen
GUI AdvancedDynamicTexture layer sampled the previous frame's canvas content
— a one-frame GUI latency (blank/stale first frame). The viz suite masked
this by pinning the GUI unicode tests to large renderCount settle frames.

Reserve the blit's view id in Context::Flush, immediately after the canvas
draws but before the scene/backbuffer render is recorded, and hand it to the
source texture so CopyTexture blits on a view ordered after the canvas Flush
yet before the consuming view. Non-canvas copies keep the PeekNextViewId()
fallback, preserving BabylonJS#1683's multi-canvas ordering fix.

Drop the now-unnecessary renderCount from the two GUI unicode viz tests;
with the fix they render correctly on the first frame.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bghgary bghgary changed the title Use properly-awaiting playground revisions for GUI unicode viz tests Fix one-frame latency when a canvas texture feeds a same-frame consumer Jul 13, 2026
@bghgary
bghgary merged commit af97986 into BabylonJS:master Jul 13, 2026
29 checks passed
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.

3 participants