fix(desktop): detect QEMU/UTM virtualized GPUs, disable HW acceleration - #65087
fix(desktop): detect QEMU/UTM virtualized GPUs, disable HW acceleration#65087nickmimic wants to merge 3 commits into
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating this to the existing pre-launch GPU policy. The premise is still present on current main: apps/desktop/electron/bootstrap-platform.ts:85-107 returns null for a local Linux display such as :0, while apps/desktop/electron/main.ts:178-184 disables hardware acceleration only for a non-null reason.
Problems
apps/desktop/electron/bootstrap-platform.ts:21reads/sys/class/dmi/id/sys_vendordirectly. UnlikeisWslEnvironment(..., kernelRelease), this makes the QEMU path non-deterministic to test; the existing suite atapps/desktop/electron/bootstrap-platform.test.ts:12-85has no coverage for the new branch.- The PR body states that disabling GPU alone did not render a window in the reported VM and that this exact commit was not rebuilt there. The user-visible result therefore is not yet verified.
Suggested changes
- Make the DMI vendor value injectable and add deterministic QEMU/non-QEMU/read-failure/non-Linux tests plus override-precedence coverage.
- Run the rebuilt commit in the reported guest and attach the detection result; scope the claim to GPU policy if the other required flags remain outside this change.
Automated hermes-sweeper review.
| } | ||
| } | ||
|
|
||
| function isVirtualizedGpuEnvironment(platform = process.platform) { |
There was a problem hiding this comment.
Please make the DMI vendor input injectable, analogous to isWslEnvironment(..., kernelRelease), and add deterministic tests for QEMU, non-QEMU, read failure, and non-Linux behavior. Reading the host sysfs file directly prevents the new branch from being tested through the existing detector suite.
There was a problem hiding this comment.
Addressed the review feedback: both sysVendor and productName are now injectable (mirrors isWslEnvironment's kernelRelease pattern), and added 15 unit tests covering QEMU detection, sysfs-read failure, and the override behavior.
Also found and fixed a gap beyond the original scope: UTM's default backend on Apple Silicon is Apple's own Virtualization.framework, not QEMU, it reports the host vendor (Apple Inc.) via sys_vendor, so the original QEMU-only check would never have matched it. Added a second detection path via DMI product_name. This is likely the common case for UTM-on-Apple-Silicon users, so it's a meaningful expansion of what's actually covered, not just a testability refactor.
Verified in a real guest: the virtualized-gpu (Apple Virtualization.framework detected...) log line fires correctly. A separate pre-existing backend-startup race currently blocks full window rendering in this dev sandbox, unrelated to this fix, will file separately if needed.
SummaryTwo PRs address distinct Linux desktop failure causes: #41236 configures and propagates a keychain backend so Electron safeStorage can persist tokens, while #65087 detects QEMU/UTM virtualized GPUs so the existing pre-launch policy disables hardware acceleration. Related pull requests
DuplicatesNone: #41236 addresses safeStorage keychain selection, whereas #65087 addresses Chromium rendering on virtualized GPUs. Suggested consolidationKeep both PRs open with separate salvage paths: retain #41236's keychain detection, config bridge, pre-ready Electron switch, and launcher tests; retain #65087's injectable virtualized-GPU detection and tests while requiring the contributor-requested end-to-end guest validation. Neither PR is a duplicate of the other. Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 33 kB of PR diffs, 10 kB of issue/PR text, 2 kB of discussion (2 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
What does this PR do?
Extends
detectRemoteDisplay()inapps/desktop/electron/bootstrap-platform.tsto also detect locally-virtualized GPUs (QEMU/UTM), not just remote/forwarded displays.Currently,
hermes desktopsilently fails to show a window on Ubuntu ARM64 running inside UTM (QEMU) on macOS. No crash, just a dbus/systemd cgroup warning (StartTransientUnit/UnitExists). The root cause is thatdetectRemoteDisplay()only checks for SSH sessions, X11 forwarding, and RDP, all remote-display cases. A UTM/QEMU guest'sDISPLAYis local (:0), so none of those checks fire, GPU acceleration stays on, and Chromium's compositor never renders a usable window against the VM's virtualized/software-rendered GPU.This mirrors the existing
isWslEnvironment()pattern already in this file (a small, pure, testable detection function based on reading a platform-identifying file) rather than adding new CLI flags or env vars, since Hermes already hasHERMES_DESKTOP_DISABLE_GPUandconfig.yaml'sdesktop.disable_gpuas manual overrides. This just fixes the automatic detection so users on this platform don't have to discover and set an override themselves.Related Issue
Search performed per CONTRIBUTING.md "Before You Start": searched issues/PRs for UTM/QEMU + black screen/window-not-appearing on desktop. Related-but-not-duplicate results: #46523 ("Desktop window never appears on Wayland-in-VM (GNOME/Proxmox/VNC) ready-to-show never fires") is adjacent (also a VM display issue) but describes a different underlying cause (ready-to-show event, not GPU-compositor flicker/no-render on QEMU's virtual GPU) and a different VM stack (Proxmox/VNC vs UTM/QEMU). No exact duplicate found.
Type of Change
Changes Made
apps/desktop/electron/bootstrap-platform.ts: addedisVirtualizedGpuEnvironment(), which detects QEMU (and by extension UTM, which runs QEMU under the hood on macOS) via/sys/class/dmi/id/sys_vendor. Wired intodetectRemoteDisplay()alongside the existing SSH/X11-forwarding/RDP checks, and exported alongside the other helpers.isVirtualizedGpuEnvironment(), checked fromdetectRemoteDisplay(), to disable GPU acceleration on virtualized-GPU Linux guests. Detects two backends: QEMU (via DMIsys_vendor) and Apple's Virtualization.framework, UTM's default on Apple Silicon, via DMIproduct_name. Both signals are injectable for unit testing, mirroring the existingisWslEnvironment()pattern.How to Test
HERMES_DESKTOP_DISABLE_GPUset and nodesktop.disable_gpuinconfig.yaml, runhermes desktop.StartTransientUnit/UnitExistsline is logged.[hermes] remote display detected (virtualized-gpu (QEMU/UTM detected via DMI sys_vendor)); disabling GPU hardware acceleration to prevent flicker, confirming GPU acceleration is disabled automatically. (See note below on this specific VM, GPU-disable alone wasn't sufficient to render a window; the sandbox/Ozone pieces are a separate, already-supported config mechanism, not part of this fix.)Note: on this VM, GPU-acceleration disabling alone wasn't enough to get a
window to render --no-sandbox and --ozone-platform=x11 were also needed.
These aren't addressed by this PR since they're a separate mechanism from
the GPU auto-detection here (sandbox flag selection and Ozone backend
selection, not GPU compositor state) but they don't need a code fix either.
Hermes already supports this via config.yaml's
desktop.electron_flags/desktop.disable_gpu(see_desktop_launch_options()inhermes_cli/main.py). Anyone hitting a similar "no window, no error" symptomunder nested virtualization can add:
One relevant detail for context: Hermes's automatic sandbox fixup
(
_desktop_linux_sandbox_fixup) only falls back to--no-sandboxwhen itfails to configure the SUID
chrome-sandboxhelper. On this VM the fixupsucceeded (root:root, 4755) but the sandbox still couldn't fully initialize
under QEMU/UTM's nested user-namespace restrictions silently, with no
fallback warning. So
--no-sandboxhas to be forced explicitly via confighere rather than relying on auto-detection.
UPDATED: Verified via console log that the
virtualized-gpureason (Apple Virtualization.framework path) fires correctly inside a real UTM/Apple Silicon guest. A separate, pre-existing race in the dev sandbox's backend startup (ECONNRESET/ECONNREFUSEDconnecting to the local API) currently blocks the window from rendering end-to-end in this environment, unrelated to this change, not something this PR attempts to fix.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests pass (N/A test runner for this change, it's TypeScript, and I don't know of a JS/TS test command has been run yet either)Documentation & Housekeeping
docs/, docstrings) or N/Acli-config.yaml.exampleif I added/changed config keys or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows or N/AisVirtualizedGpuEnvironment()check is Linux-only (platform !== 'linux'short-circuits), matching the existing pattern for the WSL and RDP checks in the same file, so it's a no-op on Windows/macOS.Screenshots / Logs
Confirmed working on my own VM (Ubuntu 26.04 ARM64, UTM/QEMU on macOS): before this change,
hermes desktopproduced no window and only:I don't yet have a rebuilt binary reflecting this exact PR's code (edited via GitHub's web editor, not built locally), so I can't attach a fresh log showing the new
virtualized-gpudetection line firing, but i'm happy to build and attach that if a maintainer wants it before merge.