ifcviewer-web: fix three web-only init aborts

1) Async-wait spin loops in initWgpu / probeAndCreatePool / pick /
   screenshot finalize all called wgpuInstanceProcessEvents in a tight
   while. wgpu-native drives queued callbacks from there; Dawn-web
   queues the callback for an event-loop tick that never happens
   because wasm doesn't yield back to JS. Page hung at the first
   await (RequestAdapter) and Firefox flagged the tab as slow.

   New `waitTickInstance` helper calls emscripten_sleep(0) on
   Emscripten (Asyncify unwinds wasm, JS resolves WebGPU promises,
   resume) before wgpuInstanceProcessEvents drains completions into
   our callback. Desktop path is unchanged. All five
   `while (!done) ProcessEvents` sites switch to the helper.

2) streaming_thread_.start() inside initWgpu spawns a std::thread.
   On Emscripten that needs -pthread + COOP/COEP headers from the
   hosting page. None of that is wired yet, so the start is gated
   `#if !defined(__EMSCRIPTEN__)`. The sync chunk-load fallback
   already inside driveStreamingLoads carries the load until #88
   replaces it with emscripten_fetch.

3) wgpuSurfacePresent at the end of render() aborted with
   "wgpuSurfacePresent is unsupported (use requestAnimationFrame via
   html5.h instead)" — Dawn-web composites the canvas at the end of
   the RAF tick automatically. Call skipped on Emscripten;
   WebViewportHost::requestFrame is the RAF-tick driver.

Page now loads, brings up wgpu, configures the surface, and renders
one frame with the configured background. The frame log in the
status overlay shows the first-frame startup spike (~1000 fps from
a 1 ms tick); subsequent frames are paint-on-demand, which on the
empty scene means no frames at all — consistent with the desktop
event-driven model.
This commit is contained in:
Dion Moult
2026-06-06 21:28:27 +10:00
parent 1fc15e78f2
commit bb0e96b406
2 changed files with 59 additions and 10 deletions
+6 -3
View File
@@ -62,9 +62,12 @@ void main_loop(void* user) {
app->last_h = h;
}
// Only render when something has requested a frame — saves battery
// on the still-camera case. The initial frame request is armed by
// WebViewportHost's ctor so the canvas always paints once at startup.
// Only render when something has requested a frame — CPU stays
// idle while the scene is static. WebViewportHost's ctor arms one
// initial frame request so the canvas always paints at startup;
// subsequent paints come from core_.render() rearming itself
// (motion settle, streaming in flight, bench mode) and, once
// input is wired (#85), from mouse / key events flagging the host.
if (app->host.consumeFrameRequest()) {
app->core.render();
}