Android Vulkan(特にMali GPU) のデバッグメモ

## 注意事項

Android Vulkan で不都合があると, デバッグや不都合解析に無限に時間が溶けてしまいます. 最近(2020/02)で Android 9 or later であれば, それなりに多くの confirmance tests をパスしているはずで, ドライバやライブラリは安定してきた感がありますが, まだまだリスクがあります.

まずは, GLES で済むのであれば GLES にしておきましょう.
(ちなみに, Android 9 or 10 では, GLES 2.0 は ANGLE を介して裏では Vulkan で動かしてくれるらしい?)

## コードの構成

まず, なるべくコードを PC と同一にして, PC 上でデバッグしやすくしておきます.

https://github.com/SaschaWillems/Vulkan-glTF-PBR  あたりを参考にするのがおすすめです.

Vulkan アプリのコードは, 基本 C++(NativeActivity)を想定します.

## デバッグの方法

* Vulkan validation layer を有効にする https://qiita.com/syoyo/items/2e6f9b999452ac6c041f
  * Vulkan API を呼び出すレイヤーでのチェック  
* Address sanitizer を on にして Android アプリビルドする
  * C/C++ レイヤーでのバグをチェックする用 
  * Android + cmake で ASAN(Address Sanitizer)を使う https://qiita.com/syoyo/items/4f01e6946ad0aee733f7
* RenderDoc を使う https://renderdoc.org/ (基本 PC でデバッグ. Android も一応ある)
* SwiftShader(PC)で動かす
  * ただ, シェーダ内での out-of-bounds エラーでは, シェーダ(SPIR-V)を LLVM JIT で動かしているためか, あまり有益な stack trace は出してくれない
* (optional) 画面を出さない, offscreen レンダリングの仕組みにして, Termux で Vulkan コードのデバッグができるようにする(e.g. シェーダのテストとか, compute shader で physics とかやりたいなど)
  * Android + Termux で Vulkan 開発を行うメモ https://qiita.com/syoyo/items/5295ae37021544d7cfbfhttps://qiita.com/syoyo/items/5295ae37021544d7cfbf 
* (optional) https://github.com/google/gapid RenderDoc と似たようなデバッガー. ただ, シーンデータが複雑だとトレース取得のメモリが足りないのか, エラーになりあまり使い物になりませんでした(PC GPU のデバッグはなぜか動かない) 
  
### 未検証

* Android シミュレータ(SwiftShader で実行?)で動かしてみる

## よくあるエラー(著者が経験したエラー)

### Descriptor set あたりでリソース不足エラー

Pool で必要なリソース(Uniform buffer, shader storage buffer など, それぞれのリソースに対して)が確保されているか確認しましょう. この場合は, Mali だと Vulkan API が error をレポートしてくれました(Adreno では error 出なかった)

### vkWaitForFences で VK_ERROR_DEVICE_LOST(-4)

https://www.reddit.com/r/vulkan/comments/egpt1i/error_device_lost_on_second_frame_on_large_object/


`vkWaitForFences` を数回後読んだ後に `VK_ERROR_DEVICE_LOST(-4)` に遭遇したら, Uniform buffer or Shader storage buffer あたりの out-of-bounds アクセスを疑ったほうがいいでしょう. 
(実際, 著者が経験したものでは, SSBO への out-of-bounds アクセスエラーが原因でした)

#### robustBufferAccess

out-of-bounds アクセスなどは, `robustBufferAccess` でとりあえず suppress することができます.


http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.101897_0200_00_en/yfx1570448101228.html

https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html


`robustBufferAccess` を有効にするには, 

`VkPhysicalDeviceFeatures.rubustBufferAccess` に VK_TRUE を設定して, 
`VkDevieCreateInfo.pEnabledFeatures` に `VkPhysicalDeviceFeatures` 構造体変数を設定し, `vkCreateDevice` します.

一応, 事前に `vkGetPhysicalDeviceFeatures` で, `rubustBufferAccess` が利用できるかチェックしておきましょう(少なくとも最新 Mali と Adreno では利用できました).

`robustBufferAccess` 有効ではエラーが出ないが, `robustBufferAccess` 無効にするとエラーが出る場合, out-of-bounds アクセス周りがおかしいと判定できます.

### 描画の乱れ

描画の乱れは心の乱れ.

頂点モーフすると glitch が出たりなど.

https://github.com/SaschaWillems/Vulkan-glTF-PBR/issues/7

こう言う感じ.

フレーム間で動的にデータが変化するもの(e.g. Uniform buffer に skinning matrix, morph の weight)は, swapChain ごとに用意しないと描画が乱れます. 
(現在描画中のコマンドに, CPU からデータ上書きすると, GPU で読んだときにデータが前のフレームと次に描画するフレームのデータが混在しておかしくなる. モバイル GPU のように CPU/GPU で共有メモリの場合に顕著に出る)
 
同期に関連する不都合は, validation layers などで検出できないので悩ましいですね.

## Android 向けの個別対応

* 画面の回転や, スリープなどからの復帰 => SwapChain などの作り直し(Vulkan-glTF-PBR にはサンプルコード無いので, 自前でコード書く必要あり)

## SwiftShader で試す.

SwiftShader(CPU Vulkan 実装) を Debug ビルド or ASAN 有効にして実行すると, out-of-bounds アクセスでは seg fault してくれたりします. ただ, シェーダの実行は marl 経由でスレッド実行 and LLVM JIT あたりで実行しているためか, 有意義な stack trace を出してくれないので, 原因が分かりづらいです. シェーダ内で printf とかできるとうれしいところ.

## Mali 向け

Mali は, 性能出すためか, 省電力化を行うためか, 仕様に忠実であり不都合が多い(不定な入力に対して undefined behavior が多い)感じがあります(Adreno と比較して). 
特に, Andreno(や PC GPU)では, out-of-bounds はいい感じにエラーにならずに処理してくれますが, Mali では device lost エラーになります(これはこれで正しい振る舞いですが)

Vulkan API レベルでは, 少なくとも Android 10 + Mali だと, 仕様に忠実であるためか, Adreno より厳格にエラーレポートしてくれる気がします.

また, OS や端末などによっても挙動がことなったりしますので, 何種類かの実デバイスでテストするのが理想です(Vulkan アプリを複数実端末でバッチでテストできる仕組みほしい)

`robustBufferAccess` ですが, いくらかパフォーマンスは落ちる & シーン(シェーダ)によるですが, すごい劇的な性能低下にはならず, 10% くらい遅くなるかな? という感じでした.

### 未検証. arm mobile studio(Mali Graphics Debugger)

最近では Graphics Analyzer と名前が変わっています.
 
https://developer.arm.com/tools-and-software/graphics-and-gaming/arm-mobile-studio

Mali Graphics Debugger, 以前は rooted or hikey みたいな dev board でないと使えなかった気がしますが, 最近は non-rooted(つまり普通に売っているスマホ）でも動くのですね. 

## 問題が起きたときの駆け込み寺とか...

ネットを漁っても, Android + Vulkan はあんまり有益な情報がないことが多いです... :cry:

Tencent ncnn https://github.com/Tencent/ncnn は, 涙ぐましい努力のたまものか, Mali のバグ回避のコードがあって意外と有益です.

Twitter が意外といいかもです. Android Vulkan に詳しい人たちの目に止まれば, なにか解決策を得られるかもしれませんよ?

あとは,, Khronos の Slack に Vulkan channel があります. ただ, 基本 PC GPU 系の人たちが集まっているので, Android 向けにはあまり有益な情報を得られないかもしれません.