ADR 0012: The stitch renders on WebGPU
Status: accepted (2026-10-19); superseded in part by ADR 0022 (how a decoded frame reaches a texture)
Context
The reference stitch (stitch/renderEquirectangular, ADR 0008) runs on the CPU, one output pixel at a time, which suits a preview but not full-resolution video: a 5.7K frame is 16 million directions, each projected through two lenses twice (ADR 0011). A browser stitcher needs the GPU. Two browser GPU APIs exist. WebGL2 is everywhere; WebGPU is in current Chrome, Edge and Safari and gives compute shaders and storage buffers, which the later seam work (multiband blending, an optical-flow seam) needs. A browser that stitches 360 already needs WebCodecs, so asking for WebGPU narrows support only a little.
Decision
- The renderer is a WGSL render pass in
packages/adapters/webgpu: a full-screen triangle whose fragments are the output pixels, applying the reference stitch to the numbers the core packs. No 3D library. - The core owns the contract.
stitch/packStitchreduces a frame (lens optics and image placement, the stabilization correction, gains, vignetting, and the rolling-shutter turn tabulated down the rows) to four-float slots laid out asSTITCH_LAYOUTstates. The shader reads only those numbers, so its maths is the core's, andoptics/lensPoseis shared so both project the same way. - Lens images are ordinary sampled textures, one per lens or one shared, sampled linearly with calibration-canvas pixels at texel centres. The stitch shader never samples an external texture: a decoded
VideoFramereaches one of these textures before the stitch runs, imported withimportExternalTextureand drawn onto it where the browser can, copied on the CPU and written withwriteTexturewhere it cannot (ADR 0022). One texture path keeps the shader testable outside a browser. - The shader is tested against the reference on a real GPU: the adapter's tests render synthetic lens images through Dawn's Node bindings (
webgpu, a dev dependency) and compare every output pixel torenderEquirectangularwith a bilinear sampler, for the plain stitch, gains, vignetting and rolling shutter. CI runs them on Mesa's software Vulkan driver.
Consequences
- The stitch needs WebGPU; in a browser without it opening a rendition fails (
render-unavailable), with no fallback renderer. - The shader works in single precision, so it takes the angle from the optical axis as
atan2of its sine and cosine (acoswould lose accuracy near the lens centre). Its output agrees with the reference to within 3 of 255 levels. - Between tabulated rows the rolling-shutter turn is interpolated; the turn varies smoothly over a readout, so a few dozen steps match the exact correction.
- A change to the packed layout changes
packStitch,STITCH_LAYOUTand the shader together; the GPU tests catch a mismatch.