Repository navigation
fix(engine): renders under WSL use the GPU through full Chrome when the headless shell cannot - #5574
Conversation
…he headless shell cannot Part of #5548.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
Please fix the optional full-Chrome cache failure path before approval. — Jerrai
| export function resolveFullChromePath(): string | undefined { | ||
| const baseDir = join(homedir(), ".cache", "puppeteer", "chrome"); | ||
| if (!existsSync(baseDir)) return undefined; | ||
| const versions = readdirSync(baseDir).sort(compareBrowserVersionsDescending); |
There was a problem hiding this comment.
This new optional cache lookup can throw (for example, ~/.cache/puppeteer/chrome exists but is a file or cannot be read). Under WSL, probeAutoBrowserGpuMode calls it after a software/headless-shell result without a catch, so resolveBrowserGpuMode rejects and createCaptureSession aborts before the previously working software render. The headless-shell cache reader already catches unreadable directories; please make this discovery fail-soft too and cover the failure path.
There was a problem hiding this comment.
Fixed in 600ffd0: the full-Chrome lookup now treats any read error on the cache folder as no full Chrome (same as the headless-shell lookup), so the render keeps its software fallback. New test points the cache at a file instead of a folder; it fails on the previous code with ENOTDIR and passes now. Also in this head: when full Chrome's own GPU check times out, the note says it could not finish rather than that it found no GPU.
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
The optional full-Chrome discovery now catches cache-directory read failures and returns no candidate, preserving the WSL software fallback; the new ENOTDIR regression fails on the prior code. The successor also distinguishes a failed full-Chrome probe from an actual no-GPU result in the diagnostic note. I rechecked the selected-browser screenshot path from the prior head. New-head CI is still running; the prior Windows-render red job stopped at Bun installation on an upstream GitHub API HTTP 500 before rendering. No real WSL GPU run was independently performed. Approval is for code, not merge or release. — Jerrai
Edit accuracy: accurate 2061 (base branch 2061), smooth 1576 of thoseThe gate passes. Quarantined, measured but not gated (0) |
Part of #5548.
What a user sees
Rendering inside WSL2 with a graphics card, the GPU check used to try only Chrome's headless shell. On Mesa's D3D12 driver (the WSL GPU path) the headless shell can fail to set up its GL surface ("No suitable EGL configs found") even after the user joins the
rendergroup, while full Chrome in--headless=newreaches the GPU. The render then fell back to software at CPU speed.Now, under WSL only, when the headless shell finds no GPU:
~/.cache/puppeteer/chrome, the same place the HDR path already looks). If it reaches the GPU, the render uses it, captured by screenshot (full Chrome has no BeginFrame). The log saysbrowserGpuMode probe → hardware (full Chrome: WebGL renderer ...).npx @puppeteer/browsers install chrome@stable --path ~/.cache/puppeteer), thatHYPERFRAMES_BROWSER_PATHcan point at one, and that native Windows uses the GPU through Direct3D.rendergroup alone is enough.Outside WSL nothing changes: the extra check never runs.
How it works
probeAutoBrowserGpuModeruns the usual headless-shell probe; under WSL, on a software result it probes full Chrome with the same hardware flags and remembers that browser when it gets a hardware renderer.resolveCaptureBrowserPathreturns that browser for hardware-mode renders.createCaptureSessionlaunches it and picks screenshot capture for it; the headless shell keeps BeginFrame.hdrCapture.tsintobrowserManager.ts(resolveFullChromePath) and now sorts versions numerically.Tests
browserManager.test.ts: under WSL, the shell finds no GPU and full Chrome does: auto and explicit hardware both resolve to hardware on full Chrome, no warning; both find no GPU: software, the note names full Chrome's result and native Windows; no full Chrome: the note gives the install command; outside WSL the locator is never called. Existing WSL tests no longer read the real Puppeteer cache.frameCapture-wslFullChrome.test.ts: the capture session launches the browser the probe chose, without BeginFrame flags; the headless shell keeps them.wslHost.test.ts: the note's two routes and the group-change wording.All new tests fail on main. Breaking the two core lines (dropping the chosen browser from the probe result, or keeping BeginFrame for full Chrome) turns three of them red.
Try this branch under WSL
Expect
browserGpuMode probe → software (WebGL unavailable)for the headless shell, thenbrowserGpuMode probe → hardware (full Chrome: ...), and aBrowser launched (..., screenshot, ...)line.Checked on a Windows 11 PC under WSL2 (Intel graphics, Ubuntu 22.04, Mesa 23.2.1)
We have no NVIDIA card, so the headless shell's failure was simulated: a wrapper adds
--disable-gputo the headless shell's GPU-mode launches only, so its GPU check answers "WebGL unavailable" right away, as the shell does on the reporter's machine. Full Chrome was installed with the command the note prints (it fetched 155.0.8059.79). Same 5 s composition,--workers 1.probe → software (WebGL unavailable), the WSL note, SwiftShader render.probe → software (full Chrome: probe failed (GPU probe page did not answer within 15000ms)), the note says full Chrome could not finish its check and names native Windows, and the render completes in software. On this PC Mesa's EGL start-up alone takes 90 to 100 s (eglinfo -p surfaceless, no Chrome involved), so any GPU check there can time out.probe → hardware (full Chrome: ... ANGLE (Microsoft Corporation, D3D12 (Intel(R) Graphics), OpenGL ES 3.0)),Browser launched (Chrome/155.0.8059.79, screenshot, ...), 150 of 150 frames, matching the software render (PSNR 62 dB). Twice. The first capture session sat at frame 0 for 60 s while Chrome's GPU process started and the existing stall retry recovered it; on the reporter's card full Chrome reached the GPU in about 0.1 s, so this Intel start-up cost should not apply there.Render times on this PC are dominated by that GPU start-up, so they say nothing about GPU drawing speed; the reporter's machine is the one to measure.