diff --git a/app/src-tauri/src/lib.rs b/app/src-tauri/src/lib.rs index d10eb4a1f..46c15c870 100644 --- a/app/src-tauri/src/lib.rs +++ b/app/src-tauri/src/lib.rs @@ -2009,21 +2009,37 @@ fn append_platform_cef_gpu_workarounds( ) { // Issue #1697: on Arch/Manjaro-family Linux systems, the AppImage can // abort during CEF GPU process startup when EGL context creation fails - // before Chromium's own fallback path gets a usable renderer. Disable the - // hardware GPU path on Linux so packaged builds can still launch via - // software compositing. Users with working GPU stacks can opt back into - // hardware acceleration via `OPENHUMAN_FORCE_GPU=1` — required for the - // Rive mascot on the Human tab and any other WebGL2 surface to render. + // before Chromium's own fallback path gets a usable renderer. + // + // The original workaround disabled the GPU path with `--disable-gpu`, but + // that shuts the GPU process down entirely — and with it every WebGL + // surface. That regressed Tiny Place (#4193): the world renderer needs a + // WebGL2 context, so on every packaged Linux build it failed to initialise + // and the world page showed a black screen with "Could not start the world + // renderer" (the Rive mascot on the Human tab is collateral damage too). + // + // Instead of killing the GPU process, pin it to ANGLE's SwiftShader + // software backend. SwiftShader is a pure-software rasteriser that needs no + // hardware EGL/driver, so it still sidesteps the #1697 EGL-context abort, + // while giving WebGL surfaces a working (software) context to render into. + // `--disable-gpu-compositing` is preserved so page compositing stays on the + // CPU exactly as before; only the lethal `--disable-gpu` is dropped. + // `--enable-unsafe-swiftshader` is required because Chromium gates + // SwiftShader-backed WebGL behind it (the "unsafe" label is about software + // perf, not security). Users with working GPU stacks can still opt into + // hardware acceleration via `OPENHUMAN_FORCE_GPU=1`. if os == "linux" { if cef_force_gpu_enabled(force_gpu_override) { log::info!( - "[cef-startup] OPENHUMAN_FORCE_GPU set — skipping --disable-gpu / --disable-gpu-compositing (issue #1697). If the app fails to launch with a GPU process abort, unset the env var." + "[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(("--disable-gpu", None)); + args.push(("--use-gl", Some("angle"))); + args.push(("--use-angle", Some("swiftshader"))); + args.push(("--enable-unsafe-swiftshader", None)); args.push(("--disable-gpu-compositing", None)); log::info!( - "[cef-startup] Linux detected: adding --disable-gpu and --disable-gpu-compositing (issue #1697); set OPENHUMAN_FORCE_GPU=1 to re-enable hardware compositing (needed for WebGL2 surfaces like the Rive mascot)" + "[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 c781ec47b..2447477e9 100644 --- a/app/src-tauri/src/lib_tests.rs +++ b/app/src-tauri/src/lib_tests.rs @@ -314,11 +314,22 @@ fn platform_os_is_macos_on_macos_build() { } #[test] -fn platform_cef_gpu_workarounds_disable_linux_gpu_path() { +fn platform_cef_gpu_workarounds_force_swiftshader_on_linux() { let mut args = Vec::new(); append_platform_cef_gpu_workarounds(&mut args, "linux", "x86_64", None); - assert!(args.contains(&("--disable-gpu", None))); + // #4193: the GPU process must NOT be killed outright — `--disable-gpu` + // takes every WebGL surface (the Tiny Place world renderer) down with it. + assert!( + !args.contains(&("--disable-gpu", None)), + "--disable-gpu kills WebGL and must not be set, got: {args:?}" + ); + // Instead the GPU process is pinned to ANGLE/SwiftShader software GL, which + // keeps WebGL available while still avoiding the #1697 hardware-EGL abort. + assert!(args.contains(&("--use-gl", Some("angle")))); + assert!(args.contains(&("--use-angle", Some("swiftshader")))); + assert!(args.contains(&("--enable-unsafe-swiftshader", None))); + // Page compositing stays on the CPU exactly as before. assert!(args.contains(&("--disable-gpu-compositing", None))); } @@ -391,6 +402,13 @@ fn platform_cef_gpu_workarounds_skip_linux_disable_when_force_gpu_set() { !args.contains(&("--disable-gpu-compositing", None)), "OPENHUMAN_FORCE_GPU=1 must suppress --disable-gpu-compositing, got: {args:?}" ); + // With hardware acceleration opted in, the SwiftShader software-GL fallback + // must NOT be forced either — otherwise WebGL would still be stuck on the + // software rasteriser despite the override. + assert!( + !args.contains(&("--use-angle", Some("swiftshader"))), + "OPENHUMAN_FORCE_GPU=1 must not force SwiftShader, got: {args:?}" + ); } #[test]