-2

I'm following a tutorial - https://www.raywenderlich.com/7475-metal-tutorial-getting-started - to learn how to use metal. I've done exactly what the tutorial said to do and no errors pop up before I try to build it, then it says build failed, along with the error - cannot load module 'metal' as 'Metal'. I can't find an answer anywhere else, so can someone help me fix this? I'm new to coding and I'm expecting this to have a straightforward solution.

Edit: So I just discovered that there was indeed a very simple solution. I hadn't downloaded the materials for the tutorial. But now that I have, another error has shown up, saying Use of unresolved identifier 'vertexBuffer'

Here's my entire code, just to resolve any confusion -

viewControllerer.swift -

import Metal
var device: MTLDevice!
var metalLayer: CAMetalLayer!
var pipelineState: MTLRenderPipelineState!
var commandQueue: MTLCommandQueue!
var timer: CADisplayLink!


class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
      metalLayer = CAMetalLayer()          // 1
      metalLayer.device = device           // 2
      metalLayer.pixelFormat = .bgra8Unorm // 3
      metalLayer.framebufferOnly = true    // 4
      metalLayer.frame = view.layer.frame  // 5
      view.layer.addSublayer(metalLayer)   // 6

    let dataSize = vertexData.count * MemoryLayout.size(ofValue: vertexData[0]) // 1
    vertexBuffer = device.makeBuffer(bytes: vertexData, length: dataSize, options: []) // 2

    // 1
    let defaultLibrary = device.makeDefaultLibrary()!
    let fragmentProgram = defaultLibrary.makeFunction(name: "basic_fragment")
    let vertexProgram = defaultLibrary.makeFunction(name: "basic_vertex")

    // 2
    let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
    pipelineStateDescriptor.vertexFunction = vertexProgram
    pipelineStateDescriptor.fragmentFunction = fragmentProgram
    pipelineStateDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm

    // 3
    pipelineState = try! device.makeRenderPipelineState(descriptor: pipelineStateDescriptor)


    device = MTLCreateSystemDefaultDevice()
    commandQueue = device.makeCommandQueue()

    timer = CADisplayLink(target: self, selector: #selector(gameloop))
    timer.add(to: RunLoop.main, forMode: .default)
  }
  let vertexData: [Float] = [
     0.0,  1.0, 0.0,
    -1.0, -1.0, 0.0,
     1.0, -1.0, 0.0
  ]

  func render() {
    guard let drawable = metalLayer?.nextDrawable() else { return }
    let renderPassDescriptor = MTLRenderPassDescriptor()
    renderPassDescriptor.colorAttachments[0].texture = drawable.texture
    renderPassDescriptor.colorAttachments[0].loadAction = .clear
    renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(
      red: 0.0,
      green: 104.0/255.0,
      blue: 55.0/255.0,
      alpha: 1.0)

    let commandBuffer = commandQueue.makeCommandBuffer()!
    let renderEncoder = commandBuffer
      .makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
    renderEncoder.setRenderPipelineState(pipelineState)
    renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
    renderEncoder
      .drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3, instanceCount: 1)
    renderEncoder.endEncoding()
    commandBuffer.present(drawable)
    commandBuffer.commit()
  }

  @objc func gameloop() {
    autoreleasepool {
      self.render()
    }
  }
}

Shaders.metal

#include <metal_stdlib>
using namespace metal;

vertex float4 basic_vertex(                           // 1
  const device packed_float3* vertex_array [[ buffer(0) ]], // 2
  unsigned int vid [[ vertex_id ]]) {                 // 3
  return float4(vertex_array[vid], 1.0);              // 4
}

fragment half4 basic_fragment() { // 1
  return half4(1.0);              // 2
}

Note - Shaders.metal is a file that the tutorial says to create

3 Answers3

1

You need to import Metal framework as below (mentioned under Creating an MTLDevice),

import Metal

Currently you are doing as below which is wrong,

import metal
Kamran
  • 14,987
  • 4
  • 33
  • 51
1

The compiler detected a similar name to Metal, which is metal. Sometimes libraries change name in their own different versions, that's why it can be different from the tutorial you're following.

try doing as the error suggest and replacing the import with: import metal

Gustavo Vollbrecht
  • 3,188
  • 2
  • 19
  • 37
0

You need to have a var vertexBuffer: MTLBuffer variable

twohyjr
  • 120
  • 9