mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
renderer/metal: prefer low‐power GPUs
Some Intel MacBook Pro laptops have both an integrated and discrete GPU and support automatically switching between them. The system uses the integrated GPU by default, but the default Metal device on those systems is the discrete GPU. This means that Metal‐using applications activate it by default, presumably as the intended audience is high‐performance graphics applications. This is unfortunate for productivity applications like terminals, however, as the discrete GPU decreases battery life and worsens the thermal throttling problems these machines have always had. Prefer to use an integrated GPU when present and not using an external GPU. The behaviour should be unchanged on Apple Silicon, as the platform only supports one GPU. I have confirmed that the resulting app runs, works, and doesn’t activate the AMD GPU on my MacBook Pro, but have not done any measurements of the resulting performance impact. If it is considered sufficiently noticeable, a GPU preference setting could be added. See <https://github.com/zed-industries/zed/issues/5124>, <https://github.com/zed-industries/zed/pull/13685>, <https://github.com/zed-industries/zed/pull/14738>, and <https://github.com/zed-industries/zed/pull/14744> for discussion, measurements, and changes relating to this issue in the Zed project. The logic implemented here reflects what Zed ended up settling on. The [Metal documentation] recommends using `MTLCopyAllDevicesWithObserver` to receive notifications of when the list of available GPUs changes, such as when [external GPUs are connected or disconnected]. I didn’t bother implementing that because it seemed like a lot of fussy work to deal with migrating everything to a new GPU on the fly just for a niche use case on a legacy platform. Zed doesn’t implement it and I haven’t heard about anyone complaining that their computer caught fire when they unplugged an external GPU, so hopefully it’s fine. [Metal documentation]: https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/multi-gpu_systems/finding_multiple_gpus_on_an_intel-based_mac [external GPUs are connected or disconnected]: https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/multi-gpu_systems/handling_external_gpu_additions_and_removals Closes: #2572
This commit is contained in:
@ -175,7 +175,7 @@ pub const GPUState = struct {
|
||||
instance: InstanceBuffer, // MTLBuffer
|
||||
|
||||
pub fn init() !GPUState {
|
||||
const device = objc.Object.fromId(mtl.MTLCreateSystemDefaultDevice());
|
||||
const device = try chooseDevice();
|
||||
const queue = device.msgSend(objc.Object, objc.sel("newCommandQueue"), .{});
|
||||
errdefer queue.release();
|
||||
|
||||
@ -200,6 +200,25 @@ pub const GPUState = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn chooseDevice() error{NoMetalDevice}!objc.Object {
|
||||
const devices = objc.Object.fromId(mtl.MTLCopyAllDevices());
|
||||
defer devices.release();
|
||||
var chosen_device: ?objc.Object = null;
|
||||
var iter = devices.iterate();
|
||||
while (iter.next()) |device| {
|
||||
// We want a GPU that’s connected to a display.
|
||||
if (device.getProperty(bool, "isHeadless")) continue;
|
||||
chosen_device = device;
|
||||
// If the user has an eGPU plugged in, they probably want
|
||||
// to use it. Otherwise, integrated GPUs are better for
|
||||
// battery life and thermals.
|
||||
if (device.getProperty(bool, "isRemovable") or
|
||||
device.getProperty(bool, "isLowPower")) break;
|
||||
}
|
||||
const device = chosen_device orelse return error.NoMetalDevice;
|
||||
return device.retain();
|
||||
}
|
||||
|
||||
pub fn deinit(self: *GPUState) void {
|
||||
// Wait for all of our inflight draws to complete so that
|
||||
// we can cleanly deinit our GPU state.
|
||||
|
@ -175,4 +175,4 @@ pub const MTLSize = extern struct {
|
||||
depth: c_ulong,
|
||||
};
|
||||
|
||||
pub extern "c" fn MTLCreateSystemDefaultDevice() ?*anyopaque;
|
||||
pub extern "c" fn MTLCopyAllDevices() ?*anyopaque;
|
||||
|
Reference in New Issue
Block a user