diff --git a/apps/photocraft/src/gpu_startup.rs b/apps/photocraft/src/gpu_startup.rs index 411708c8f8..56dbbb9400 100644 --- a/apps/photocraft/src/gpu_startup.rs +++ b/apps/photocraft/src/gpu_startup.rs @@ -267,12 +267,7 @@ fn rank(a: &Candidate, backend: GpuBackend, os: Os) -> (u8, u8, u8) { pub fn pick(adapters: &[Candidate], backend: GpuBackend, os: Os) -> Option { let usable = |a: &&Candidate| a.surface_ok; let any_wanted = adapters.iter().filter(usable).any(|a| a.wanted); - adapters - .iter() - .enumerate() - .filter(|(_, a)| a.surface_ok && (a.wanted || !any_wanted)) - .min_by_key(|(i, a)| (rank(a, backend, os), *i)) - .map(|(i, _)| i) + adapters.iter().enumerate().filter(|(_, a)| a.surface_ok && (a.wanted || !any_wanted)).min_by_key(|(i, a)| (rank(a, backend, os), *i)).map(|(i, _)| i) } /// Whether an adapter called `name` is the one the user asked for: `wanted` is a case-insensitive @@ -290,7 +285,7 @@ pub fn wanted_missed(adapters: &[Candidate], wanted: Option<&str>) -> bool { /// The adapter to ask for: `PHOTOCRAFT_GPU_ADAPTER` when set (for one launch), else /// `performance.gpuAdapter`; `None` is automatic. pub fn wanted_adapter(env: Option<&str>, pref: &str) -> Option { - [env.unwrap_or(""), pref].iter().map(|s| s.trim()).find(|s| !s.is_empty()).map(str::to_string) + [env.unwrap_or(""), pref].iter().map(|s| s.trim()).find(|s| !s.is_empty()).map(|s| s.chars().take(256).collect()) } /// Whether picking `chosen` applied the Intel-on-Windows DX12 default (a Vulkan adapter of the @@ -684,6 +679,7 @@ mod tests { assert_eq!(wanted_adapter(None, ""), None); assert_eq!(wanted_adapter(Some(" "), "iris"), Some("iris".into())); assert_eq!(wanted_adapter(Some("nvidia"), "iris"), Some("nvidia".into())); + assert_eq!(wanted_adapter(Some(&"x".repeat(1000)), "").map(|w| w.len()), Some(256)); } #[test] diff --git a/apps/photocraft/src/main.rs b/apps/photocraft/src/main.rs index 1c06e23898..0c2be25232 100644 --- a/apps/photocraft/src/main.rs +++ b/apps/photocraft/src/main.rs @@ -682,10 +682,8 @@ fn main() -> eframe::Result { } let gpu_note: std::sync::Arc>> = Default::default(); // The adapter's real texture limits (egui asks for 8192 px), so big documents stay on the GPU. - let wanted_adapter = gpu_startup::wanted_adapter( - std::env::var("PHOTOCRAFT_GPU_ADAPTER").ok().as_deref(), - &gpu_startup::read_gpu_adapter(services::prefs_file().as_deref()), - ); + let wanted_adapter = + gpu_startup::wanted_adapter(std::env::var("PHOTOCRAFT_GPU_ADAPTER").ok().as_deref(), &gpu_startup::read_gpu_adapter(services::prefs_file().as_deref())); gpu_startup::configure(&mut options.wgpu_options.wgpu_setup, &plan, os, wanted_adapter, sentinel.clone(), gpu_note.clone()); // Preferences › Performance › Low-Latency Drawing (#1343): without vsync a stroke shows about // 50 ms sooner; wgpu picks Immediate, else Mailbox, else Fifo by what the driver offers. diff --git a/docs/development.md b/docs/development.md index bf4898482d..2691f55d1c 100644 --- a/docs/development.md +++ b/docs/development.md @@ -86,7 +86,9 @@ On Windows and Linux the first PhotoCraft holds an exclusive lock on `instance.l ## Graphics startup and device loss -`--safe-gpu` starts with the CPU renderer for one launch (no GPU canvas; a software adapter for the window where the platform has one: WARP on Windows, llvmpipe over GL on Linux). Before creating the wgpu device the app writes and locks `gpu-starting.json` in the config directory; it clears it once the first frames have rendered. A launch that finds an unlocked marker knows the previous start died inside the graphics driver (#4) and uses the next safer backend (Windows: Vulkan → DX12 → CPU; Linux: Vulkan → GL → CPU; macOS: Metal → CPU), remembering a working hardware backend in `performance.gpuBackend` (Preferences › Performance › GPU Backend, with **Reset GPU Backend**). CPU recovery is temporary until **Keep Using CPU** is chosen in the recovery dialog; dismissing the dialog or quitting without a choice preserves the previous GPU preference (#3483). With `auto`, Intel adapters on Windows use DX12. On a machine with several GPUs (say an eGPU, a discrete laptop GPU and an iGPU), `auto` takes the first discrete adapter the driver lists; choose another in Preferences › Performance › Advanced › GPU adapter (`performance.gpuAdapter`, Linux; a case-insensitive piece of the adapter's name, empty is automatic), or for one launch with `PHOTOCRAFT_GPU_ADAPTER=nvidia`. An adapter that is missing or can't present to the window falls back to the automatic choice, with a note in System Info. Help › System Info shows the adapter, backend, driver and fallback state. +`--safe-gpu` starts with the CPU renderer for one launch (no GPU canvas; a software adapter for the window where the platform has one: WARP on Windows, llvmpipe over GL on Linux). Before creating the wgpu device the app writes and locks `gpu-starting.json` in the config directory; it clears it once the first frames have rendered. A launch that finds an unlocked marker knows the previous start died inside the graphics driver (#4) and uses the next safer backend (Windows: Vulkan → DX12 → CPU; Linux: Vulkan → GL → CPU; macOS: Metal → CPU), remembering a working hardware backend in `performance.gpuBackend` (Preferences › Performance › GPU Backend, with **Reset GPU Backend**). CPU recovery is temporary until **Keep Using CPU** is chosen in the recovery dialog; dismissing the dialog or quitting without a choice preserves the previous GPU preference (#3483). With `auto`, Intel adapters on Windows use DX12. Help › System Info shows the adapter, backend, driver and fallback state. + +On a machine with several GPUs (say an eGPU, a discrete laptop GPU and an iGPU), `auto` takes the first discrete adapter the driver lists; choose another in Preferences › Performance › Advanced › GPU adapter (`performance.gpuAdapter`, Linux; a case-insensitive piece of the adapter's name, empty is automatic), or for one launch with `PHOTOCRAFT_GPU_ADAPTER=nvidia`. An adapter that is missing or can't present to the window falls back to the automatic choice, with a note in System Info. On DX12 the shader compiler is FXC (`d3dcompiler_47.dll`, part of Windows), or a `dxcompiler.dll` placed beside `photocraft.exe`, loaded by its full path. wgpu's default looks `dxcompiler.dll` up by name, which reaches the current directory and `PATH` and loaded other programs' incompatible builds (#712).