Skip to content

feat(engine): render WebGPU compositions on SwiftShader behind an opt-in - #5133

Merged
miguel-heygen merged 5 commits into
mainfrom
feat/engine-software-webgpu
Oct 7, 2026
Merged

miguel-heygen merged 5 commits into
mainfrom
feat/engine-software-webgpu

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

What

An opt-in, off by default, that lets a host without a GPU render a composition declaring data-requires-webgpu: set PRODUCER_ALLOW_SOFTWARE_WEBGPU=true. Without it, such a render is refused exactly as today.

Why it works now

SwiftShader reports a WebGPU adapter, and #4091 refused it because a canvas drawn on it came out blank. Measured on a GPU-less Linux host with chrome-headless-shell 152 and 154: SwiftShader draws canvas WebGPU only through its Vulkan backend with GPU compositing on. The engine's software launch turns compositing off (--disable-gpu-compositing, the HF#3049 workaround), and then every draw fails with "A valid external Instance reference no longer exists." (or, with the Vulkan flags alone, a blank canvas).

So an opted-in launch, and only that launch:

  • adds Vulkan to --enable-features and --use-vulkan=swiftshader;
  • keeps GPU compositing on;
  • lets the adapter check accept the fallback adapter.

usesSoftwareWebGpu() is the one owner of that decision: the composition requires WebGPU, the render opted in, the GPU mode resolved to software, and disableGpu is off (SwiftShader cannot draw WebGPU at all under --disable-gpu). The Chrome flags and the capture session's adapter check both read it, so the launch and the check cannot disagree.

Verification

  • Producer renders on a GPU-less Linux host of WebGPU compositions built on the shaders npm library: every frame distinct, byte-identical across two runs and across 1 vs 2 workers; without the opt-in, the same refusal as before. Two of them match a Metal render of the same composition to about 1/255.
  • packages/engine: browserManager and config tests, plus a new frameCapture-softwareWebGpu.test.ts that drives the real createCaptureSession + initializeSession and asserts the launch flags and the adapter check's arguments with the opt-in on, off, and on a GPU. Three runs each; each of the eight one-line breaks of the decision or its wiring tried in review turns a test red (dropping the check entirely fails by test timeout).
  • Every non-opted-in launch is byte-identical to main (972 flag combinations compared in review).

Limits

  • Distributed renders: each chunk worker reads the engine config from its own environment, like every other engine setting, so every worker needs PRODUCER_ALLOW_SOFTWARE_WEBGPU=true. A programmatic allowSoftwareWebGpu: true (in-process or serialized) does not reach the chunks; a worker without the variable fails loudly with the same error, never renders blank.
  • hyperframes snapshot, layout, validate, check and Studio thumbnails keep refusing WebGPU compositions on software hosts.
  • Measured on Linux only; the opt-in is not limited to Linux, so on macOS and Windows it turns on a flag set nobody has measured there.
  • When opted in, the adapter check accepts the SwiftShader adapter, which reports the same values on a launch that would draw blank; today the flags and the check come from one decision, so that launch is not reachable.
  • The browser launch log does not say whether software WebGPU is on.
  • The HF#3049 compositor workaround is off for opted-in launches. The repo's regression fixture does not reproduce that ghosting on the pinned Chrome either way, so no test watches for it.
  • The refusal message suggests the variable even when it is already set but cannot apply (--browser-gpu, disableGpu).

Review

Independent adversarial review, one report per head. Final round at this head (dd6235c): no BLOCKERs, no MAJORs.

Head Findings Resolution
8ac0d4e MAJOR: distributed chunks ignore a programmatic opt-in; MAJOR: the capture-session wiring was untested; 5 MINOR (limits above) wiring test added; distributed and minors documented as limits
6afdbf6 MINOR: limits not yet in this body this body
dd6235c 3 MINOR: limits incomplete or imprecise in this body this body

PRODUCER_ALLOW_SOFTWARE_WEBGPU=true lets a host without a GPU render a
data-requires-webgpu composition instead of refusing it. SwiftShader can
draw canvas WebGPU only through its Vulkan backend with GPU compositing
on, so an opted-in software launch adds the Vulkan feature and
--use-vulkan=swiftshader, keeps compositing on, and the adapter check
accepts the fallback adapter. Off by default; every other launch is
unchanged.
@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Edit accuracy: accurate 2059 (base branch 2059), smooth 1489 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked at dd6235c.

  • With the opt-in off, nothing changes: usesSoftwareWebGpu needs requiresWebGpu, the flag on, no disableGpu, and software mode. The new test asserts byte-identical Chrome args for each case where it doesn't apply.
  • The launch and the adapter check agree. createCaptureSession computes softwareWebGpu from the same gpuConfig it passes to buildChromeArgs, and the check accepts a fallback adapter only then. A pooled browser can't be reused across the two shapes, because acquireBrowser keys the pool on the args fingerprint, and --use-vulkan=swiftshader / ,Vulkan change it.
  • The CLI callers (validate, layout, motionShot, snapshot capture, studio thumbnails) pass only browserGpuMode, so they keep the old launch and keep refusing a fallback adapter.
  • Dropping --disable-gpu-compositing on the opt-in path is documented as a tradeoff (the HF#3049 workaround is skipped), and the code comment says SwiftShader WebGPU needs GPU compositing.

Non-blocking:

  • WebGpuUnavailableError is shared with those CLI commands. hyperframes validate or layout on a no-GPU host will now tell the user to set PRODUCER_ALLOW_SOFTWARE_WEBGPU=true, which those commands ignore. The typegpu skill line reads the same way, next to "local capture commands". Scope the hint to renders, or pass the flag through to the CLI capture paths.
  • On the opt-in path, GSAP yoyo stale frames (HF#3049) can come back. Worth one line in the skill doc so someone who opts in knows why.

Rames

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 7, 2026
Merged via the queue into main with commit 4cf5cf9 Oct 7, 2026
165 of 166 checks passed
@miguel-heygen
miguel-heygen deleted the feat/engine-software-webgpu branch October 7, 2026 01:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants