Skip to content

Latest commit

 

History

History
50 lines (30 loc) · 8.08 KB

common_pitfalls.adoc

File metadata and controls

50 lines (30 loc) · 8.08 KB

新規 Vulkan 開発者のためのよくある落とし穴

これは、Vulkan API の前提、罠、アンチパターンの短いリストです。「ベストプラクティス」のリストではなく、Vulkan を初めて使う開発者が陥りやすいミスを取り上げています。

検証レイヤ

開発時には、検証レイヤが有効になっていることを確認してください。検証レイヤは、Vulkan API を使用する際のミスを発見するための重要なツールです。パラメータのチェック、オブジェクトのライフタイム、スレッディング違反など、すべてのエラーチェックに対応しています。これが有効になっていることを確認するには、出力ストリームに「Debug Messenger Added」というテキストが表示されているかどうかを確認します。詳細については、Vulkan SDK レイヤのドキュメントを参照してください。

Vulkan はツールの箱

Vulkan では、ほとんどの問題は複数の方法で対処でき、それぞれにメリットとデメリットがあります。「完璧」なソリューションが存在することは稀であり、それを見つけることに執着することは、無益な努力となる可能性があります。問題に直面した際は、現在のニーズを満たし、複雑になりすぎない適切なソリューションを見つけるようにしてください。Vulkan の仕様書は有用ですが、実際に Vulkan をどのように使用するかについての最良の情報源ではありません。代わりに、このガイド、ハードウェアのベストプラクティスガイド、チュートリアル、その他の記事などの外部ソースを参照して、より詳細な情報を得るようにしてください。最後に、さまざまなソリューションのプロファイリングは、どのソリューションを使用すべきかを見極めるための重要な要素です。

コマンドバッファの記録

初期の Vulkan チュートリアルやドキュメントの多くは、コマンドバッファを一度書き、可能な限り再利用することを推奨しています。しかし実際には、再利用することで宣伝されているようなパフォーマンス上のメリットが得られることはほとんどなく、実装の複雑さのために自ずと開発の負担も大きくなります。計算されたデータを再利用することは一般的な最適化であり、直感的ではないかもしれませんが、オブジェクトの追加や削除が行われるシーンの管理や、フレームごとに発行されるドローコールを変化させるフラスタムカリングなどのテクニックを考えると、コマンドバッファの再利用は深刻な設計上の課題となります。コマンドバッファを管理するためのキャッシングスキームと、再記録が必要かどうかを判断するための状態の維持が必要です。それよりも、フレームごとに新しいコマンドバッファを再記録するほうが良いでしょう。パフォーマンスが問題となる場合は、記録をマルチスレッド化したり、ポストプロセスなどの変化しないドローコールに二次的コマンドバッファを使用することもできます。

複数のパイプライン

グラフィックスの VkPipeline には、ドローコールを実行するために必要な状態の組み合わせが含まれます。異なるシェーダ、ブレンドモード、頂点レイアウトなどでシーンをレンダリングするには、それぞれの可能性に応じたパイプラインが必要になります。パイプラインの作成やドローコール間のスワップにはコストがかかるため、必要なときにだけ行うのがいいでしょう。しかし、さまざまな技術や機能を使って、パイプラインの作成や交換をさらに減らすことは、利益が保証されないまま複雑さを増すことになり、逆効果になります。大規模なエンジンでは必要かもしれませんが、そうでなければボトルネックになることはないでしょう。パイプラインキャッシュを使用すれば、より複雑なスキームに頼ることなく、コストをさらに削減することができます。

スワップチェーンイメージごとのリソース重複

フレームをパイプライン化することは、パフォーマンスを向上させる一般的な方法です。複数のフレームを同時にレンダリングし、それぞれが必要なリソースのコピーを使用することで、リソースの競合をなくしてレイテンシーを低減します。これを簡単に実装すると、スワップチェーン内の各イメージに必要なリソースを複製します。問題は、スワップチェインの各イメージにレンダリングリソースを1回ずつ複製しなければならないと仮定してしまうことです。各フレームに使用されるコマンドバッファやセマフォなど、一部のリソースについては実用的ですが、スワップチェーンイメージで1対1の複製が必要になることはあまりありません。Vulkan には柔軟性があり、開発者はどのレベルの複製が状況に適しているかを選択することができます。たとえば、ユニフォームバッファや1フレームに1回更新されるデータなど、多くのリソースは2つのコピーで済むかもしれませんし、全く重複を必要としないものもあります。

1つのキューファミリの複数のキュー

ハードウェアプラットフォームによっては、キューファミリごとに1つ以上の VkQueue があります。これは、別々のキューから同じキューファミリに作業をサブミットすることができるので便利です。このような利点はありますが、余分なキューを作成したり使用したりすることが必ずしも良いとは限りません。具体的なパフォーマンスに関する推奨事項については、ハードウェアベンダのベストプラクティスガイドを参照してください。

ディスクリプタセット

ディスクリプタセットは、シェーダで使用されるデータを用途や更新頻度ごとにグループ化するためのものです。Vulkan Spec では、ハードウェアが同時に少なくとも4つのディスクリプタセットの使用をサポートすることが義務付けられており、ほとんどのハードウェアは少なくとも8つのディスクリプタセットをサポートしています。そのため、常識的な範囲で複数のディスクリプタセットを使用しない理由はほとんどありません。

正しい API の使い方

検証レイヤは多くの種類のエラーを検出できますが、完璧ではありません。以下に、良い習慣と、奇妙な動作に遭遇したときに考えられるエラーの原因を簡単に示します。

  • すべての変数と構造体を初期化します。

  • 各構造体に正しい sType を使用します。

  • 正しい pNext チェーンの使用方法を確認し、必要ない場合は null にします。

  • Vulkan にはデフォルト値がありません。

  • 正しい列挙型、VkFlag、ビットマスクの値を使用してください。

  • C++の Vulkan.hpp など、型安全な Vulkan ラッパーの使用を検討してください。

  • 関数の戻り値、たとえば VkResult をチェックします。

  • 必要に応じてクリーンアップ関数を呼び出します。