From bb514c158e1604916b32fc8c9bbe602a78727742 Mon Sep 17 00:00:00 2001 From: cacaosteve <1307385+cacaosteve@users.noreply.github.com> Date: Thu, 20 Nov 2025 21:25:37 -0800 Subject: [PATCH] macOS: Enumerate GPUs first; prefer low-power non-removable; fall back to system default (#38164) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Some macOS environments report no devices via MTLCopyAllDevices, causing startup failure with “unable to access a compatible graphics device,” especially on Apple Silicon. Change: Prefer MTLCreateSystemDefaultDevice (metal::Device::system_default()) first. If None, enumerate devices and select a non‑removable, low‑power device by preference. Why this works: On Apple Silicon the system default is the unified GPU; on Intel, the fallback keeps a stable policy and avoids accidentally picking removable/high‑power devices. Impact: Fixes startup on affected ASi systems; improves selection consistency on Intel multi‑GPU. Behavior unchanged where system_default() succeeds. Risk: Low. Aligns with Apple’s recommended selection path. Still fails early with a clearer message if no Metal devices exist. Closes #37689. Release Notes: - Fixed: Startup failure on some Apple Silicon machines when Metal device enumeration returned no devices by falling back to the system default device. --------- Co-authored-by: 张小白 <364772080@qq.com> Co-authored-by: Kate --- .../gpui/src/platform/mac/metal_renderer.rs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 9e5d6ec5ff02c74b4f0acfada8eee3d002bfd06b..550041a0ccb4cd39bc7a86317d9540e806af2a28 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -132,11 +132,21 @@ impl MetalRenderer { // Prefer low‐power integrated GPUs on Intel Mac. On Apple // Silicon, there is only ever one GPU, so this is equivalent to // `metal::Device::system_default()`. - let mut devices = metal::Device::all(); - devices.sort_by_key(|device| (device.is_removable(), device.is_low_power())); - let Some(device) = devices.pop() else { - log::error!("unable to access a compatible graphics device"); - std::process::exit(1); + let device = if let Some(d) = metal::Device::all() + .into_iter() + .min_by_key(|d| (d.is_removable(), !d.is_low_power())) + { + d + } else { + // For some reason `all()` can return an empty list, see https://github.com/zed-industries/zed/issues/37689 + // In that case, we fall back to the system default device. + log::error!( + "Unable to enumerate Metal devices; attempting to use system default device" + ); + metal::Device::system_default().unwrap_or_else(|| { + log::error!("unable to access a compatible graphics device"); + std::process::exit(1); + }) }; let layer = metal::MetalLayer::new();