Objects in Metal

Unlike OpenGL, Metal treats most rendering components as Objects. For example, Metal creates a rendering pipeline as a Pipeline object. The shaders, known as functions in Metal, are encapsulated in Library objects. Vertex data is encapsulated in Buffer objects.

Metal requires a set of objects to be created before rendering can occur. The primary objects in Metal are:

Device Object

Command Queue Object

Library/Function Objects

Pipeline Objects

Buffer Objects

Render Pass Descriptor Object

Command Buffer Object

Render Command Encoder Object

Metal Rendering Process

The Metal Rendering Process consists of the initialization of these objects, which are created once and last for the lifetime of the application:

Device Object

Command Queue Object

Library/Function Objects

Pipeline Objects

Buffer Objects

And the creation of these objects during each render pass:

Render Pass Descriptor Object

Command Buffer Object

Render Command Encoder Object

The Metal rendering process consists of the following steps:

Iniatilizing Objects

Create a device object, i.e. a GPU

Create a Command Queue object

Create a CAEMetalLayer

Create a Library object

Create a Pipeline object

Create buffer objects

Render-Pass

Retrieve the next drawable layer

Create a Render Pass Descriptor object

Create a Command Buffer object

Create a Render Command Encoder object

Present the drawable

Commit the Command Buffer

Initializing Metal Objects

Create a Metal Device

The Metal rendering process starts with the creation of an MTLDevice object. An MTLDevice represents an abstraction of the GPU. A device object is used to create other kinds of objects such as buffers, textures and function libraries.

Create a Command Queue Object

An MTLCommandQueue object is created from an MTLDevice. The Command Queue object provides a way to submit commands/instructions to the GPU.

Create a CAMetalLayer

Next, we must provide a destination texture for the rendering pipeline.

The destination of a rendering pipeline is a Framebuffer. A framebuffer contains several attachments such as Color, Depth, and Stencil attachments. However, a framebuffer can display the rendering content to a screen ONLY if a texture has been attached to a framebuffer attachment. The CAMetalLayer object provides a texture that is used as a rendering destination.

Create a Library and Function Objects

Next, we must create the Vertex and Fragment functions (Shaders) that will be used by the rendering pipeline. The Vertex and Fragment are MTLFunction objects and are created through an MTLLibrary object.

Create a Rendering Pipeline Object

Now is time to create the rendering pipeline object.

An MTLRenderPipelineState object represents a rendering pipeline. However, unlike other objects, you do not directly create a pipeline object. Instead, you create it indirectly through an object called Rendering Pipeline Descriptor.

The MTLRenderPipelineDescriptor describes the attribute of a render pipeline states. For example, it defines the Vertex and Fragment functions used by the pipeline. As well as the color attachment properties.

Create Buffer Objects

The next step is to load MTLBuffers objects with vertex data. i.e., vertices, normals, UV, etc.

The interaction between these objects is illustrated below:

Metal Render-Pass

Whereas, objects mentioned in "Initializing Metal Objects" are created once and last for the lifetime of your application, objects created during the render pass are often created and short-lived.

The steps in the rendering-pass stage are as follow:

Retrieve the next drawable layer

As mentioned above, a framebuffer requires a texture before it can display the rendering results to the screen. Thus, you must ask the CAMetalLayer object for the next available texture.

Create a Render Pass Descriptor object

Next, we must describe the various actions that must occur before and after the render pass. For example, you may want to clear the rendering texture to a particular color.

These actions are described through the MTLRenderPassDescriptor object. Moreover, The MTLRenderPassDescriptor object links the texture provided by the CAMetalLayer as the pipeline destination texture.

Create a Command Buffer object & Encoder object

We then create an MTLCommandBuffer object. An MTLCommandBuffer object stores drawing commands and rendering pipeline states until the buffer is committed for execution by the GPU.

However, these drawing commands and rendering pipeline states must be encoded by an MTLRenderCommandEncoder object before they are stored into the MTLCommandBuffer object. Essentially, the MTLRenderCommandEncoder translates the commands into a format the GPU can understand.

Present the drawable layer

I mentioned previously that the CAMetalLayer provided a texture that serves as the rendering destination. With our commands encoded, we must inform the command buffer that it must present this texture to the screen once rendering is complete.

Commit the Command Buffer

Finally, the Command Buffer is committed, and loaded into the Command Queue; where it waits to be executed by the GPU.

The render pass routine is illustrated below:

In summary, the Metal rendering process can be summarized in these steps:

Create a device object, i.e. a GPU

Create a Command Queue object

Create a CAEMetalLayer

Create a Library object

Create a Pipeline object

Create buffer objects

Retrieve the next drawable layer

Create a Render Pass Descriptor object

Create a Command Buffer object

Create a Render Command Encoder object

Present the drawable

Commit the Command Buffer

Your First Metal Application

Let's create a simple Metal application. We are going to render a simple red rectangle on the screen.

At this point, the initialization of the Metal objects is complete. We need to create sort of a timer that constantly calls a render-pass function. The best way to do this is through a CADisplayLink object.

If you look at step 10, you told the render encoder to use information in the vertexBuffer (which holds your rectangle vertices) and link it to the buffer at index 0. The Vertex function shader receives these information a vertex at a time.

Fragment function shader sets the color of the fragment to red.

And that is it. If you have an iPhone or an iPad, connect it to your Mac and run the project. You should see a red rectangle on the screen. Note, the iOS simulator does not support Metal yet.