Skip to content

Commit

Permalink
iOS: Fix crash on device (#4684)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mitchellh authored Jan 6, 2025
2 parents 4838bcb + 63a47d0 commit 3461204
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 12 deletions.
35 changes: 23 additions & 12 deletions src/renderer/Metal.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 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;

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 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;
}
},
.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();
}
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/metal/api.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

0 comments on commit 3461204

Please sign in to comment.