macOS: Enumerate GPUs first; prefer low-power non-removable; fall back to system default (#38164)
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 <work@localcc.cc>
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user