From 78079587ad1f3a8c767e3e162392ac5ad16d046d Mon Sep 17 00:00:00 2001 From: devrosx Date: Thu, 15 Oct 2026 00:25:31 +0200 Subject: [PATCH] Build bodies on the CPU on AMD FirePro under Metal (GPU hang on Mac Pro 2013) (#1171) The AMD FirePro D300/D500/D700 Metal driver hangs on the tessellation compute shader and macOS resets the GPU, freezing the desktop. Bodies are built on the CPU on that device, and SOLIDCRAFT_CPU_TESS=1 forces the CPU path on any GPU. The check is a tested predicate, and the troubleshooting guide documents the variable. --- crates/ui-egui/src/gpu.rs | 24 +++++++++++++++++++++++- docs/book/src/guide/troubleshooting.md | 7 +++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/gpu.rs b/crates/ui-egui/src/gpu.rs index 1c3c74ef..d35e905c 100644 --- a/crates/ui-egui/src/gpu.rs +++ b/crates/ui-egui/src/gpu.rs @@ -834,6 +834,10 @@ fn tessellation(adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Qu return None; } let info = adapter.get_info(); + if hangs_on_gpu_tessellation(info.backend, &info.name) || std::env::var_os("SOLIDCRAFT_CPU_TESS").is_some() { + log::warn!("bodies are built on the CPU on {} ({:?})", info.name, info.backend); + return None; + } match solidcraft_gpu::TessGpu::with_shader(info.name.clone(), device.clone(), queue.clone(), shader) { Ok(t) => Some(t), Err(e) => { @@ -843,6 +847,13 @@ fn tessellation(adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Qu } } +/// A device whose driver hangs on the evaluation shader, so bodies are built on the CPU there: +/// the AMD FirePro D300/D500/D700 (Mac Pro 2013, Tahiti) under Metal, where macOS resets the GPU +/// and the whole desktop freezes. `SOLIDCRAFT_CPU_TESS=1` forces CPU evaluation on any device. +fn hangs_on_gpu_tessellation(backend: wgpu::Backend, name: &str) -> bool { + backend == wgpu::Backend::Metal && name.contains("FirePro") +} + /// Create the pipelines. Call once with the app's render state and its depth/stencil/MSAA /// settings. Without a stencil the section cap does not hide the inside of cut bodies. Without /// `gpu_meshing` (safe mode) bodies are meshed on the CPU. @@ -1182,7 +1193,18 @@ pub fn analysis_colors(c: &crate::theme::AnalysisColors) -> [f32; 36] { #[cfg(test)] mod tests { - use egui_wgpu::wgpu::naga; + use egui_wgpu::wgpu::{self, naga}; + + /// Only the FirePro under Metal skips GPU evaluation; the same card under another backend + /// and other Metal GPUs keep it. + #[test] + fn firepro_under_metal_builds_bodies_on_the_cpu() { + assert!(super::hangs_on_gpu_tessellation(wgpu::Backend::Metal, "AMD FirePro D500")); + assert!(super::hangs_on_gpu_tessellation(wgpu::Backend::Metal, "AMD FirePro D700")); + assert!(!super::hangs_on_gpu_tessellation(wgpu::Backend::Metal, "Apple M2")); + assert!(!super::hangs_on_gpu_tessellation(wgpu::Backend::Metal, "AMD Radeon Pro 560X")); + assert!(!super::hangs_on_gpu_tessellation(wgpu::Backend::Vulkan, "AMD FirePro W5100")); + } /// The viewport shader parses and validates (a bad shader would only fail at run time). #[test] diff --git a/docs/book/src/guide/troubleshooting.md b/docs/book/src/guide/troubleshooting.md index 582f454a..bb4bf224 100644 --- a/docs/book/src/guide/troubleshooting.md +++ b/docs/book/src/guide/troubleshooting.md @@ -62,6 +62,13 @@ saying what failed (earlier versions closed without a word). Things to try: - Run `solidcraft --crash-log` to list recent crash reports, and attach the newest one to an issue. +## The desktop stutters or freezes while SolidCraft builds bodies + +Some graphics drivers hang on the shader SolidCraft uses to build bodies on the GPU, and the +system then resets the GPU. SolidCraft already builds bodies on the CPU on the AMD FirePro +D300/D500/D700 (Mac Pro 2013). On another GPU that does this, start SolidCraft with +`SOLIDCRAFT_CPU_TESS=1` set to build bodies on the CPU, and open an issue with the GPU's name. + ## SolidCraft closes right away on Windows A graphics driver can crash the app while it starts, before SolidCraft can show anything (an