iOS: Fix crash on device (#4684)

Currently causes a crash on launch in iOS devices (not Simulators) since
[isHeadless](https://developer.apple.com/documentation/metal/mtldevice/1433377-isheadless),
[isRemovable](https://developer.apple.com/documentation/metal/mtldevice/2889851-isremovable)
and
[isLowPower](https://developer.apple.com/documentation/metal/mtldevice/1433409-islowpower)
are only available on macOS (raises `[AGXG16GDevice isHeadless]:
unrecognized selector sent to instance ... `).

The [preferred
method](https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/getting_the_default_gpu)
in iOS is to access the single GPU device by attempting to create a
default one.

Fixes #4685.
This commit is contained in:
Mitchell Hashimoto
2025-01-06 07:31:21 -08:00
committed by GitHub
2 changed files with 27 additions and 12 deletions

View File

@ -209,20 +209,31 @@ pub const GPUState = struct {
}
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 thats 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;
switch (comptime builtin.os.tag) {
.macos => {
const devices = objc.Object.fromId(mtl.MTLCopyAllDevices());
defer devices.release();
var iter = devices.iterate();
while (iter.next()) |device| {
// We want a GPU thats 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;
}
},
.ios => {
chosen_device = objc.Object.fromId(mtl.MTLCreateSystemDefaultDevice());
},
else => @compileError("unsupported target for Metal"),
}
const device = chosen_device orelse return error.NoMetalDevice;
return device.retain();
}

View File

@ -175,4 +175,8 @@ pub const MTLSize = extern struct {
depth: c_ulong,
};
/// https://developer.apple.com/documentation/metal/1433367-mtlcopyalldevices
pub extern "c" fn MTLCopyAllDevices() ?*anyopaque;
/// https://developer.apple.com/documentation/metal/1433401-mtlcreatesystemdefaultdevice
pub extern "c" fn MTLCreateSystemDefaultDevice() ?*anyopaque;