OpenGL や DirectX11 を触っていた自分が Vulkan 入門した際に感じたことをまとめました。
まだ Vulkan 初心者ですが、これから入門する人の参考になればと思います。
座標系について
実装の初期では -1 から +1 の値の範囲で三角形を作って手早く描画を確認してみたいことがあります。
NDC(デバイス正規化座標系)について DirectX/OpenGL では 画面中央を (0,0,0) として 左(-1.0) から 右(+1.0)、上部(+1.0)、下部(-1.0) という範囲になっています。
Zの座標については DirectX では、 near 0, far 1.0 で、 OpenGL では near -1.0, far +1.0 となっています。
Vulkan は上記のどちらにも属しませんでした。
画面中央を (0,0,0) をしたときに 左(-1.0) から 右(+1.0)、上部(-1.0)、下部(+1.0) という範囲になっています。また near 0, far 1.0 となっています。
この差のため、上向きの三角を作ったつもりが、下を向いているなんてことになります。
補足
これらの詳細仕様については OpenGL では 13.6 Coordinate Transformations に、Vulkan では 23.4 Coordinate Transformations に記載されています。
見比べてみても、 Y については反転していないし、なぜだ!と悩みました・・・。
これを解決するポイントは、Viewport 原点はどこか、でした。 OpenGL では bottom-left が原点(0,0) です。 Vulkan では upper-left が原点になります。
つまり、増加する方向は違います。 ちゃんと仕様書は頭から漏れなく読んで頭に入れておきましょうということですね。
あとこれらを見つけた後、いい解説ページを見つけました。
https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/
シザーテスト
DirectX や OpenGL ではシザーテストの ON/OFF が制御できました。 Vulkan では、シザーテストは常に ON で OFF とすることができません。
OFF を設定したい場合には、現在の範囲を全指定するようにして、擬似的に実現していくしかないようです。
情報元は、 API without Secrets: Introduction to Vulkan Part 3: First Triangle のサイトに書かれていました。
気付かずにはまりそうなポイントですね。
拡張機能について
拡張機能を使用するために
OpenGL に慣れているからこそのハマリポイントでした。
vkGetInstanceProcAddr など、まさに OpenGL のときと同じような関数ポインタ取得のための API が用意されています。
これを使って関数ポインタを得て、実行すればその機能が使える!と思ってしまいますが、そうではありません。Vulkan のインスタンスや、デバイスの初期化の時に、有効化する拡張機能を設定する必要があります。その後で、この関数などで関数ポインタを取得して使用する、という手順が必要です。
また、Vulkan ではインスタンスの拡張機能と、デバイスの拡張機能と分かれています。それぞれ使用したい拡張機能がどちらに属するのかを確認して設定するようにしましょう。
いきなり関数ポインタが取得できてしまって、実行できる環境があるかもしれません。しかし自分が試した環境では、該当関数を実行して内部でクラッシュという状況に出遭いました。こうならないためにも正規の手順を踏むようにしましょう。
RenderDoc と拡張機能
RenderDoc を使う際にはベンダー依存の拡張機能を使わないようにしましょう。
初期化の際に、有効化の指定するだけで動作不良の原因になります。動作がおかしいときにデバッグ目的で使用したいでしょうが、RenderDoc がそのうち対応してくれるか、拡張機能を使っていても大丈夫なベンダー提供のデバッグツールを使うしかないかなと思います。
バリデーションレイヤーの有効化
Vulkan SDK が更新されるとこのバリデーションレイヤも更新されます。その結果、今までは警告されなかったのものが出現するといったこともあります。現時点ではまだまだ開発途上のようで警告されないものも多いと思います。
また、公開されているサンプルプログラムも増えてきていますが、このバリデーションレイヤーを有効化した状態で動かすとたくさんの警告が出るものがほとんどです。プログラム自体はエラーを返さず動いているようなものもありますが、バリデーションレイヤーの警告を信じるならば、たまたまその環境では問題なく動いた、といったものでしょう。
サンプルコードを公開する方はぜひバリデーションレイヤーを有効化して、警告はつぶすようにして頂きたく思います。あと、SDKを更新したタイミングで、公開しているサンプルコードは問題なく動くのか、あるいは確認した SDK バージョンはどれなのか、その辺りの情報もセットでほしい感じです。
バリデーションで警告されない事例
データのコピーには転送元・転送先のサイズを確認しましょう。
転送元のサイズよりも大きい領域をコピーしようとした際に、デバイスロストになったり、プログラムのハングアップになったりしました。とくにプライマリターゲットに書いた領域をリードバックしようとする際には注意が必要です。手抜きして、 AdjustWindowRect でのサイズ調節をすっ飛ばした時にこの問題に出遭いました。警告してくれなかったバージョンは 1.0.37 でした。いずれこのあたりのチェックも入るかもしれませんね。
[amazonjs asin=”0134464540″ locale=”JP” title=”Vulkan Programming Guide: The Official Guide to Learning Vulkan (OpenGL)”]