- iOS 10.3+
- tvOS 10.2+
- macOS 10.12+
- Xcode 10.0+
Metal provides low-level, low-overhead access to the graphics processing unit (GPU) of a user’s device, resulting in great apps that use the GPU efficiently. The key to developing such an app is understanding the underlying software and hardware interactions holistically.
In this sample, you’ll learn how to write an app that uses Metal and issues basic rendering commands to the GPU. In particular, you’ll learn how to obtain a Metal device, configure a MetalKit view, create and execute GPU commands, and display rendered content.
The Metal and MetalKit Frameworks
The sample uses two frameworks to display rendered content: Metal and MetalKit. Metal provides access to the GPU, and MetalKit provides common utilities that make it easier to develop a Metal app. Together they seamlessly integrate with the OS and with other frameworks, so you can focus on GPU programming.
One of MetalKit’s most useful features is the
MTKView class, which wraps
NSView objects and configures Metal-specific Core Animation functionality. In particular, a MetalKit view automatically sets up and manages a continuous rendering loop that provides you with a 2D, displayable resource, commonly known as a drawable, for each frame.
Separate Your Rendering Loop
When developing a Metal app, it’s often useful to separate your rendering loop into its own class. Using a separate class, you can better manage your initial Metal setup code and per-frame Metal commands. This common architecture is demonstrated by the
AAPLRenderer class, which is initialized with a MetalKit view and is assigned as the view’s delegate.
Respond to View Events
MTKView object implements the
draw methods. These methods notify your renderer of the MetalKit view’s resizing and drawing events.
The view calls the
mtkmethod whenever the window size changes (macOS) or a relayout operation, such as a device orientation change, occurs (iOS and tvOS). You can then respond to the new size of the view and change your rendering resolution, if necessary.
View: drawable Size Will Change:
The view calls the
drawmethod whenever it’s time to render a new frame, as specified by the frame rate (for example, 60 FPS) set on the view’s
preferredproperty. This callback is typically the main event that begins the execution of your rendering loop.
Frames Per Second
Metal Command Objects
MTLDevice object represents a GPU. Typically, you call the
MTLCreate method to obtain a single
MTLDevice object that represents the default GPU of a device. A
MTLDevice object provides information about a GPU, but its main purpose is to create other objects that can interact with the GPU.
The first object all apps need to interact with the GPU is a
You use a
MTLCommand object to create and organize
MTLCommand objects, ensuring that they’re sent to the GPU in the correct order.
For every frame, a new
MTLCommand object is created and filled with commands that are executed by the GPU.
There are many different types of GPUs, each accepting and interpreting commands in their own unique way. A
MTLCommand object coalesces these commands into a single submission, but they must first be encoded in a device-agnostic way using a
MTLCommand object. There are a few different types of
MTLCommand classes, each used to execute different types of tasks on the GPU. This sample demonstrates the use of a
MTLRender subclass, which specifically encodes rendering commands into a command buffer.
This sample uses a
MTLRender object to encode GPU commands that render pixels to the MetalKit view’s drawable. To do so, the render command encoder must be specifically associated with this drawable.
To create a
MTLRender object, you must first create a
MTLRender object. A
MTLRender is a lightweight, temporary object with a number of configurable properties that are used by an existing
MTLCommand object to create a new
MTLRender object. Afterward, the
MTLRender object is no longer needed.
The following diagram illustrates the relationship between Metal’s command objects. To summarize:
Command buffers are created from a command queue
Command encoders encode commands into command buffers
Command buffers are then committed and sent to the GPU
The GPU executes the commands and renders the results to a drawable
Prepare a Frame
A MetalKit view creates a new
MTLRender object for every frame, provided via the
current property. This render pass descriptor is preconfigured with view-specific properties, some derived from the view’s drawable, and can be used to easily and conveniently create a new
Commands encoded into this
MTLRender object render to the view’s drawable. By default, creating a
MTLRender object implicitly encodes a clear command that the GPU executes before any other rendering commands. The clear command sets the drawable’s pixels to a clear color that’s updated at the start of the rendering loop.
Finalize a Frame
Typically, Metal apps call many
MTLRender methods that encode explicit rendering commands into a command buffer. For simplicity, this sample doesn’t actually encode explicit rendering commands; only the implicit clear command is encoded. After creating the
MTLRender object, the sample simply calls the
end method to indicate that the encoder is finalized.
When the encoder is finalized, the command buffer accepts two final commands: present and commit.
Because the GPU doesn’t draw directly to the screen, it’s prevented from drawing pixels before it has finished executing commands. To avoid a poor user experience resulting from incomplete drawables, you call the
present method. This method tells Metal to wait for the GPU to finish rendering to a drawable before presenting it onscreen.
The GPU also doesn’t execute commands immediately. Calls to a
MTLCommand object are executed only after the
commit method is called. Metal then schedules the command buffer for execution. When the GPU begins execution, the drawable is cleared with a new color. When the GPU completes execution, the rendered drawable is presented onscreen.
In this sample, you learned how to write an app that uses Metal and issues basic rendering commands to the GPU.
In the Using a Render Pipeline to Render Primitives sample, you’ll learn how to render basic geometry in Metal.