Repository navigation
fix: follow the system GPU on dual-GPU Macs - #2776
AasishDairelSahayaGrinspan wants to merge 3 commits into
Conversation
|
@AasishDairelSahayaGrinspan is attempting to deploy a commit to the Cap Software Inc Team on Vercel. A member of the Team first needs to authorize it. |
|
@AasishDairelSahayaGrinspan thanks for digging into this on real hardware, the device logs make the macOS diagnosis clear. A few things before we can take it: 1) |
9751dbb to
709f6e0
Compare
709f6e0 to
d9deb92
Compare
|
Updated the default to The short version on the 2019 MBP, on battery with only the main window open:
Head is |
|
Thanks @AasishDairelSahayaGrinspan, this is a big improvement: the patch is macOS-only now, the |
|
Addressed in 44daf4d.
Checks: One unrelated note: macOS |
|
Captured from the built app at Both the GPUI renderer and the wgpu renderer/encoders are on the 5300M. For comparison, |
|
@greptileai review |
| power_preference: cap_rendering::gpu_power_preference( | ||
| wgpu::PowerPreference::LowPower, | ||
| ), |
There was a problem hiding this comment.
With CAP_GPU_PREFERENCE unset on macOS, gpu_power_preference(LowPower) returns PowerPreference::None. This direct request_adapter call never uses system_metal_adapter. The vendored Metal backend sorts discrete GPUs first, so blur can wake the discrete GPU even when macOS and GPUI use integrated graphics, increasing battery use.
Route this request through the same system-device matching used by create_shared_device, while preserving forced software rendering.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/camera_blur.rs
Line: 189-191
Comment:
**Blur skips system GPU choice**
With `CAP_GPU_PREFERENCE` unset on macOS, `gpu_power_preference(LowPower)` returns `PowerPreference::None`. This direct `request_adapter` call never uses `system_metal_adapter`. The vendored Metal backend sorts discrete GPUs first, so blur can wake the discrete GPU even when macOS and GPUI use integrated graphics, increasing battery use.
Route this request through the same system-device matching used by `create_shared_device`, while preserving forced software rendering.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Fixed in c09abaf. camera_blur.rs and camera_blur_portable.rs now go through cap_rendering::request_wgpu_adapter, which uses the same MTLCreateSystemDefaultDevice() match as create_shared_device when CAP_GPU_PREFERENCE is unset, and still forces the fallback adapter when software rendering is requested. The vendored wgpu-hal orders discrete devices first, so the previous direct None request could indeed wake the dGPU; that path is gone.
| + device.is_removable(), | ||
| + if prefer_low_power { | ||
| + !device.is_low_power() | ||
| + } else { | ||
| + device.is_low_power() |
There was a problem hiding this comment.
CAP_GPU_PREFERENCE=high still prefers any built-in GPU over an external GPU because is_removable() is the first sort key. If an Intel Mac has integrated graphics and an external discrete GPU, integrated graphics wins despite the explicit high-performance request.
Rank the requested power class first and use removability only to break ties.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/patches/zed-gpu-preference.patch
Line: 30-34
Comment:
**High ignores external GPUs**
`CAP_GPU_PREFERENCE=high` still prefers any built-in GPU over an external GPU because `is_removable()` is the first sort key. If an Intel Mac has integrated graphics and an external discrete GPU, integrated graphics wins despite the explicit high-performance request.
Rank the requested power class first and use removability only to break ties.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Fixed in c09abaf. The sort key now ranks the requested power class first and uses is_removable() only as a tie-breaker, so CAP_GPU_PREFERENCE=high can select an external discrete GPU over a built-in iGPU.
|
Both Greptile findings are fixed in c09abaf:
The new workflows are waiting for approval. Could you approve them when you get a chance? |
|
@greptileai review |
Supersedes #1759 for the shipping GPUI app. #1759 only changed the old Tauri
Info.plist; the key alone could never fix this because GPUI explicitly requested the integrated GPU.Problem
On Intel Macs with a discrete AMD GPU,
gpui_macos::metal_renderer::create_devicesortedmetal::Device::all()by(is_removable, !is_low_power). On my 2019 MacBook Pro (i7-9750H, Intel UHD 630 + Radeon Pro 5300M) that always selected the low-power Intel iGPU, so the UI was rendered and composited on the integrated GPU even when macOS itself was using the AMD GPU. This caused the lag and GPU-related instability reported in #1759.Reproduction with GPUI's exact predicate:
Fix
apps/desktop-gpui/patches/zed-gpu-preference.patchto the existing GPUI patch stack.create_devicenow followsMTLCreateSystemDefaultDevice()by default;CAP_GPU_PREFERENCE=high|performance|discreteforces the high-performance GPU (including an external GPU over a built-in iGPU), andlow|integrated|batteryforces the iGPU.cap_rendering::request_wgpu_adapter. On macOS the hardware adapter is matched toMTLCreateSystemDefaultDevice()by name, because wgpu'sPowerPreference::Nonetakes the first Metal adapter and wgpu-hal orders discrete devices before low-power ones. Off macOS each call site keeps its previous preference (HighPerformancefor the renderer and probe,LowPowerfor camera blur) when the variable is unset.Info.plistunchanged.NSSupportsAutomaticGraphicsSwitchingis omitted; I also testedtrue, and it did not change the system default or mux decision on this machine.apps/desktop-gpui/README.md.Verification
cargo check --workspaceandcargo check --workspace --all-targetsinapps/desktop-gpui.cargo test -p cap-rendering gpu_power_preference --lib— 2 passed, andsystem_metal_adapter --lib— 1 passed. The latter asserts the wgpu Metal adapter name equalsMTLCreateSystemDefaultDevice()'s name on this machine.node --test scripts/prepare-gpui-dependency.test.mjs— 8/8, including a fresh checkout with the new patch applied../scripts/prepare-gpui-dependency.shvalidates the patch stack on an already-prepared checkout.RUST_LOG=gpui_macos=info; with noCAP_GPU_PREFERENCEit logsselected system Metal device: AMD Radeon Pro 5300M, withCAP_GPU_PREFERENCE=highit logsselected Metal device: AMD Radeon Pro 5300M (low_power=false), and withlowit logs the Intel UHD 630.Following the system Metal device adapter_name=AMD Radeon Pro 5300MandUsing hardware GPU adapter adapter_name="AMD Radeon Pro 5300M" adapter_backend=Metal adapter_device_type=DiscreteGpu, so the GPUI renderer and the wgpu renderer/encoders land on the same GPU.CAP_GPU_PREFERENCE=lowselectsIntel(R) UHD Graphics 630,highselects the 5300M.lowoverride logs are unchanged (5300M and UHD 630 respectively).cargo fmt --all --check.Idle GPU power
Measured on the same 2019 MacBook Pro, on battery, automatic graphics switching on, only the Cap main window open, same debug binary.
powermetrics --samplers gpu_poweron this Intel Mac only reports the Intel GPU (GPU 0 name IntelIG) and has no AMD power counter, so I sampled the AMD driver's"Total Power(W)"from IOAccelerator at 1 Hz for 30 s, plus whole-system battery current.CAP_GPU_PREFERENCE=low(old iGPU choice)CAP_GPU_PREFERENCE=high(previous default)system(new default)The high-performance path keeps the dGPU powered at ~15.6 W while the mux stays on the iGPU, so both GPUs are active. With
system, macOS moves the display to the 5300M (muxGFX0), powers down the iGPU, and system draw returns to the iGPU-only baseline in the 10 s sample. The default is nowsystem;CAP_GPU_PREFERENCE=highremains available for users who need to force the dGPU, andlowrestores the old battery behavior.Battery draw is noisier than the AMD counter because other apps were running; the stable result is that the previous high-performance default kept the dGPU at ~15.6 W for as long as the window was open.


Confidence Score: 5/5
The PR appears safe to merge; both previous findings are fixed.Summary
Cap now follows the system GPU on macOS by default, with
CAP_GPU_PREFERENCEoverrides.Reviews (2) · Last reviewed commit: "fix: follow the system GPU for camera bl..." · Reviewed by Greptile