Skip to content

fix(engine): software renders reach SwiftShader when VK_DRIVER_FILES pins a GPU - #5976

Open
diogochaves wants to merge 2 commits into
heygen-com:mainfrom
diogochaves:fix/swiftshader-vk-driver-files
Open

diogochaves wants to merge 2 commits into
heygen-com:mainfrom
diogochaves:fix/swiftshader-vk-driver-files

Conversation

@diogochaves

@diogochaves diogochaves commented Oct 20, 2026 •

Copy link
Copy Markdown

What

Software renders (--no-browser-gpu, or auto falling back to software) launch Chrome without VK_DRIVER_FILES, VK_LOADER_DRIVERS_SELECT and VK_LOADER_DRIVERS_DISABLE. Hardware launches, and environments that set none of them, are unchanged.

Why

On my Linux desktop the session pins Vulkan to the AMD iGPU with VK_DRIVER_FILES=/usr/share/vulkan/icd.d/radeon_icd.json (it has a second GPU). Every software render failed before the first frame:

[assertSwiftShader] Chrome reported a non-SwiftShader WebGL backend. ... Got vendor="Google Inc. (AMD)"
renderer="ANGLE (AMD, Vulkan 1.4.354 (AMD Ryzen 7 9800X3D 8-Core Processor (RADV RAPHAEL_MENDOCINO) (0x000013C0)), radv)"

The flags were right (--use-gl=angle --use-angle=swiftshader --enable-unsafe-swiftshader). ANGLE loads SwiftShader by pointing the Vulkan loader at its ICD through VK_ICD_FILENAMES, and the loader ignores VK_ICD_FILENAMES whenever VK_DRIVER_FILES is set (LoaderDriverInterface.md), so ANGLE gets the real GPU. VK_LOADER_DRIVERS_SELECT breaks it too: VK_LOADER_DRIVERS_SELECT='*radeon*' filters SwiftShader out and the check sees no WebGL at all.

Repro, any project: VK_DRIVER_FILES=<your GPU's ICD json> npx hyperframes render --no-browser-gpu. Fails on 0.8.179 and 0.8.181 with chrome-headless-shell 155.0.8059.84; works with env -u VK_DRIVER_FILES.

Related work

None that I found (searched issues and PRs for VK_DRIVER_FILES, VK_ICD_FILENAMES, assertSwiftShader, SwiftShader Vulkan). It sits next to the WAYLAND_DISPLAY launch env from #5591. The CLI's own browsers (check, snapshot) don't go through launchBrowser, so they still inherit the pin in software mode; nothing fails there, so I left them out.

How

launchBrowser now asks launchEnv(fingerprint) for its env: the WSL case as before, otherwise, when the args select SwiftShader (--use-angle=swiftshader or --use-vulkan=swiftshader) and one of the three variables is set, a copy of process.env without them. Otherwise undefined, so Puppeteer inherits as it does today.

Size budget

@hyperframes/engine packed budget goes from 456055 (main, after #6194) to 456397 bytes (+342, the increase this PR already asked for). Main packs at 435883 and this branch at 436205: launchEnv and its list of Vulkan variables are the whole difference.

Test plan

  • Unit tests added: browserManager-vulkanEnv.test.ts checks the launch env for software (pins dropped, rest kept), hardware (inherited) and an unpinned env (inherited). The first case fails on main.
  • Manual testing: the render above, built from this branch, with the pin set: renders, assertSwiftShader passes on worker 0. Same with VK_LOADER_DRIVERS_SELECT='*radeon*'. Default (hardware) render unchanged.
  • oxlint, oxfmt --check, engine typecheck, check-comment-citations.mjs, comment-ratchet.mjs. Engine suite: the 6 failures I get are the same on main (ffmpeg 9 dropped -vsync, and two WSL probe-timeout tests).
  • Comments follow CONTRIBUTING.md "Comments"

@miguel-heygen miguel-heygen 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.

Thank you for this, and for citing the loader documentation. The diagnosis is exactly right and the fix sits in the one place every launch routes through.

I checked the two ways it could misbehave and both are safe. withoutWaylandDisplay is only ever set on the hardware branch of the GPU probe, so the early return cannot swallow a software launch, and use-vulkan=swiftshader is gated on browserGpuMode being software, so a hardware render can never lose its pins. The test going through acquireBrowser rather than calling the helper directly is the right seam, and it restores the variables after each case.

One question rather than a change request: is VK_LOADER_DRIVERS_DISABLE in the list because you saw it filter SwiftShader out, or is it there for symmetry with the other two?

Worth flagging that no test job has run on this PR yet, only the mergeability check, so the suite still needs a maintainer to let the fork workflows run before merge.

@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.

Approving at fb53d4db, adding to Miguel's approval at the same head. I won't repeat his two safety checks, I agree with both.

What I added:

  • Applied onto current main (the file has moved since, #6149 and #6037, but the patch still applies cleanly): the new test file passes 3 of 3, and with only browserManager.ts reverted the software-render case fails. So the test guards the fix.
  • Both ppt.launch calls inside launchBrowser (the first launch and the capture-mode retry) read the same env, so the retry can't relaunch with the pins back. The GPU probe keeps the inherited env, which is right since it is testing the real GPU.
  • It only touches the launch env when the args select SwiftShader and one of the three variables is actually set, so the default path still passes undefined and Puppeteer inherits as before.

Need: yes, software renders fail outright on a machine that pins a Vulkan driver · Size: ok · Reuse: extends the existing launch-env hook next to envWithoutWaylandDisplay · Simpler: already minimal

— Rames

@jrusso1020

Copy link
Copy Markdown
Collaborator

Thanks, @diogochaves. This one is approved, and it'll go into the merge queue once these are sorted:

Once it's green and signed, we'll queue it at your new head. If you push code changes beyond a rebase, we'll take another look first.

— Rames

@diogochaves
diogochaves force-pushed the fix/swiftshader-vk-driver-files branch from fb53d4d to f9bfcc9 Compare October 24, 2026 11:08

@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.

Re-approving at the new head. I diffed this PR's own patch against the head I approved and it's identical: a rebase or a main merge only.

@diogochaves

Copy link
Copy Markdown
Author

One question rather than a change request: is VK_LOADER_DRIVERS_DISABLE in the list because you saw it filter SwiftShader out, or is it there for symmetry with the other two?

I'd only added it by the loader rule, so I went and tested it to be sure. It turns out it breaks things on its own: on 0.8.179, with no other Vulkan variables set, VK_LOADER_DRIVERS_DISABLE='' fails --no-browser-gpu the same way SELECT does (assertSwiftShader gets vendor="" renderer="", since the loader filters SwiftShader's ICD out). A narrow glob like 'nvidia' is harmless and renders fine. With this branch, DISABLE='' renders, with or without VK_DRIVER_FILES set.

I've also rebased onto main for the Test (support) fix Rames mentioned. It's the same diff and signed. Thanks to you both!

@jrusso1020

Copy link
Copy Markdown
Collaborator

Thanks, @diogochaves. At f9bfcc9b the required Build job fails at verify:packed-manifests: @hyperframes/engine packed size 433033 bytes is over its budget of 428562 by more than 1%. Main's engine is already close to its budget, and this change tips it over. Could you either keep the new code out of the packed output, or raise the engine budget in scripts/package-size-budgets.json and give the reason in the PR body, as the check asks? "Studio: edit accuracy gate" only failed because it depends on Build. I'll re-approve once CI is green.

— Rames

@diogochaves

Copy link
Copy Markdown
Author

Thanks, raised the engine packed budget by the 342 bytes launchEnv adds (main was already 157 bytes under the limit) in c77d4149d, with the reason in the PR body.

@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.

Re-approving at c77d4149. Against my approval, the only change is the engine packed budget raised by 342 bytes in scripts/package-size-budgets.json, with the reason in the PR body as the check asks. I've approved the fork CI at this head.

@jrusso1020

Copy link
Copy Markdown
Collaborator

Thanks for the budget bump. Since then, #6194 and #6175 landed on main and both edit scripts/package-size-budgets.json, so this now conflicts. Could you rebase onto main and keep your engine budget increase on top of the new values? Once you push, I'll re-approve at the new head and add it to the merge queue.

diogochaves and others added 2 commits October 24, 2026 12:55
…pins a GPU

ANGLE (and Dawn) load SwiftShader by pointing the Vulkan loader at its ICD
through VK_ICD_FILENAMES. The loader ignores VK_ICD_FILENAMES while
VK_DRIVER_FILES is set, and still applies VK_LOADER_DRIVERS_SELECT/DISABLE,
so on a machine that pins its Vulkan driver that way a --no-browser-gpu
render gets ANGLE on the real GPU and assertSwiftShader refuses it.

Launch SwiftShader browsers without those three variables. Hardware
launches, and environments that set none of them, are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…v adds

The increase sits on top of main's engine budget, 456055 after heygen-com#6194.
Main packs the engine at 435883 bytes and this branch at 436205.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@diogochaves
diogochaves force-pushed the fix/swiftshader-vk-driver-files branch from c77d414 to a1963ca Compare October 24, 2026 16:31
@diogochaves

Copy link
Copy Markdown
Author

Rebased onto main; the engine budget is now main's 456055 + 342 = 456397, in a1963ca03.

@miguel-heygen miguel-heygen 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.

Thanks for testing VK_LOADER_DRIVERS_DISABLE on its own. That settles my question: it's in the list because it really filters SwiftShader out, not for symmetry.

I compared this head against the one I approved. The code and test are unchanged. The only addition is the engine packed budget, 456055 to 456397, which matches main's current value plus the 342 bytes the PR body explains.

The only thing outstanding is CI. The fork workflows at this head are waiting for a maintainer to approve the run, so nothing beyond the mergeability check has run here yet. The previous head was green, so I expect this one to be too. Once the run goes green this is good to go from my side.

Verdict: COMMENT
Reasoning: The code is unchanged from the approved head apart from an explained budget bump, but the required checks have not run at this head yet.

This branch has not been deployed

No deployments
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.

3 participants