Article

Handling External GPU Additions and Removals

Register and respond to external GPU notifications initiated by a user.

Overview

A user can connect or disconnect external GPUs from a Mac at any time. The sequence of events that occurs when a user properly adds and removes an external GPU from the system is:

  1. The user connects an external GPU to the Mac. The GPU is added to the system, and Metal makes it available to your app.

  2. While one or more external GPUs are connected to the system, macOS presents an item in the menu bar that allows the user to safely disconnect any external GPUs.

  3. The user selects an external GPU for a safe disconnect.

  4. Metal notifies your app of the request, and you migrate all current and future work off of the external GPU.

  5. After all apps (including yours) have stopped using the external GPU, macOS notifies the user that it's safe to disconnect the GPU.

  6. The external GPU is removed from the system, and the user can disconnect the GPU from the Mac.

To support external GPUs effectively, you must ensure that your app responds to these events appropriately.

Set a GPU Eject Policy

You can modify your app's Info.plist file to control how your app responds to a safe disconnect request for an external GPU. This response is determined by the GPUEjectPolicy key, which takes the following values:

  • wait. Set this value to manually respond to the safe disconnect request. Your app must register and respond to the removalRequested notification posted by Metal. macOS waits for your app to remove all references to the external GPU before notifying the user that it's safe to disconnect the GPU.

  • relaunch. Set this value to allow macOS to quit and relaunch your app with another GPU. Your app can implement the application(_:willEncodeRestorableState:) method to save any state before it quits, and it can implement the application(_:didDecodeRestorableState:) method to restore any saved state after it relaunches.

  • kill. Set this value to allow macOS to force your app to quit.

To support external GPUs effectively, set a wait value and respond to a safe disconnect request appropriately.

Register for External GPU Notifications

Call the MTLCopyAllDevicesWithObserver(_:_:) function to get a list of all the Metal devices available to a system and register an observer that's called whenever this list changes (or may change due to a safe disconnect request).

let devicesWithObserver = MTLCopyAllDevicesWithObserver(handler: { (device, name) in
    self.handleExternalGPUEvents(device: device, notification: name)
})
deviceList = devicesWithObserver.devices
deviceObserver = devicesWithObserver.observer

To deregister the observer, call the MTLRemoveDeviceObserver(_:) function.

Respond to External GPU Notifications

Metal notifies your app about these external GPU events:

  • wasAdded. Metal posts this notification when an external GPU is added to the system. Evaluate the updated list of devices and consider using the new addition.

  • removalRequested. Metal posts this notification when the user initiates a safe disconnect request for an external GPU. Your app has approximately one second to migrate work off the device and remove all references to it. If your app fails to do so, macOS notifies the user that your app is blocking the safe disconnect request.

  • wasRemoved. Metal posts this notification when an external GPU is removed from the system and your app still has references to that device. If the user safely disconnected an external GPU, Metal posts this notification after it posts a removalRequested notification. If the user unexpectedly disconnected an external GPU, Metal posts this notification without first posting a removalRequested notification. After an external GPU is removed, any command buffers queued for the device are completed with an error, and any new API calls that reference the device fail with an error.

Set up a method to respond to the notifications, and pass this method to the handler parameter of the MTLCopyAllDevicesWithObserver(_:_:) function.

func handleExternalGPUEvents(device: MTLDevice, notification: MTLDeviceNotificationName) {
    switch notification {
    case .wasAdded:
        // Handle addition
        break
    case .removalRequested:
        // Handle safe disconnect
        break
    case .wasRemoved:
        // Handle removal
        break
    default:
        break
    }
}

See Also

Selecting GPUs on Mac

Device Selection and Fallback for Graphics Rendering

Demonstrates how to work with multiple GPUs and efficiently render to a display.

Device Selection and Fallback for Compute Processing

Demonstrates how to work with multiple GPUs and efficiently execute a compute-intensive simulation.

About External GPUs

Learn how to support external GPUs in your macOS apps and games.

About Multi-GPU and Multi-Display Setups

Learn about the different ways that a user can connect external GPUs and external displays to a Mac computer.

About GPU Bandwidth

Learn about some of the main factors that affect bandwidth between a GPU and a system on a Mac.

Getting Different Types of GPUs

Obtain, identify, and choose suitable GPUs for your app.

Getting the GPU that Drives a View's Display

Keep up to date with the optimal device for your display.