fix(linux): fall back to software rendering after repeated GPU crashes - #8
Open
pango07 wants to merge 2 commits into
Open
fix(linux): fall back to software rendering after repeated GPU crashes#8pango07 wants to merge 2 commits into
pango07 wants to merge 2 commits into
Conversation
On some Linux setups (AMD integrated graphics on Mesa) the GPU process fails to launch, Chromium retries, and then kills the app outright: [ERROR:gpu_process_host.cc] GPU process launch failed: error_code=1002 [FATAL:gpu_data_manager_impl_private.cc] GPU process isn't usable. Goodbye. There was no fallback for this anywhere in main, so the app was simply unusable on affected machines and the only workaround was passing --disable-gpu by hand, which breaks the transparent overlay windows. Count GPU process crashes in userData and, once a machine looks chronically affected, start the next launch with hardware acceleration off. A run that stays up for a minute without a GPU crash clears the counter, so a one-off crash mid driver update doesn't permanently downgrade a healthy machine. FLICKY_DISABLE_GPU=1 forces the fallback for anyone who wants to confirm the diagnosis immediately. Refs #5
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Review caught three defects in the first cut. The reset timer cleared the counter while the fallback was active. A broken machine would crash until the counter tripped, come up stable in software rendering, reset itself at 60s because "no GPU crash this run", and re-enable acceleration on the next launch — crashing forever on any session longer than a minute. The reset now only runs at tier 0, and only for a run that saw no GPU failure at all, so a recovered run no longer wipes an accumulating count either. Every child-process-gone event with type GPU was counted, including clean-exit and killed. Normal teardown at quit, or an OOM kill, would accumulate into a permanent downgrade on a healthy machine. Only crashed, abnormal-exit, launch-failed and integrity-failure count now. The listener was attached inside whenReady().then(), but the failure it counts is a startup launch failure that begins before ready resolves — the events it existed to catch were the ones it could miss. It now attaches pre-ready, gated on the single-instance lock so a duplicate launch still never writes. Also: disableHardwareAcceleration does not stop the GPU process from launching, so it can't fix a sandbox-level launch failure, which is a commonly reported cause of this same error signature. Added a second tier that appends disable-gpu-sandbox when a machine keeps failing while already in software rendering. And clamp the persisted counter through Number.isFinite — NaN is a number and compares false against every threshold, which would have disabled the fallback outright.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found while looking into #5. Unproven against real hardware — see the testing section before merging.
the bug
On some Linux setups (AMD integrated graphics on Mesa in the reported case) the GPU process fails to launch, Chromium retries, and then kills the app:
There is no fallback for this anywhere in
src/mainright now: noapp.disableHardwareAcceleration(), noapp.commandLine.appendSwitch. So the app is unusable on affected machines, and the only workaround is passing--disable-gpuby hand, which tends to break the transparent overlay windows rather than help.the fix
You can't detect a GPU that will fail before it fails, so this counts failures across runs and degrades in tiers on the next launch:
disableHardwareAcceleration()disable-gpu-sandboxTier 2 matters because
disableHardwareAcceleration()does not stop the GPU process from launching — it only skips GL/driver init. That fixes a crash during Mesa driver setup, but not one where the sandbox fails to start the process at all, which is a commonly reported cause of this same error signature. If a machine keeps failing while already in software rendering, the sandbox is the next suspect. This tier is reasoned from the error class, not confirmed on hardware.Counting rules that matter:
crashed,abnormal-exit,launch-failed,integrity-failurecount.clean-exitandkilledare normal teardown and an OOM kill — counting those would let ordinary shutdowns accumulate into a permanent downgrade on a healthy machine.gpu-state.jsondeletion, printed in the log line.FLICKY_DISABLE_GPU=1or=2forces a tier.Runs pre-ready (the switches only apply before ready, and the failure being counted happens during startup), gated on the single-instance lock so a duplicate launch never touches the counter.
testing
npm run typecheckpasses.npm run lintfails on master too, unrelated: eslint 9 wants a flateslint.config.jsand the repo doesn't have one.Not runtime-tested against a failing GPU — I don't have that hardware.
FLICKY_DISABLE_GPU=1 npm startexercises the fallback path on any machine, which is worth doing before merge.the open question that decides whether this works at all
It is unverified whether Electron emits
child-process-goneto JS before Chromium'sLOG(FATAL)aborts the process. IfGpuDataManagerImpl's observer runs first, the app dies before JS ever sees the events, the counter never increments, and the fallback never engages. The writes are synchronous with an fsync so each captured event has the best chance of landing, but that's mitigation, not proof.One test on an affected machine settles it: launch, let it die, then check whether
gpu-state.jsonin the app data directory has a non-zero count. If it's absent or zero, this approach doesn't work and the fallback needs to be driven by something other than crash events — likely a "did the last launch reach ready?" sentinel written at startup and cleared on clean shutdown.also unresolved
Nothing gates the overlay windows in fallback mode. They're fullscreen,
transparent: true,alwaysOnTop: 'screen-saver', one per display, fed cursor positions every 16ms. Electron on Linux has a history of transparent windows rendering opaque black without GPU compositing — a black fullscreen always-on-top overlay would be a worse outcome than the crash. Worth checking on the target config; if it's a problem, skipping overlay creation at tier 1+ is the obvious follow-up.