Wire up wgpu init + scene load + RAF render so the embedded sample
sidecar paints on the canvas in both browsers.
Root-cause fix: BufferPool::addSubBuffer spin-waited on
PopErrorScope, which resolves via JS microtask on Dawn-web. The
spin blocked the JS event loop, so the microtask never fired and
the first allocation hung the page indefinitely. Skip the
error-scope dance on Emscripten; trust the buffer pointer.
ViewportCore: add initWgpuAsyncWeb (nested-callback adapter→device
chain with AllowSpontaneous mode, no spin) and loadSidecarFromPath
(Qt-free entry point). waitTickInstance becomes a no-op shim on
web; cull-threads / streaming_thread_ / wgpuSurfacePresent gated
off; chunk I/O runs inline.
main_web.cpp: AppState + initWgpuAsyncWeb → buildPipelines (+
HiZ/edge/pick) → loadSidecarFromPath → ready flag → Module._app_ptr
handoff. The RAF loop lives in shell.html (NOT here) because any
RAF helper called from inside Dawn-web's wgpu Promise.then chain
stalls the device callback.
CMakeLists.txt: EXIT_RUNTIME=0 + Module.noExitRuntime=true (shell)
keeps wasm alive past main() so the device promise lands; no
Asyncify; export _raf_tick_c so shell.html's RAF can call it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
First Emscripten target. main_web.cpp brings up a wgpu instance against
a <canvas id="viewer-canvas">, requests adapter+device asynchronously
via the standard webgpu.h callback chain, configures the surface, and
clears to the BonsaiViewer slate background on each RAF tick. No
sidecar load, no pipelines, no scene state yet — the goal is to end-
to-end verify the build + canvas + wgpu plumbing.
src/ifcviewer-web/ is a separate CMake root (not a subdir under the
desktop cmake/CMakeLists.txt) so the web build doesn't have to opt out
of Qt / OpenCASCADE / IfcGeom find_packages it can't satisfy. It adds
src/ifcviewer EXCLUDE_FROM_ALL and consumes only IfcViewerCore.
src/ifcviewer/CMakeLists.txt now gates the wgpu-native fetch + the
Qt-using IfcViewer target + install commands behind NOT EMSCRIPTEN.
The wgpu_native link target still resolves under Emscripten as an
INTERFACE library that activates --use-port=emdawnwebgpu (Dawn's
webgpu.h, replaces the legacy -sUSE_WEBGPU=1).
Build:
source path/to/emsdk_env.sh
emcmake cmake -S src/ifcviewer-web -B build-web -G Ninja
ninja -C build-web
python3 -m http.server --directory build-web 8080
# open http://localhost:8080/IfcViewerWeb.html in a WebGPU-capable
# browser (Chrome 113+, Edge 113+).
Phase B step 3 of #45.