Article

Capturing a Frame Programmatically

Invoke the Metal frame debugger from your app under the specific runtime conditions you choose.

Overview

Use MTLCaptureManager to programmatically control GPU frame capture.

When you start a capture, you filter the results by choosing whether the capture contains the commands of a specific MTLDevice, command queue, or those defined by a custom MTLCaptureScope.

When you stop the capture, Xcode halts your app and presents its results in the Metal frame debugger. Depending on the runtime conditions you choose to stop the capture, it enables you to capture a specific frame, just a part of a frame, or implement a custom UI that triggers a capture.

Capture a Device or Command Queue

To start capturing commands for a specific MTLDevice or MTLCommandQueue, call the startCapture(device:) or startCapture(commandQueue:) method. To stop capturing commands, call the stopCapture() method.

func triggerProgrammaticCapture() {
    MTLCaptureManager.shared().startCapture(device: device)
}

func runMetalCommands() {
    let commandBuffer = commandQueue.makeCommandBuffer()!
    // Do Metal work
    commandBuffer.commit()
    MTLCaptureManager.shared().stopCapture()
}

The capture manager only captures commands within MTLCommandBuffer objects that are created after the capture starts and are committed before the capture stops.

Capture a Custom Scope

To define boundaries for a MTLCaptureScope, call the begin() and end() methods just before and after the commands that you want to capture. To start capturing commands for a specific capture scope, call the startCapture(scope:) method. The capture stops when your app reaches the corresponding end() method of the given capture scope.

func setupProgrammaticCaptureScope() {
    myCaptureScope = MTLCaptureManager.shared().makeCaptureScope(device: device)
    myCaptureScope?.label = "My Capture Scope"
}

func triggerProgrammaticCaptureScope() {
    guard let captureScope = myCaptureScope else { return }
    MTLCaptureManager.shared().startCapture(scope: captureScope)
}

func runMetalCommands() {
    myCaptureScope?.begin()
    let commandBuffer = commandQueue.makeCommandBuffer()!
    // Do Metal work
    commandBuffer.commit()
    myCaptureScope?.end()
}

The capture scope only captures commands within MTLCommandBuffer objects that are created after the scope begins and are committed before the scope ends.

Capture Multiple Frames

When you capture a frame programmatically, you can capture Metal commands that span multiple frames by using a custom capture scope. For example, by calling begin() at the start of frame 1 and end() after frame 3, the trace will contain command data from all the buffers that were committed in the three frames.

See Also

Capturing a Frame Programmatically

class MTLCaptureManager

An object you use to capture customized frame data in your app.

protocol MTLCaptureScope

An object that defines custom boundaries for a GPU frame capture.