ifcviewer: fix blank-until-interaction stall on web (streaming settle burst)

On first web load the sample stayed blank until a click/drag, then popped
in. Root cause: the main draw + cull run before driveStreamingLoads in
render(), so a chunk that becomes resident there is only painted a frame
later. On desktop the streaming thread keeps inFlightApprox() > 0 during a
load, so the render loop keeps ticking and the next frame paints it. On web
the sync MEMFS / Blob load finishes instantly (inFlightApprox stays 0), so
the single post-load requestFrame fired once and the on-demand loop went
idle before the geometry was ever drawn — until some input re-armed it.

Fix: arm a bounded settle burst (kStreamingSettleFrames) whenever there's
streaming activity — a load this frame, work still queued, or a visible
chunk not yet resident — and bleed it down over the next few frames, each
requesting one more. Covers the cull→display latency under an on-demand
loop and still quiesces at idle (no busy-rendering). General, not web-only.

Regression test: the sample must render with NO pointer input — a centred
patch (the framed cube) differs from a corner patch (background); a blank
stall leaves both as background. Verified empirically with a no-interaction
probe (canvas went from a static blank hash to a stable rendered one).
107/107 unit tests pass; 4/4 web smoke tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-06-30 10:11:58 +10:00
parent 2b58d7be74
commit 3cc759d72b
3 changed files with 70 additions and 1 deletions
+8
View File
@@ -873,6 +873,14 @@ private:
int streaming_loads_this_frame_ = 0;
bool streaming_more_pending_ = false;
// Settle burst: keep the render loop alive for a few frames after any
// streaming activity so the cull→load→display latency (the draw + cull
// precede driveStreamingLoads, so a freshly-resident chunk paints a frame
// later) flushes even under an on-demand render loop (web). Bounded, so
// the loop still quiesces when streaming is done. See driveStreamingLoads.
static constexpr int kStreamingSettleFrames = 4;
int streaming_settle_frames_ = 0;
// Per-frame breakdown counters consumed by the WGPU_STREAM_DEBUG
// log. All reset at the top of driveStreamingLoads.
int streaming_candidates_this_frame_ = 0;