“This is the 13th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021”

An overview of the

In the Metal Framework MTKView article, we introduced how to use MTKView to create, configure, and display Metal objects. This article complements the previous article and introduces the basics of Metal rendering graphics content.

In this example, you create a MetalKit view and a render channel, then specify the background color to be erased and update the view by submitting the render channel command.

Prepare the MetalKit view

MetalKit provides a class called MTKView, which is a subclass of NSView (in macOS) or UIView (in iOS and tvOS). MTKView encapsulates many of the details of using Metal to render content to the screen.

MTKView relies on Metal device objects to create resources, so you need to associate the device properties of the view with the existing MTLDevice.


_view.device = MTLCreateSystemDefaultDevice();

Copy the code

Set the clearColor property on MTKView to change the background color of view content by using MTLClearColorMake(_ : : _:) to set the color.


_view.clearColor = MTLClearColorMake(0.0, 0.5, 1.0, 1.0);

Copy the code

There is no animation in the example, so the view needs to be redrawn when it changes shape:


_view.enableSetNeedsDisplay = YES;

Copy the code

Commissioned drawing duties

MTKView relies on the App submitting commands to Metal to generate view content. MTKView uses delegate mode to tell when it should be drawn. To receive delegate callbacks, specify the view’s delegate as an object following the MTKViewDelegate protocol.


_view.delegate = _renderer;

Copy the code

Delegate needs to implement the following two methods:

  • The view calls the mtkView(_ :drawableSizeWillChange:) method every time the size of the content changes. This happens when the view’s window size changes, or when the device orientation changes (on iOS). This allows the App to adjust the resolution based on the size of the view.

  • The view calls the draw(in:) method whenever it needs to update the view’s contents. In this approach, you create a command buffer, encode the command to tell the GPU what to draw and when to display, and queue the command buffer for the GPU to execute. This is sometimes called a frame, and all it does is display a single image on the screen.

Create the render channel descriptor

When drawing, the GPU stores the result into a texture, which is a block of memory that contains the image data and can be accessed by the GPU. In this example, a number of textures are created using MTKView into which the contents of the view display will be rendered. Create multiple textures at once so that when rendered to one texture the contents of another can be displayed.

Drawing involves creating a render pass, which is a set of render commands through which to draw a set of textures. In render channels, textures are also called render targets. To create a render channel, you need a render channel descriptor, which is represented by an instance of MTLRenderPassDescriptor in Metal.


MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;

if (renderPassDescriptor == nil)

{

    return;

}


Copy the code

Render channel descriptors describe a set of render targets and how they should be handled at the beginning and end of a render channel. The view returns a render channel descriptor with a single color attachment that points to a texture. By default, at the start of the render channel, the render target is erased to a solid color that matches the view’s clearColor attribute, and at the end of the render channel, all changes are stored back into the texture.

Since the render channel descriptor for a view can be empty, you need to ensure that the render channel descriptor is not empty before creating the render channel.

Create render channel

Render channels are created by encoding render channel descriptors into command buffers using the MTLRenderCommandEncoder object. Call the makeRenderCommandEncoder(descriptor:) method of the command buffer and pass in the render channel descriptor to generate the MTLRenderCommandEncoder object.


id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];

Copy the code

In this case, no drawing commands are encoded, and the only thing the render channel does is erase the texture, so you can call the encoder’s endEncoding method directly to indicate that the transfer is complete.


[commandEncoder endEncoding];

Copy the code

Render to screen

Textures drawn to do not automatically appear on the screen. In fact, only part of the texture can be displayed on the screen. In Metal, the textures that can be displayed on the screen are managed by a drawable object, through which the textures are displayed.

MTKView automatically creates drawable objects to manage their textures. The currentDrawable property is read to get the drawable object, and the render channel draws the render result into the texture associated with the drawable object.


id<MTLDrawable> drawable = view.currentDrawable;

Copy the code

Call the present(_ 🙂 method in the command line buffer, passing in a drawable object as an argument.


[commandBuffer presentDrawable:drawable];


Copy the code

This method tells Metal that when the command buffer is scheduled to execute, Metal should coordinate with Core Animation to display the texture after rendering. When Core Animation renders a texture, the texture becomes the new content of the view. In this case, this means that the erased texture becomes the new background of the view. The view background changes at the same time that Core Animation refreshes the user interface elements.

Submit command buffer

Finally, the command buffer is submitted to manipulate the GPU work, which in turn renders the frames that update the view.

conclusion

To render a view with Metal, you need to create a MetalKit view and a render channel, configure the necessary view attributes, associate the drawable object with the command buffer, and submit the command buffer to complete the drawing.

Download the sample code for this article