Expand description
WASM target support for browser-based GPU compute via WebGPU.
This module is conditionally compiled on wasm32 targets (or when the wasm
feature is enabled for native testing) and provides browser-friendly wrappers
around the wgpu WebGPU backend.
§Architecture
+-------------------------------------------+
| JavaScript / Browser |
+-------------------+-----------------------+
|
+-------------------v-----------------------+
| WasmGpuDevice / WasmBackend (wasm32) |
+-------------------+-----------------------+
| delegates to
+-------------------v-----------------------+
| WebGpuBackend (wgpu web-sys backend) |
+-------------------------------------------+§Usage
The WasmBackend wraps the existing WebGpuBackend
and adds browser-specific initialisation methods such as
init_from_canvas.
The WasmMemoryManager provides async-friendly buffer staging suited to the
browser event loop.
§Known limitation: WasmBackend does not actually use WasmMemoryManager
Despite the name, every WasmBackend compute and memory operation
forwards to WebGpuBackend, which is backed by
WebGpuMemoryManager — not by
WasmMemoryManager in this module. WasmMemoryManager (and
WasmGpuDevice) exist, are async-safe, and are unit-tested, but nothing
in WasmBackend constructs or calls them. This matters because:
WebGpuBackend’s compute methods end in a blockingDevice::poll(PollType::wait_indefinitely())(seebackend.rs), andWebGpuMemoryManager::copy_from_device’s readback blocks on anmpsc::channelrecv()that only resolves once that same poll drives themap_asynccallback to completion. On the single-threaded browser main thread,Device::pollcannot make progress without yielding back to the event loop that would deliver that callback — so this would deadlock the tab, exactly the failureWasmMemoryManager::copy_dtoh’s own#[cfg(target_arch = "wasm32")]guard (in this file) already exists to prevent, just on the wrong type.- Fixing this by swapping
WasmBackend’s memory calls (alloc,copy_htod,copy_dtoh) over toWasmMemoryManagerwhile leaving the compute calls (gemm,unary, …) onself.inner: WebGpuBackendis not a valid partial fix: the two memory managers keep independentHashMap<u64, Buffer>handle tables, each with its ownnext_handle/AtomicU64counter starting at 1. A buffer allocated throughWasmMemoryManagerwould not exist inWebGpuMemoryManager’s map (or worse, its handle number would collide with an unrelatedWebGpuMemoryManagerbuffer), so every compute call would either fail with “unknown handle” or silently operate on the wrong buffer. Correctly fixing this requiresWasmBackendto own one coherent device + buffer table end-to-end and give every compute dispatch (not just readback) an async, non-blocking form — a genuine rework of this module andbackend.rstogether, out of scope here.
Until that rework lands: WasmBackend is appropriate for native
testing of the WASM code paths (via the wasm feature, where blocking
is safe) and for non-browser wasm32 hosts (e.g. a WASI runtime driving
its own event loop outside a browser tab). On an actual browser main
thread, treat every WasmBackend compute/readback call as unsafe to call
synchronously; WasmMemoryManager::copy_dtoh_async is the
already-implemented pattern a real async rework would extend to the rest
of the surface.
§Deeper pre-existing gap: this crate does not compile for wasm32-unknown-unknown at all
cargo check -p oxicuda-webgpu --target wasm32-unknown-unknown fails
today (independent of anything in this module): oxicuda_backend:: ComputeBackend requires Send + Sync, but on the real wasm32 target
wgpu’s WebGPU backend represents Device/Buffer using Rc/RefCell
internally (browser JS handles are not thread-safe), which makes
WebGpuDevice/WebGpuBufferInfo — and therefore WebGpuBackend, which
every WasmBackend method forwards to — not Send. So WasmBackend
(and WebGpuBackend) cannot implement ComputeBackend on that target
today at all; this is a compile error, not a runtime one, so nothing in
this crate has ever actually run compiled-for-wasm32. Fixing it needs
either a ?Send carve-out on ComputeBackend for wasm32 (a change to
oxicuda-backend, out of scope for this crate) or a non-ComputeBackend
wasm32-native entry point built directly on WasmGpuDevice; both are
part of the same async rework noted above.
Structs§
- Wasm
Backend - WebGPU compute backend for WASM (browser) targets.
- Wasm
GpuDevice - A WebGPU device obtained from the browser’s
navigator.gpuAPI. - Wasm
Memory Manager - Browser-side buffer manager that uses async
map_asyncstaging.
Functions§
- request_
adapter - Request a WebGPU adapter from the browser.