diff --git a/README.md b/README.md index 41af2b453..31c2769e7 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,20 @@ CRAFT_FONTS_DIR="$PWD/../craft-fonts" cargo run --release -p designcraft # abs Without it, Japanese falls back to the system's fonts (none on the web). Release builds always include it. +On Windows, the desktop app initializes only DirectX 12 by default. This avoids an AMD +OpenGL driver startup crash in `atio6axx.dll`; no custom launcher or shortcut is needed. +For graphics troubleshooting, `WGPU_BACKEND` overrides this default (for example, `dx12` +or `vulkan`). In PowerShell, run this from the directory containing the executable: + +```powershell +$env:WGPU_BACKEND = "vulkan" +& .\designcraft.exe +Remove-Item Env:WGPU_BACKEND # restore the default for later launches +``` + +An explicit `opengl` override can reintroduce the driver crash on affected systems. +The macOS, Linux and web backend defaults are unchanged. + To drive a running app, send JSON lines to `127.0.0.1:7979`. The protocol is described in [`docs/control-protocol.md`](docs/control-protocol.md). diff --git a/apps/designcraft/src/graphics.rs b/apps/designcraft/src/graphics.rs new file mode 100644 index 000000000..d8b70bc57 --- /dev/null +++ b/apps/designcraft/src/graphics.rs @@ -0,0 +1,41 @@ +//! Windows instance configuration, applied before wgpu can initialize any driver. + +use eframe::{NativeOptions, egui_wgpu::WgpuSetup, wgpu::Backends}; + +pub fn configure(options: &mut NativeOptions, backend_override: Option) { + if let WgpuSetup::CreateNew(create) = &mut options.wgpu_options.wgpu_setup { + // eframe's default includes GL. Creating that backend can crash inside + // AMD's atio6axx.dll before adapter selection or Rust error handling. + // Match the verified WGPU_BACKEND=dx12 workaround without mutating + // process environment variables or initializing GL as a fallback. + create.instance_descriptor.backends = backend_override.unwrap_or(Backends::DX12); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn configured_backends(backend_override: Option) -> Backends { + let mut options = NativeOptions::default(); + configure(&mut options, backend_override); + let WgpuSetup::CreateNew(create) = options.wgpu_options.wgpu_setup else { + panic!("default native options must create a wgpu instance"); + }; + create.instance_descriptor.backends + } + + #[test] + fn windows_default_initializes_only_dx12() { + // Adapter preference is too late: enabling GL can crash inside atio6axx.dll + // while creating the instance, even when a different adapter is selected. + assert_eq!(configured_backends(None), Backends::DX12); + } + + #[test] + fn explicit_backend_override_is_preserved() { + for backends in [Backends::VULKAN, Backends::GL, Backends::DX12, Backends::VULKAN | Backends::DX12, Backends::empty()] { + assert_eq!(configured_backends(Some(backends)), backends); + } + } +} diff --git a/apps/designcraft/src/main.rs b/apps/designcraft/src/main.rs index 101a5f5f5..ba25f9a05 100644 --- a/apps/designcraft/src/main.rs +++ b/apps/designcraft/src/main.rs @@ -9,6 +9,8 @@ #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] mod control_server; +#[cfg(any(target_os = "windows", test))] +mod graphics; #[cfg(target_os = "macos")] mod native_menu; @@ -209,6 +211,8 @@ fn main() -> eframe::Result { .with_title_shown(false), ..Default::default() }; + #[cfg(target_os = "windows")] + graphics::configure(&mut options, eframe::wgpu::Backends::from_env()); options.viewport = options.viewport.with_app_id(APP_ID); if let Some(icon) = app_icon() { options.viewport = options.viewport.with_icon(icon);