diff --git a/.env.example b/.env.example index 6afc6a6e0..c46c524f4 100644 --- a/.env.example +++ b/.env.example @@ -139,9 +139,11 @@ OPENHUMAN_REASONING_ENABLED= OPENHUMAN_SHELL_HIDE_WINDOW= # [optional] Desktop CEF startup escape hatch. Set to 1/true/yes/on only when # CEF fails before the app can render, for example on a GPU/driver stack where -# startup logs show `cef::initialize returned 0`. Adds --disable-gpu and -# --disable-gpu-compositing to the embedded CEF runtime. Leave unset otherwise; -# this disables GPU acceleration and can break WebGL-heavy surfaces. +# startup logs show `cef::initialize returned 0`. On Windows this pins CEF to the +# pure-software ANGLE/SwiftShader GL backend (needed on NVIDIA Blackwell / +# RTX 50-series, where bare --disable-gpu is insufficient — #4385); on other +# platforms it adds --disable-gpu and --disable-gpu-compositing. Leave unset +# otherwise; this disables hardware GPU acceleration and slows WebGL-heavy surfaces. # OPENHUMAN_DISABLE_GPU= # --------------------------------------------------------------------------- diff --git a/app/src-tauri/src/lib.rs b/app/src-tauri/src/lib.rs index 1840d17fc..210fe0d28 100644 --- a/app/src-tauri/src/lib.rs +++ b/app/src-tauri/src/lib.rs @@ -2030,6 +2030,23 @@ fn cef_disable_gpu_enabled(env_override: Option<&str>) -> bool { } } +/// Pin CEF to ANGLE's pure-software SwiftShader GL backend. +/// +/// SwiftShader is a software rasteriser that needs no hardware EGL/driver, so it +/// gives both WebGL surfaces and GPU-process init a working (software) context +/// on stacks where the hardware GPU path aborts. `--enable-unsafe-swiftshader` +/// is required because Chromium gates SwiftShader-backed WebGL behind it (the +/// "unsafe" label is about software perf, not security). `--disable-gpu-compositing` +/// keeps page compositing on the CPU. Crucially this does **not** pass +/// `--disable-gpu`, which would shut the GPU process down entirely — and with it +/// the SwiftShader context that lets CEF start. +fn push_swiftshader_software_gl(args: &mut Vec) { + args.push(("--use-gl", Some("angle"))); + args.push(("--use-angle", Some("swiftshader"))); + args.push(("--enable-unsafe-swiftshader", None)); + args.push(("--disable-gpu-compositing", None)); +} + fn append_platform_cef_gpu_workarounds( args: &mut Vec, os: &str, @@ -2044,11 +2061,27 @@ fn append_platform_cef_gpu_workarounds( // do not reach the vendored CEF runtime. Provide a narrow, release-safe // env escape hatch instead of forwarding arbitrary Chromium flags. if disable_gpu { - args.push(("--disable-gpu", None)); - args.push(("--disable-gpu-compositing", None)); - log::info!( - "[cef-startup] OPENHUMAN_DISABLE_GPU set: adding --disable-gpu and --disable-gpu-compositing for CEF startup compatibility (issue #4294)" - ); + if os == "windows" { + // Issue #4385: on NVIDIA Blackwell / RTX 50-series Windows stacks the + // bundled CEF's GPU process fails to initialise and bare + // `--disable-gpu` is not enough — `cef::initialize` still returns 0 + // before any UI renders (#4294, #4385). `--disable-gpu` removes the + // GPU process without giving CEF a working software GL path, so init + // still aborts. Pin CEF to the pure-software ANGLE/SwiftShader backend + // instead — the same fallback the Linux #1697/#4193 path relies on — + // which needs no hardware driver and lets CEF start on GPUs the + // bundled Chromium doesn't yet support. + push_swiftshader_software_gl(args); + log::info!( + "[cef-startup] OPENHUMAN_DISABLE_GPU set on Windows: forcing ANGLE/SwiftShader software GL for CEF startup compatibility (issues #4294/#4385)" + ); + } else { + args.push(("--disable-gpu", None)); + args.push(("--disable-gpu-compositing", None)); + log::info!( + "[cef-startup] OPENHUMAN_DISABLE_GPU set: adding --disable-gpu and --disable-gpu-compositing for CEF startup compatibility (issue #4294)" + ); + } } // Issue #1697: on Arch/Manjaro-family Linux systems, the AppImage can @@ -2078,10 +2111,7 @@ fn append_platform_cef_gpu_workarounds( "[cef-startup] OPENHUMAN_FORCE_GPU set — skipping SwiftShader software-GL fallback (issue #1697). If the app fails to launch with a GPU process abort, unset the env var." ); } else { - args.push(("--use-gl", Some("angle"))); - args.push(("--use-angle", Some("swiftshader"))); - args.push(("--enable-unsafe-swiftshader", None)); - args.push(("--disable-gpu-compositing", None)); + push_swiftshader_software_gl(args); log::info!( "[cef-startup] Linux detected: forcing ANGLE/SwiftShader software GL so WebGL surfaces (Tiny Place world renderer, Rive mascot) render without the crash-prone hardware GPU process (issues #1697/#4193); set OPENHUMAN_FORCE_GPU=1 for hardware acceleration" ); diff --git a/app/src-tauri/src/lib_tests.rs b/app/src-tauri/src/lib_tests.rs index 0b8862efa..15c798fc5 100644 --- a/app/src-tauri/src/lib_tests.rs +++ b/app/src-tauri/src/lib_tests.rs @@ -414,9 +414,37 @@ fn platform_cef_gpu_workarounds_disable_windows_gpu_when_requested() { let mut args = Vec::new(); append_platform_cef_gpu_workarounds(&mut args, "windows", "x86_64", None, Some("1")); + // #4385: on Windows the escape hatch pins CEF to the pure-software + // ANGLE/SwiftShader backend instead of bare `--disable-gpu`, which is + // insufficient on NVIDIA Blackwell / RTX 50-series stacks (cef::initialize + // still returns 0). This mirrors the proven Linux #1697/#4193 fallback. assert_eq!( args, - vec![("--disable-gpu", None), ("--disable-gpu-compositing", None)] + vec![ + ("--use-gl", Some("angle")), + ("--use-angle", Some("swiftshader")), + ("--enable-unsafe-swiftshader", None), + ("--disable-gpu-compositing", None), + ] + ); +} + +#[test] +fn platform_cef_gpu_workarounds_windows_disable_gpu_avoids_bare_disable_gpu() { + // Regression guard for #4385: `--disable-gpu` alone leaves CEF without a + // working software GL path on unsupported (Blackwell) GPUs and init keeps + // failing. The Windows escape hatch must route through SwiftShader and must + // NOT emit the lethal `--disable-gpu` switch. + let mut args = Vec::new(); + append_platform_cef_gpu_workarounds(&mut args, "windows", "x86_64", None, Some("1")); + + assert!( + !args.contains(&("--disable-gpu", None)), + "Windows OPENHUMAN_DISABLE_GPU must not emit bare --disable-gpu (#4385), got: {args:?}" + ); + assert!( + args.contains(&("--use-angle", Some("swiftshader"))), + "Windows OPENHUMAN_DISABLE_GPU must force SwiftShader software GL (#4385), got: {args:?}" ); } diff --git a/gitbooks/developing/cef.md b/gitbooks/developing/cef.md index 02bd0bf63..1a0455389 100644 --- a/gitbooks/developing/cef.md +++ b/gitbooks/developing/cef.md @@ -119,10 +119,17 @@ the current stable Windows release. That separates a profile/cache problem from an OS/runtime compatibility regression in CEF startup. If the logs point to a GPU-process startup failure rather than a stale CEF -profile lock, set `OPENHUMAN_DISABLE_GPU=1` before launching OpenHuman. This -passes `--disable-gpu` and `--disable-gpu-compositing` to the embedded CEF -runtime without forwarding arbitrary Chromium flags. Leave it unset for normal -use because disabling the GPU path can break WebGL-heavy surfaces. +profile lock, set `OPENHUMAN_DISABLE_GPU=1` before launching OpenHuman. On +Windows this pins CEF to the pure-software ANGLE/SwiftShader GL backend +(`--use-gl=angle --use-angle=swiftshader --enable-unsafe-swiftshader +--disable-gpu-compositing`) rather than bare `--disable-gpu`: on NVIDIA Blackwell +/ RTX 50-series stacks the GPU process fails to initialise and `--disable-gpu` +alone leaves CEF with no working software GL path, so `cef::initialize` still +returns 0 (#4294, #4385). SwiftShader needs no hardware driver, so it lets CEF +start on GPUs the bundled Chromium (currently CEF 146.4.1) doesn't yet support. +On other platforms the same env var passes `--disable-gpu` and +`--disable-gpu-compositing` without forwarding arbitrary Chromium flags. Leave it +unset for normal use because forcing software rendering slows WebGL-heavy surfaces. ## Linux shell fallback for CEF startup crashes