Skip to content

Using MetalKit part 8

By now, you might have all noticed I am in love with Swift. I am also an avid user of Xcodeplaygrounds. This week we will take our Metal code and put it into a playground. Huzzah, for Metalprototyping in the playgrounds!

Let’s start by creating a new Xcode playground for OS X. Once created, click the Show the Assistant editor button and also press Command + 1 to show the Project navigator as well. Your playground should look like this:

alt text

First thing we do is create Shaders.metal under the Resources folder in the Project navigatorwith the same source code from the previous episode of this series. Next, we create MathUtils.swiftand MetalView.swift under the Sources folder. The only change we make in MathUtils.swift is we create a handy initializer for the Vertex struct:

struct Vertex {
    var position: vector_float4
    var color: vector_float4
    init(pos: vector_float4, col: vector_float4) {
        position = pos
        color = col

In MetalView.swift we need to make more changes though. First, we need to make the class public as we will call it from outside the Sources folder. Consequently, the initializer and the drawRect(:) method need to become public as well. Also, we will create a second initializer so we can create a MetalView with a given frame:

public class MetalView: MTKView {
    required public init(coder: NSCoder) {
        super.init(coder: coder)
    override public init(frame frameRect: CGRect, device: MTLDevice?) {
        super.init(frame: frameRect, device: device)

Next, we need to make a rather curious change because as you notice, creating a Library:

let library = device.newDefaultLibrary()!

fails with this error message: failed assertion `filepath must not be nil.'

Since the playground does not have a default filepath that we could use, we will need to create our own:

func registerShaders() {
    let path = NSBundle.mainBundle().pathForResource("Shaders", ofType: "metal")
    let input: String?
    let library: MTLLibrary
    let vert_func: MTLFunction
    let frag_func: MTLFunction
    do {
        input = try String(contentsOfFile: path!, encoding: NSUTF8StringEncoding)
        library = try device!.newLibraryWithSource(input!, options: nil)
        vert_func = library.newFunctionWithName("vertex_func")!
        frag_func = library.newFunctionWithName("fragment_func")!
        let rpld = MTLRenderPipelineDescriptor()
        rpld.vertexFunction = vert_func
        rpld.fragmentFunction = frag_func
        rpld.colorAttachments[0].pixelFormat = .BGRA8Unorm
        rps = try device!.newRenderPipelineStateWithDescriptor(rpld)
    } catch let e {

Notice that we tell the playground to find a path where a resource named Shaders of type metalexists. Next, we convert that file into a large String and then we create the library from this source.

Finally, we go to the playground’s main page and create a new MetalView with a given frame. Then we tell the playground to present us the live view:

import Cocoa
import XCPlayground
let device = MTLCreateSystemDefaultDevice()!
let frame = NSRect(x: 0, y: 0, width: 300, height: 300)
let view = MetalView(frame: frame, device: device)
XCPlaygroundPage.currentPage.liveView = view

If you are showing the Timeline in the Assistant editor you should have a similar view:

alt text

The source code is posted on Github as usual.

Until next time!

Leave a Reply

Your email address will not be published. Required fields are marked *