Skip to content

macOS: Enumerate GPUs first; prefer low-power non-removable; fall back to system default#38164

Merged
reflectronic merged 8 commits intozed-industries:mainfrom
cacaosteve:main
Nov 21, 2025
Merged

macOS: Enumerate GPUs first; prefer low-power non-removable; fall back to system default#38164
reflectronic merged 8 commits intozed-industries:mainfrom
cacaosteve:main

Conversation

@cacaosteve
Copy link
Contributor

@cacaosteve cacaosteve commented Sep 15, 2025

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.

@cla-bot
Copy link

cla-bot bot commented Sep 15, 2025

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: steve.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email email@example.com
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

@maxdeviant maxdeviant changed the title macOS: Prefer Metal system default device; stable enumeration fallback (fixes #37689) macOS: Prefer Metal system default device; stable enumeration fallback Sep 15, 2025
@cla-bot
Copy link

cla-bot bot commented Sep 15, 2025

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: steve.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email email@example.com
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

@cacaosteve
Copy link
Contributor Author

recheck

std::process::exit(1);
}
// When multiple devices exist (e.g., Intel iGPU + dGPU or eGPU), prefer low-power, non-removable.
devices.sort_by_key(|d| (d.is_removable(), !d.is_low_power()));
Copy link

@filipwiech filipwiech Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original code sorted by (is_removable(), is_low_power()), while this new one sorts by (is_removable(), !is_low_power()): was there a bug before? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a MacBook with M1 Max and it works for me before and after the change. Hopefully I'm on the right track here so we can get some momentum for a fix. Definitely open to suggestions.

Use metal::Device::system_default() first to select the GPU.
Fall back to Device::all() only if default device is unavailable.
When enumerating, prefer non-removable, low-power devices for stability.
Improves startup on ASi where enumeration returns empty; keeps sensible default on Intel multi‑GPU.
Clarify error when no Metal devices are found.
Fixes zed-industries#37689
@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Sep 16, 2025
@JunkuiZhang
Copy link
Contributor

From my perspective, this PR has two issues:

  • When enumerating GPUs, low-power ones should come first. That way on Intel Macs we’ll use the iGPU instead of the dGPU.

  • On Intel Macs, metal::Device::system_default() actually always returns the dGPU, which means the code for selecting another GPU is never reached, so this PR will instroduce a regression.

@cacaosteve
Copy link
Contributor Author

@JunkuiZhang thank you, I have fixed the issues. is there a way for people who have the issue to try a build?

@SomeoneToIgnore SomeoneToIgnore added the run-bundling Configures PR to run the bundle step label Sep 23, 2025
@JunkuiZhang
Copy link
Contributor

I think your changes make things a bit more complicated than they need to be. If I understand correctly, the issue on your machine is that devices.pop() returns None, which leads to an error being logged and then an immediate exit. A better approach, in my opinion, would be to log the error but not exit right away. Instead, fall back to metal::Device::system_default().

@cacaosteve
Copy link
Contributor Author

thank you. updated.

@zed-industries-bot
Copy link
Contributor

zed-industries-bot commented Sep 29, 2025

Warnings
⚠️
macOS: Enumerate GPUs first; prefer low-power non-removable; fall back to system default
^

Write PR titles using sentence case.

⚠️

This PR is missing release notes.

Please add a "Release Notes" section that describes the change:

Release Notes:

- Added/Fixed/Improved ...

If your change is not user-facing, you can use "N/A" for the entry:

Release Notes:

- N/A

Have feedback on this plugin? Let's hear it!

Generated by 🚫 dangerJS against 38bf822

@cacaosteve cacaosteve changed the title macOS: Prefer Metal system default device; stable enumeration fallback macOS: Enumerate GPUs first; prefer low-power non-removable; fall back to system default Sep 29, 2025
@cacaosteve
Copy link
Contributor Author

recheck

@JunkuiZhang
Copy link
Contributor

I pushed a few changes to your PR, could you check if everything still runs fine on your machine?

@cacaosteve
Copy link
Contributor Author

thank you! yes it still works for me on MacBook Pro M1 Max. I've never been able to reproduce the original issue. your change is good, but sorting with (is_removable(), is_low_power()) then pop() still risks picking a removable eGPU when present.

proposed change:
let mut devices = metal::Device::all();
let device = if devices.is_empty() {
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);
})
} else {
// Prefer iGPU by default; avoid eGPU unless it’s the only device
devices.sort_by_key(|d| (d.is_removable(), !d.is_low_power()));
devices.remove(0)
};

Why:
Prefer non-removable, low-power (iGPU) on Intel for stability/power.
Avoid eGPU by default; use dGPU/iGPU first.
If enumeration is empty (seen in some environments), log and fall back to system_default().
Exit only if both enumeration and system_default() fail.

@JunkuiZhang
Copy link
Contributor

The change you suggested seems logically the same as mine, the only difference is that you’re using !d.is_low_power() while I’m using d.is_low_power(). From my testing, d.is_low_power() seems to be the correct one. But maybe I misunderstood your point, happy to adjust if that’s the case.

@cacaosteve
Copy link
Contributor Author

I cleaned it up a bit more, I hope that's okay. My testing on MacBook Pro M1 Max always works, I was not able to reproduce the original issue.

Prefer non-removable, low-power GPU (iGPU) by ordering with min_by_key(|d| (d.is_removable(), !d.is_low_power())), yielding iGPU → dGPU → eGPU.
If enumeration returns empty (as seen in #37689), log and fall back to metal::Device::system_default(); exit only if both paths fail.
Fixes the prior sort+pop behavior, which could select an eGPU/dGPU unintentionally and is harder to reason about.
Avoids Intel regression where system_default() often picks the dGPU; Apple Silicon (single GPU) behavior is unchanged.

@reflectronic reflectronic merged commit bb514c1 into zed-industries:main Nov 21, 2025
21 of 23 checks passed
11happy pushed a commit to 11happy/zed that referenced this pull request Dec 1, 2025
…k to system default (zed-industries#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 zed-industries#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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement run-bundling Configures PR to run the bundle step

Projects

None yet

Development

Successfully merging this pull request may close these issues.

zed 0.202.7 crash on start up on macbook m1

7 participants