Building Metal Application

// 1. Device 획득
guard let device = MTLCreateSystemDefaultDevice() else {
    return
}
// 2. CommandQueue 생성
guard let commandQueue = device.makeCommandQueue() else {
    return
}
// 3. 리소스 생성
var bytes: [UInt8] = // Raw Pointer로 넘겨야 됨. 
device.makeBuffer(bytes: &bytes, length: bytes.count, options: [])

// 4. 파이프라인 생성
let desc = MTLRenderPipelineDescriptor()

// 셰이더 설정
let library = device.makeDefaultLibrary()
desc.vertexFunction = library?.makeFunction(name: "myVertexShader")
desc.fragmentFunction = library?.makeFunction(name: "myFragmentShader")

// 프레임 버퍼의 픽셀 포맷 지정
desc.colorAttachments[0].pixelFormat = .bgra8Unorm

guard let renderPipeline = try? device.makeRenderPipelineState(descriptor: desc) else { return }

// 5. 뷰 만들기
let view = MyView() //layer가 CAMetalLayer인 뷰
struct Vertex {
	float4 position;
	float4 color;
};

struct VertexOut {
	float4 position [[position]];
	float4 color;
}

vertex VertexOut myVertexShader(
const global Vertex* vertexArray [[buffer(0)]],
unsigned int vid                 [[vertex_id]])
{
	VSOut out;
	out.position = vertexArray[vid].position;
	out.color = vertexArray[vid].color
	return out;
}

fragment float4 myFragmentShader(
	VertexOut interpolated [[stage_in]] {
	return interpolated.color;
}
// 현재 프레임의 타겟 drawalbe을 가져온다.
// 쓸 수 있는 텍스쳐가 당장 없으면 스레드가 블록될 수 있다.
let drawable = metalLayer.nextDrawable()

// 1. 커맨드 버퍼 획득
let commandBuffer = commandQueue.makeCommandBuffer()

let renderDesc = MTLRenderPassDescriptor()

renderDesc.colorAttachments[0].texture = drawable.texture
renderDesc.colorAttachments[0].loadAction = .clear
renderDesc.colorAttachments[0].clearColor = MTLClearColor()

// 2. 랜더 패스 시작
let render = commandBuffer?.makeRenderCommandEncoder(descriptor: renderDesc)

// 3. 드로잉
render?.setRenderPipelineState(renderPipeline)
render?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
render?.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3)
render?.endEncoding()

// 4. 커맨드 버퍼에 커밋

// Core Animation에 해당 drawable 객체를 표시할지를 알려줌
// 당장은 그려진게 없으니, 커밋 이후에 다그려지면 메탈이 Core Animation에 통보
commandBuffer?.present(drawable)

// commandBuffer를 CommandQueue에 커밋
// 큐에 들어간 이후에 실제 모든 작업이 일어난다.
commandBuffer?.commit()

Metal Shading Language