Metalのデバッグまとめ（随時更新）

Metalのデバッグに関連する機能やツールの使い方を本記事にまとめていこうと思います。

## GPUフレームキャプチャ

XcodeにビルトインされているMetalのデバッグ機能。

Metal利用アプリを実行中、カメラ型のアイコン（"Capture GPU Frame"）を押すと、その瞬間のGPUフレームがキャプチャされ、次のような画面になる。

![xcode_gpu_overview_draw_2x.png](https://qiita-image-store.s3.amazonaws.com/0/3180/9f441ee6-7fe1-9c4e-dc8f-a1d5f6738af3.png)

非常に高機能なので、詳細はそれぞれの項にて。


## ラベル

Metalのクラスやプロトコルは文字列型の`label`というプロパティを備えているものが多くある。

例:

- `MTLCommandQueue`
- `MTLResource`
  - `MTLBuffer`, `MTLTexture`
- `MTLFunction`
- `MTLRenderPipelineDescriptor`
- `MTLCommandBuffer`
- `MTLCommandEncoder`


たとえば次のようにラベルをつけておいて、

```swift
commandQueue.label = "HogeCommandQueue"
texture.label = "HogeTexture"
vertexBuffer.label = "HogeVertexBuffer"
texCoordBuffer.label = "HogeTexCoordBuffer"
```

```swift
vertexFunction.label = "HogeVertexFunction"
fragmentFunction.label = "HogeFragmentFunction"
```

```swift
descriptor.label = "HogeRenderPipeline"
```

```swift
commandBuffer.label = "HogeCommandBuffer"
```

```swift
renderEncoder.label = "HogeRenderCommandEncoder"
```

XcodeでGPUフレームをキャプチャすると、ナビゲータ内でのコマンドエンコーダやリソース名に、自分がつけたラベルが表示されるので、識別しやすくなる。

<img width="342" alt="Screen Shot 2018-01-20 at 16.19.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/f59a4d45-1922-9642-bf3c-194737a96a3c.png">

ラベルは Instruments で見た場合にもこんな感じで適用されている。

<img width="971" alt="Screen Shot 2018-01-20 at 16.24.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/25438c30-9b18-f9e2-6c2c-c15b7dce941c.png">

というわけでパスが複雑な処理を行う場合はラベルをつけておくとデバッグやパフォーマンスにおけるボトルネックの特定が捗る。


## デバッググループ

`MTLCommandEncoder`はiOS 8から、**`MTLCommandBuffer`はiOS 11から**以下のようなメソッドが使える。

```swift
public func pushDebugGroup(_ string: String)
public func popDebugGroup()
```

push〜popの間にそのコマンドエンコーダやコマンドバッファに対して行った処理が、XcodeでのGPUフレームキャプチャ画面におけるナビゲータ上にフォルダアイコンでまとめられて表示される。

```swift
commandBuffer.pushDebugGroup("HogeCommandBufferDebugGroup")

guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else {return}
renderEncoder.label = "HogeRenderCommandEncoder"
renderEncoder.pushDebugGroup("HogeCommandEncoderDebugGroup")
renderEncoder.insertDebugSignpost("HogeDebugSignpost")

guard let renderPipeline = renderPipeline else {fatalError()}
renderEncoder.setRenderPipelineState(renderPipeline)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder.setVertexBuffer(texCoordBuffer, offset: 0, index: 1)
renderEncoder.setFragmentTexture(texture, index: 0)
renderEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4)
renderEncoder.endEncoding()

commandBuffer.present(drawable)
commandBuffer.commit()
commandBuffer.waitUntilCompleted()

commandBuffer.popDebugGroup()
renderEncoder.popDebugGroup()
```

<img width="337" alt="Screen Shot 2018-01-20 at 16.40.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/5054d6d2-59a9-489b-180a-75207550628c.png">

## insertDebugSignpost

MTLCommandEncoderのメソッド。

```swift
public func insertDebugSignpost(_ string: String)
```

[公式リファレンス](https://developer.apple.com/documentation/metal/mtlcommandencoder/1458034-insertdebugsignpost)によると、

> Inserts a string into the command buffer.

> When debugging with Xcode, this string may appear.

ちょっと用途がよくわからない。。コマンドバッファへのエンコードがうまくいってるかを確認するため？


## シェーダの処理毎のパフォーマンス確認

ナビゲータの右上の方にあるアイコンをクリックして「**View Frame By Performance**」を選択。（デフォルトは「View Frame By Call」）

![xcode_gpu_view_frame_by_2x.png](https://qiita-image-store.s3.amazonaws.com/0/3180/8488cce6-8f48-d7c9-d3ed-45643fc32a85.png)

リストからパフォーマンスを見たいシェーダを選択すると、ソース上に処理時間のパーセンテージが表示される。

<img width="948" alt="Screen Shot 2018-01-20 at 16.47.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/f7964029-f60d-ea9f-9aa3-7d5ac6433e43.png">

（表示されないケースもあった。理由は分かり次第追記します）


## Remarks

ナビゲータから"Pipeline Statistics"を選択すると、"Remarks"という欄に、warning的な事項が表示される。

<img width="962" alt="Screen Shot 2018-01-20 at 16.52.25 copy.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/ab36faaa-3999-e432-221c-f1a293aac20e.png">


## Instruments

- [InstrumentsのMetal System Traceの使い方 - Qiita](https://qiita.com/shu223/items/fb6de03c59b547430765)

<img width="1396" alt="instruments2.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/dac5ce6d-ab40-5429-af16-2ad1766bf465.png">


## 参考資料

### 書籍

- [Metal入門 - shu223 - BOOTH](https://booth.pm/ja/items/826318)
  - 日本語では初のMetal解説書

### 公式ドキュメント

- [Instruments User Guide: Profiling Templates](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/ProfilingTemplates.html#//apple_ref/doc/uid/TP40004652-CH19-SW13)
  - Metal System Trace Profiling Template
- [Instruments User Guide: Metal Application Instrument](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/MetalApplicationInstrument.html#//apple_ref/doc/uid/TP40004652-CH98-SW1)
- [Instruments User Guide: GPU Hardware Instrument]( https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/GPUHardwareInstrument.html#//apple_ref/doc/uid/TP40004652-CH97-SW1)
- [Instruments User Guide: Graphics Driver Activity Instrument](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/GraphicsDriverActivityInstrument.html#//apple_ref/doc/uid/TP40004652-CH96-SW1)
- [Instruments User Guide: Displayed Surfaces Instrument](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/DisplayedSurfacesInstrument.html#//apple_ref/doc/uid/TP40004652-CH95-SW1)
- [Metal Tools](https://developer.apple.com/library/content/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Dev-Technique/Dev-Technique.html)
- [Specialized Debugging Workflows](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/debugging_with_xcode/chapters/special_debugging_workflows.html#//apple_ref/doc/uid/TP40015022-CH9-SW24)
  - Debugging Metal and OpenGL ES

### WWDCセッション

一次情報としてリファレンスだけでは不十分で、WWDCのセッションでしか話されてない情報も多々ある。

そして**最新年度のだけ観れば十分かというと全然そんなこともなく**、たとえばInstrumentsのMetal System Traceについてのまともな解説は2015年まで遡らないとなかったりするので、「どのセッションでどの（デバッグ関連の）話をしているか」をここに整理しておく。


- [Metal 2 Optimization and Debugging](https://developer.apple.com/videos/play/wwdc2017/607/) (WWDC17)
- [Adopting Metal, Part 1](https://developer.apple.com/videos/play/wwdc2016/602/) (WWDC16)
  - デバッググループの話がちらっと出てくる
- [Metal Performance Optimization Techniques](https://developer.apple.com/videos/play/wwdc2015/610/) (WWDC15)
  - InstrumentsのMetal System Traceの解説（この年が初登場なのでがっつりデモつきの解説）
- [Working with Metal: Advanced](https://developer.apple.com/videos/play/wwdc2014/605/) (WWDC14)
  - XcodeのGPUフレームキャプチャからパフォーマンスのボトルネックを発見するデモ
- [Working with Metal: Overview](https://developer.apple.com/videos/play/wwdc2014/603/) (WWDC14)
  - XcodeのMetalツール（フレームキャプチャ）の概要だけ。目新しい情報ではない
  - （Metal全体の設計思想が語られているのでその点では今観ても有用ではある）