Repository navigation
fix(engine): say why WSL renders fall back to software and how to get the GPU - #5560
Conversation
… the GPU Under WSL the GPU check often falls back to SwiftShader and the only output was the probe line, with Docker passthrough advice for --browser-gpu. Print one note that says what was checked (can this user open the render node), the exact fix, and the native Windows alternative. The CLI's WSL detector moves to the engine so both use one. Part of #5548
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
terencecho
left a comment
There was a problem hiding this comment.
REQUEST CHANGES — the WSL diagnostic conflates probe failure with the selected render mode.
Reviewed exact HEAD aaf712787732804b50193cd493682c1ecef07e79. API base: ab8a4da53f31653350632980fa63cb07e957f0f6; effective Git/GitHub merge-base: 6f76b306751fdab465d9c6702228b119edd8ce30. Complete effective scope: one commit, ten files, +278/−20.
1. [P2] Preserve probe-failure uncertainty and the actual requested render mode
browserManager.ts:578–587,657–673 now prints the same WSL fallback note for both a completed software result and every caught probe error. The WSL warning branch then runs before cause === "probe-error" and says the probe “found no usable GPU,” replacing the existing unverified/Chrome-install/hyperframes doctor guidance. For example, a WSL --browser-gpu invocation with a bad Chrome path produces a launch failure, not evidence that its GPU is absent. The raw error line remains visible; the regression is the contradictory diagnosis and wrong remediation that follow it.
The same note unconditionally says “this render uses software WebGL (SwiftShader)” in wslHost.ts:54–56, but the explicit-hardware caller still returns "hardware" (browserManager.ts:623–635). The real capture path passes that result into buildChromeArgs (frameCapture.ts:1290–1294,1327–1331); Linux hardware arguments remain gl-egl plus --disable-software-rasterizer, not the SwiftShader arguments. A probe timeout therefore does not establish either a missing GPU or a software render; this matters especially for the slow-but-capable WSL hardware described in the PR body.
Keep the useful WSL permission observation, but distinguish probe result, probe failure/timeout, and selected render mode. Preserve the Chrome/probe-error remediation, describe explicit hardware as unverified when appropriate, and reserve the definite SwiftShader-fallback sentence for a caller that actually selects software. Add a WSL launch-error and explicit-hardware timeout regression that checks the absence of these false claims; do not change the explicit-hardware selection merely to make the wording true.
Additional [P3] diagnostic cleanup — not a separate merge hold
Do not infer missing render-group membership from an access failure.
wslHost.ts:27–33,61–66 checks only accessSync(R_OK | W_OK), catches every error, and reports “not in the "render" group” with usermod as the fix. No group membership, device ownership, mode or error reason is checked.
A non-root user already in render with a root:render node whose mode is 0600 still fails this predicate. Restrictive ACLs can do the same. The new diagnostic falsely identifies missing membership and recommends adding a group the user already has, which cannot repair that denial. That is an introduced wrong diagnosis for configured/nonstandard device permissions, not evidence of a default Ubuntu regression. I am not making this edge case a separate merge hold or asking for a general driver/permission repair system.
Report the observed read/write access denial and make render-group membership a possible cause/conditional suggestion, or verify membership before asserting it. Align the troubleshooting wording and tests with that narrower evidence. Also describe this as an access check rather than an actual device-open test: the production implementation does not call open.
Coverage and evidence bounds
The detector migration, retained CLI detectWSL alias, engine source/published subpath declarations and CLI bundle alias are coherent. The existing cached probe Promise and warning latch retain once-per-process behavior; explicit software still bypasses probing and a successful hardware probe stays quiet. No source blocker was identified in those paths.
The new assertions cover the three injected render-node states and WSL note routing, but encode the unverified group assertion. The test named as a timed-out probe rejects launch immediately; it does not exercise the real 15-second page deadline. The new explicit-hardware assertion checks only the warning, not the false SwiftShader sentence on stderr. Existing generic/Docker/probe-error warning tests supply a platform override but no non-WSL host facts, so their expectations also become dependent on the machine's actual WSL detector; make those fixtures deterministic when extending this coverage.
Audited: the complete ten-file effective diff; immutable changed-file blob reconciliation; current PR/commit prose and exhausted review/comment histories; independent browser/control-flow and WSL-contract/packaging source lenses. Parent independently read the new helper/tests, changed package/CLI declarations, browser probe/warning/cache and relevant test sources, documentation hunks, the pre-change failure branch, and real capture/launch-mode witnesses. Unchanged dependency files were reviewed selectively, not exhaustively.
Trusting / not exercised: author-reported engine/CLI checks, repeated local runs and real WSL/Windows/Intel measurements. I did not run repository tests, Chrome/GPU/native fixtures, usermod, wsl --shutdown, installs, builds or CI reruns; no source/configuration fixes, deployment/release triggers or merge were performed. These findings are source-backed diagnostic regressions, not a hold for missing native evidence or pending CI. Home retains merge ownership.
— tai
The WSL note now prints only when auto mode really selects software, and says whether the GPU check found no GPU or could not finish. Explicit --browser-gpu keeps its unverified and Chrome-install advice and adds the WSL checks. The render-node check verifies group membership before suggesting usermod.
|
Thanks, both findings were right. Fixed at 20f45bd: P2, probe result vs render mode. The probe now only records the WSL checks with its outcome; it prints nothing itself. The "this render uses software WebGL (SwiftShader)" note prints only from the auto-mode caller, which is the only one that selects software, and its first line says either "found no hardware GPU" (probe ran) or "could not finish" (probe failed or timed out). Explicit P3, group membership. The check now reads the node's owning gid and the process groups. Determinism. The existing Linux/macOS warning tests now pass a non-WSL host. Re-checked on the WSL2 machine at this head: auto prints the "could not finish" note with the fix; |
terencecho
left a comment
There was a problem hiding this comment.
APPROVE — the prior diagnostic findings are repaired at this head; no introduced blocker found.
Reviewed exact HEAD 20f45bd04f28e4046550e24606c8b6b5e7de89c3. API base: ab8a4da53f31653350632980fa63cb07e957f0f6; independently verified Git/GitHub merge-base: 6f76b306751fdab465d9c6702228b119edd8ce30. Complete effective scope: two commits, ten files, +420/−32.
The P2 in my previous review is fixed:
browserManager.ts:624–642,654–695prints the definite SwiftShader sentence only when auto actually selects software. A completed no-GPU result and a failed/timed-out probe now have different wording. Explicit hardware remains hardware; probe errors retain UNVERIFIED, the underlying Chrome/probe explanation andhyperframes doctor, with WSL observations appended as another possible cause rather than proof of a missing GPU.- The real capture path still forwards that returned selection to Chrome arguments (
frameCapture.ts:1290–1294,1327–1333;browserManager.ts:1138–1175). The fix does not change requested hardware to make its prose true. - The additional P3 membership issue is also repaired:
wslHost.ts:40–51,81–94reads the node's owning group and process groups, and suggestsusermodonly for access denial and absent membership. Already-in-group denial instead reports the observed denial and points to permissions. This is a bounded diagnostic, not a universal mode/ACL/driver repair promise.
Source-inspected regressions now reach the real page-probe deadline with fake timers, separately cover Chrome launch rejection and explicit hardware, and check that stderr does not claim software in hardware mode. The in-group-denied test rejects an unnecessary usermod suggestion; generic Linux/macOS fixtures explicitly supply non-WSL host facts. The shared cached probe and separate per-mode logging latches remain coherent for concurrent auto/hardware callers. Detector migration, the CLI detectWSL alias, source/published engine subpaths, bundle alias and documentation align.
Audited: all ten effective-diff files; current PR and full commit/review/comment prose; independently reconciled all changed-file blobs and actual merge-base; a finite independent source audit plus parent verification of diagnostics, regressions and actual capture/launch consumers. Unchanged dependencies were inspected selectively.
Trusting / not exercised: author-reported tests, mutation checks and real WSL/Windows measurements. I did not run repository suites, Chrome/GPU/WSL/native fixtures, permission changes, installs, builds or CI reruns. No source/configuration edits, direct merge or release action. This is a code-merit approval, not a new native-performance receipt or a waiver of independent release gates; Home retains merge ownership.
— tai
|
@miguel-heygen did you test this on the windows computer? |
Edit accuracy: accurate 2061 (base branch 2061), smooth 1510 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
Part of #5548.
What a user sees now
Under WSL, when auto GPU mode falls back to software, the log says so once, with what was checked and what to do:
usermodfix appears only when the access check fails and the user is not in the group that owns the node. If the user is in that group and still denied, it says so and points tols -l. If the node is readable and writable, or missing, it says permissions are not the cause.--browser-gpu, the mode stays hardware as before. Its warning keeps the "unverified" and Chrome-install (hyperframes doctor) advice for a failed or timed-out probe and adds the WSL checks; for a probe that found no GPU, the WSL checks replace the Docker passthrough advice. Nothing claims the render uses SwiftShader in that mode.Before, the only output was the probe line, and
--browser-gpugave Docker passthrough advice.Why
#5548 traced the fallback to Mesa failing to open
/dev/dri/renderD128because a default WSL2 Ubuntu user is invideobut notrender. That is the one cause we can check without a GPU. The note says "can stop" rather than "stops": on an Intel laptop under WSL2 the same kind of user did reach the GPU through Mesa's D3D12 driver, but Chrome took 35 to 60 s to answer, past the probe's 15 s budget.How
packages/engine/src/services/wslHost.ts: WSL detection (moved from the CLI's telemetry so both use one detector, exported as@hyperframes/engine/wsl-host) and the render-node check: an access check for read and write (not an open), the owning group's name, and whether the user is in it.browserManager.ts: the probe records the WSL checks with its outcome; auto mode prints the note when it selects software; the explicit-hardware warning includes the checks. Both print once per process.Checked on a real WSL2 machine
Windows 11, Intel graphics, WSL 3.0.3, Ubuntu 22.04, Mesa 23.2.1, a fresh non-root user in
videobut notrender, 10 s example composition:renderusermodfixusermod -aG render+wsl --shutdown--browser-gpu, user not inrenderThe
usermod+wsl --shutdownfix takes effect (the user getsrenderand the node becomes readable and writable). On this Intel machine it does not make Chrome use the GPU, because the D3D12 path is too slow to start, and the runs that did use hardware GL were slower than SwiftShader, so falling back is the right call here. Whether the fix gets an NVIDIA card working, as in the report, is not tested here: no NVIDIA card was available.The same composition rendered from native Windows on that machine picked the GPU in auto mode (
ANGLE (Intel ... Direct3D11)), which is what the note and docs point to.Not in this PR: the firewall prompt (#5548 suggestion 4)
The render's local file server already listens on 127.0.0.1 only. On native Windows, sampling every listening TCP socket and UDP endpoint of
node.exeand Chrome during a fullhyperframes rendershowed only127.0.0.1(the file server, and Chrome's debugging port), so there is nothing in the render path to rebind. The CLI commands that do bind every interface arepreview's port check,playandpresent, which are a different change.Tests
wslHost.test.ts: detection from the kernel release and/proc/version; the four render-node states (denied and not in the group, denied but in the group, readable and writable, missing); a numeric group id when the group has no name; nothing outside WSL.browserManager.test.ts, with a faked WSL host: auto mode prints the note once with the right first line for no GPU and for a real 15 s page timeout; explicit hardware after a timeout or a Chrome launch failure keeps the unverified/doctor advice and never claims software; explicit hardware with no GPU gives the WSL fix instead of Docker; a WSL host with a hardware renderer stays quiet. The existing Linux and macOS warning tests now pass a non-WSL host, so they no longer depend on the machine running them.