나만의 공부 노트
Tutorial - Chapter 1 정리 본문
기본 구조

모듈
import Metal
- 가장 Low 레벨의 Metal 모듈
- 그래픽스 API를 가지고 있다.
import MetalKit
- Metal을 유용하게 쓸 수 있도록 도와주는 유틸리티 모듈
- Metal, Model I/O 모듈을 가지고 있음
- Model I/O의 경우, MetalKit, GLKit, SceneKit 등에서 통합해서 사용할 수 있는 모델 로드 모듈
Metal 디바이스
guard let device = MTLCreateSystemDefaultDevice() else {
fatalError("GPU is not supported")
}
- iOS, watchOS 등은 GPU를 하나만 사용하므로 위의 API를 통해 기본 GPU를 얻어올 수 있다.
let devices = MTLCopyAllDevices()
or
let (devices, observer) = MTLCopyAllDevicesWithObserver() { (device, notification) in self.device(device, issued: notification)}
- macOS는 GPU가 여러 개일 수 있다. default 디바이스를 얻을 수 있지만, 위의 API처럼 여러 개의 GPU 목록 또는 옵저버를 등록하여 추가 & 제거 여부를 실시간으로 감지할 수 있다.
| GPU Type | isLowPower | isRemovable |
| Integrated | true | false |
| Discrete | false | false |
| External | false | true |
GPU의 종류는 3가지 인데, macOS에서 default 디바이스를 얻어오면 Discrete 타입이 얻어진다고 한다.
- Integrated는 인텔 칩 처럼 CPU와 GPU가 같이 있는 GPU 칩을 말하는 것 같다.
- Integrated graphics means a computer where the graphics processing unit (GPU) is built onto the same die as the CPU.
- Discrete는 M1 칩 처럼 GPU가 별도로 구성되어 있는 GPU 칩을 말하는 것 같다.(M1 칩은 CPU와 메모리 공유를 하는게 아닌가? 흠..)
- Discrete graphics is a GPU that is a separate from the processor. Discrete graphics has its own dedicated memory that is not shared with the CPU.
- External는 외장 GPU 칩을 말하는 것 같다.
MTKView
- NSView, UIView를 상속받은 뷰
- delegate에 draw 함수 안에 그리는 로직을 넣으면, fps에 맞게 호출되어 자동으로 그려지는 형태
- delegate를 안쓰면 매 프레임 갱신되지 않는다!
MTKMeshBufferAllocator
- An interface for allocating a MetalKit buffer that backs the vertex data of a Model I/O mesh, suitable for use in a Metal app.
- MDLMeshBufferAllocator 프로토콜의 구현체
MDLMeshBufferAllocator
- Classes adopting this protocol provide different ways of handling mesh buffer data. For example, the MTKMeshBufferAllocator class can share mesh data with Metal buffers for use in rendering.
- 프로토콜
메탈 버퍼 형태로 로드 단계부터 가져오기 위해서, MTKMeshBufferAllocator를 사용하는 것 같다.
MDLMesh
MDLMesh(sphereWithExtent: [0.75, 0.75, 0.75], segments: [100, 100], inwardNormals: false, geometryType: .triangles, allocator: allocator)
segments : vertex 갯수 -> [10, 1]의 결과

inwardNormals : 법선 백터를 안쪽으로 생성할 것인지 -> false가 당연(?)
let mesh = try MTKMesh(mesh: mdlMesh, device: device)
- MTKMesh로 변환해서 사용해야한다.
- device를 allocator에서 사용한 device와 다르게 사용하면 어떻게 될까?
- MDLMesh를 만들 때,
반드시 allocator를 사용하는 것은 아니다.(아니네.. 반드시 필요함) - allocator에서 vertex buffer, index buffer를 만든다고 함
즉, MDLMesh에서 Metal Device가 없어서 MTKMesh를 만들 때에도 device를 넣어주어야 하는 것 같다.- 왜.. device를 반드시 필요로 하지?? allocator면 충분할 것 같은데..
- MDLMesh -> MTKMesh 타입 변환하는데, device가 필요한가? 잘 모르겟다.. 문서도 충분한 설명이 없다 ㅜ
- 그냥 컨버팅하는데 Metal 전용 mesh로 변환하는거라,, 의미상 넣었을 수도
- MDLMesh를 만들 때,
Command

- Command queue
- 보통 일반적으로 하나의 device, command queue를 쓴다.
- Command buffer
- command buffer에 commit을 호출함으로써, Command encoder를 한꺼번에 날릴 수 있다.
- render말구 transfer, compute 등도 한 command buffer 안에 묶을 수 도 있을 듯?
- shadow를 별도 render pass로 빼는 이유가, 물체의 외형만 따서 그림자 그리기 위해(몰랐다..) 최적화를 더 시킬 수 있는 것 같다.
- 뭔가 한 Scene을 구성하는 모든 커맨드를 모아놓는 곳이 Command buffer? 라는 생각이 든다.
- 한 프레임당 한 개의 커맨드 버퍼를 생성한다고 하는 것을 보니.. 맞는듯!?
- Command encoder

MSL
쉐이더 코드는 추후에.. 상세히 분석
- MTLLibrary
- let library = try device.makeLibrary(source: shader, options: nil) 으로 만들 수 있음
- options쪽에는 language version, dynamic library 링킹 등.. 유용한 옵션들을 설정할 수 있다고 한다.
- 컴파일이 잘 되면(sync로 동작한다고 함)
- let vertexFunction = library.makeFunction(name: "vertex_main") 처럼 함수 꺼내올 수 있다.
- 타입은 MTLFunction
MTLRenderPipeline
- MTLRenderPipelineDescriptor : MTLRenderPipelineState를 만들기 위해 필요한 인자들을 모아놓는 structure 같다. 재사용 가능, light 한 듯
- colorAttachments[], vertexFunction, fragmentFunction, vertexDescriptor 등을 셋팅
- 포맷, 쉐이더, 데이터 저장 방식 등을 저장하기 위한 것 같다.(그래서 데이터가 큰 버텍스 버퍼, 텍스쳐 등은 여기서 셋팅하지 않는듯?)
- MTLRenderPipelineState : sync로 생성되며, 처리 시간이 상당함. 맨 처음 앱 구동(?) 시에 필요한 state들을 미리 생성해놓고 사용하는 패턴
Render Pass

- 일단 커맨드 큐로부터, 커맨드 버퍼 생성
- MTLRenderPassDescriptor 생성
- texture attachments들을 지니고 있다고 함(?)
- 보니깐 MTKView에서 currentRenderPassDescriptor를 꺼내오면, MTKView가 원래 가지고 있는 텍스쳐가 colorAttachments[0]에 들어있는 것 같다.(아마 레퍼런스인듯)
- MTLRenderPipelineDescriptor의 colorAttachments[0].pixelFormat과 일치해야하는 것 같다.
- 아직 잘 모르겠다.. 추후에 깊게 파자.
- MTLRenderCommandEncoder 생성
- MTLRenderPipelineState 셋팅
- 이제보니 state는 데이터는 일절 가지고 있지 않고, format & 타입 같은 메타 정보만 담고 있는 것 같다.
- colorAttachments[0].pixelFormat = .bgra8Unorm 을 보니, 픽셀 포맷이 뭔지만 알려주었었다.
- 여기서 설정한 colorAttachments에 맞는 MTLRenderPassDescriptor에 텍스쳐를 올려야하는 거 같다!
- MTLBuffer 셋팅
- setVertexBuffer로 버텍스 버퍼 올려주기
- MTLRenderPipelineState 셋팅
- MTLRenderCommandEncoder에 draw 콜 여러 번 호출
- MTLRenderCommandEncoder에 endEncoding 콜 호출
- MTLRenderCommandEncoder에 present 콜 호출
- MTLRenderCommandEncoder에 commit 콜 호출
'Graphics > Metal' 카테고리의 다른 글
| Tutorial - Chapter 3 정리 (0) | 2023.03.31 |
|---|---|
| Tutorial - Chapter 2 정리 (0) | 2023.03.29 |