判断设备是否支持metal
guard let device = MTLCreateSystemDefaultDevice() else {
label.text = "Your GPU does not support Metal!"
return
}
label.text = "Your system has the following GPU(s):\n" + "\(device.name)\n"
创建 MTKView 的子类MetalView
Storyboard 或者 xib 上找个View 集成于 MetalView 或者 拖一个 MTKView 继承 MetalView
/// 缓存区的命令串行队列
var commandQueue: MTLCommandQueue?
/// 渲染管道
var rps: MTLRenderPipelineState?
/// 矩阵
var verters: [Float] = [
0, 0.1, 0,
-0.5, -0.5, 0,
0.5, -0.5, 0
]
/// 定点缓存数据
var vertexBuffer: MTLBuffer?
required init(coder: NSCoder) {
super.init(coder: coder)
self.clearColor = MTLClearColor.init(red: 0.22, green: 1, blue: 0.4, alpha: 1)
render()
}
func render() {
// 给 device 赋值
device = MTLCreateSystemDefaultDevice()!
// 1. 创建顶点缓存区
self.vertexBuffer = device!.makeBuffer(bytes: verters,
length: verters.count * MemoryLayout<Float>.size, options: [])
//2.1 makeDefaultLibrary:加载项目中所有.metal文件,当然也可以使用其他API来指定metal文件
let library = device!.makeDefaultLibrary()!
// 2.2 从库中加载顶点函数、片元函数 着色器语言和原理
let vertex_func = library.makeFunction(name: "vertex_shader")
let frag_func = library.makeFunction(name: "fragment_shader")
let rpld = MTLRenderPipelineDescriptor()
rpld.label = "test"
//3.2 可编程函数,用于处理渲染过程中每个顶点、片元
rpld.vertexFunction = vertex_func
rpld.fragmentFunction = frag_func
// rpld.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm
// view.colorPixelFormat
//3.3 确定渲染管线中颜色附着点0的颜色组件;使用当前view颜色组件
rpld.colorAttachments[0].pixelFormat = self.colorPixelFormat
/// 这个暂时使用无效 invalid 如果xib 里面有值则会闪退,此处目前一定要为 invalid
self.depthStencilPixelFormat = MTLPixelFormat.invalid
do {
try rps = device!.makeRenderPipelineState(descriptor: rpld)
} catch let error {
// self.printView("\(error)")
print("\(error)")
}
commandQueue = device!.makeCommandQueue()
}
override func draw(_ rect: CGRect) {
//6. 用于保存渲染过程中的一组结果,渲染命令编码器描述符
if let drawable = currentDrawable, let rpd = currentRenderPassDescriptor {
rpd.colorAttachments[0].clearColor = MTLClearColorMake(0, 0.5, 0.5, 1.0)
//5. 为每一次渲染创建一个新的命令缓冲区
let commandBuffer = commandQueue!.makeCommandBuffer()
// 创建渲染命令编码器,通过它来进行渲染的配置
let commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: rpd)
// 设置当前渲染管道状态对象
commandEncoder?.setRenderPipelineState(rps!)
//10. 载入顶点数据
//通过VertexInputIndexVertices将数据传递到顶点函数的对应buffer中
commandEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
/// 绘制
commandEncoder?.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 3, instanceCount: 1)
// 结束编码
commandEncoder?.endEncoding()
// 锁定缓存区, 等待缓冲区处理完成后绘制
commandBuffer?.present(drawable)
// 将命令缓存区提交给GPU
commandBuffer?.commit()
}
}
创建metal 文件 MyVertex.metal
#include <metal_stdlib>
using namespace metal;
vertex float4 vertex_shader(const device packed_float3 * vertices[[buffer(0)]], uint vertexId[[vertex_id]]){
return float4(vertices[vertexId], 1);
}
fragment half4 fragment_shader() {
return half4(1,1,0.5,1); //红色
}
模拟器不支持 请跑mac 应用