Skip to content

Latest commit

 

History

History
230 lines (165 loc) · 20.6 KB

ray_tracing.adoc

File metadata and controls

230 lines (165 loc) · 20.6 KB

レイトレーシング

相互に関連する5つの拡張機能により、Vulkan API においてレイトレーシングがサポートされています。

また、SPIR-V や GLSL の拡張機能を追加することで、シェーダに必要なプログラマブルな機能を実現しています。

Note

多くのレイトレーシングアプリケーションは、大きな連続したメモリの割り当てを必要とします。アドレス空間のサイズが限られているため、32ビットシステムではこれが困難な場合があります。実装は32ビットシステム上で自由にレイトレーシング拡張機能を公開することができますが、アプリケーションはフラグメンテーションによるアロケーションの失敗など、メモリ関連の問題に断続的に遭遇する可能性があります。さらに、いくつかの実装では、32ビットドライバ上でレイトレーシング拡張機能を公開しないことを選択する場合があります。

VK_KHR_acceleration_structure

アクセラレーション構造は、レイトレーシングに使用される、実装に依存した幾何学的オブジェクトの不透明な表現です。オブジェクトをアクセラレーション構造としてビルドすることで、レイトレーシングを既知のデータレイアウトに対して、効率的に行うことができます。VK_KHR_acceleration_structure 拡張機能は、アクセラレーション構造をビルドしたりコピーしたりする機能と、メモリとの間のシリアル化をサポートする機能を導入します。

アクセラレーション構造は、レイパイプライン(VK_KHR_ray_tracing_pipeline)とレイクエリ(VK_KHR_ray_query)の両方に必要です。

アクセラレーション構造を作るためには:

  • VkAccermedStructureBuildGeometryInfoKHR のインスタンスに、アクセラレーション構造タイプ、ジオメトリタイプ、カウント、および最大サイズを入力します。この時点では、ジオメトリデータを入力する必要はありません。

  • ビルドを実行するために必要なメモリサイズを取得するには、vkGetAccloationStructureBuildSizesKHR を呼び出します。

  • アクセラレーション構造(VkAccelerationStructureBuildSizesKHR::accelerationStructureSize)とビルドスクラッチバッファ(VkAccelerationStructureBuildSizesKHR::buildScratchSize)を保持するのに十分なサイズのバッファを割り当てます。

  • vkCreateAccelerationStructureKHR を呼び出して、バッファ内の指定された場所にアクセラレーション構造を作成します。

  • vkCmdBuildAccelerationStructuresKHR を呼び出してアクセラレーション構造をビルドします。ここでは、先に入力した VkAccelerationStructureBuildGeometryInfoKHR をパラメータとして使用し、目的のアクセラレーション構造オブジェクト、ビルド用のスクラッチバッファ、ジオメトリデータポインタ (頂点、インデックス、トランスフォーム用) を追加します。

VK_KHR_ray_tracing_pipeline

VK_KHR_ray_tracing_pipeline 拡張機能は、レイトレーシングパイプラインを導入します。この新しい形式のレンダリングパイプラインは、従来のラスタライズパイプラインから独立しています。レイトレーシングパイプラインは、従来のバーテックス/ジオメトリ/フラグメントステージとは異なる、専用のシェーダステージのセットを利用します。レイトレーシングパイプラインは、レンダリング作業を送信するための専用コマンド(vkCmdTraceRaysKHRvkCmdTraceRaysIndirectKHR)を利用します。これらのコマンドは、従来のラスタライズパイプラインの描画コマンド(vkCmdDrawvkCmdDrawIndirect)にやや類似しています。

レイをトレースするには:

  • vkCmdBindPipelineVK_PIPELINE_BIND_POINT_RAY_TRACING_KHR を使用してレイトレーシングパイプラインをバインドします。

  • vkCmdTraceRaysKHR または vkCmdTraceRaysIndirectKHR を呼び出します。

レイトレーシングパイプラインは、いくつかの新しいシェーダドメインを導入します。その内容は以下の通りです:

Ray Tracing Shaders
  • Ray generation シェーダはレイトレーシングの出発点を表します。レイトレーシングコマンド(vkCmdTraceRaysKHRvkCmdTraceRaysIndirectKHR)は、コンピュートシェーダと同様に、シェーダの呼び出しのグリッドを起動します。Ray generation シェーダはレイを作成し、traceRayEXT() の呼び出しによってトレースを開始します。さらに、ヒットグループからの結果を処理します。

  • Closest hit シェーダは、レイが最も近いジオメトリと交差するときに実行されます。アプリケーションは任意の数の Closest hit シェーダを使用できます。これらは通常、ライティング計算を行うために使用され、再帰的に追加のレイをトレースすることができます。

  • Miss シェーダは、レイがトラバーサル中にどのジオメトリとも交差しなかった場合に、Closest hit シェーダの代わりに実行されます。Miss シェーダの一般的な使用方法は、環境マップをサンプリングすることです。

  • 組み込みの交差テストはレイ-トライアングルテストです。Intersection シェーダでは、カスタムの交点処理が可能です。

  • Any-hit シェーダは、Closest hit シェーダと同様に、交点が報告された後に実行されます。違いは、Any-hit シェーダは、レイの原点に最も近いものではなく、[tmin, tmax] で定義されるレイ区間内の任意の交点に対して呼び出されることです。Any-hit シェーダは交点のフィルタリングに使用されるため、アルファテストの実装によく使用されます。

VK_KHR_ray_query

VK_KHR_ray_query 拡張機能は、グラフィックス、コンピュート、レイトレーシングパイプラインを含む、すべてのシェーダタイプからのレイのトレースをサポートします。

レイクエリでは、レイトラバーサルコードがシェーダ内に明示的に含まれている必要があります。これは、レイ生成、交差テスト、およびレイ-ジオメトリヒットの処理が別々のシェーダステージとして表現されるレイトレーシングパイプラインとは異なります。その結果、レイクエリは、より広範なシェーダステージからのレイのトレースを可能にする一方で、Vulkan の実装がレイのスケジューリングとトレースに適用できる最適化の範囲を制限します。

この拡張機能は、追加の API エントリポイントを導入するものではありません。関連する SPIR-V と GLSL の拡張機能(SPV_KHR_ray_queryGLSL_EXT_ray_query)の API サポートを提供するだけです。

VK_KHR_ray_query によって提供される機能は、VK_KHR_ray_tracing_pipeline によって提供される機能を補完するものであり、この2つの拡張機能は一緒に使用することができます。

rayQueryEXT rq;

rayQueryInitializeEXT(rq, accStruct, gl_RayFlagsNoneEXT, 0, origin, tMin, direction, tMax);

while(rayQueryProceedEXT(rq)) {
        if (rayQueryGetIntersectionTypeEXT(rq, false) == gl_RayQueryCandidateIntersectionTriangleEXT) {
                //...
                rayQueryConfirmIntersectionEXT(rq);
        }
}

if (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionNoneEXT) {
        //...
}

VK_KHR_pipeline_library

VK_KHR_pipeline_library はパイプラインライブラリを導入します。パイプラインライブラリは、VK_PIPELINE_CREATE_LIBRARY_BIT_KHR を使って作成された特別なパイプラインで、直接バインドして使用することはできません。その代わりに、他のパイプラインにリンクできるシェーダ、シェーダグループ、関連する状態のコレクションを表します。

VK_KHR_pipeline_library は、新しい API 関数を直接導入したり、パイプラインライブラリを作成する方法を定義したりしません。代わりに、この機能は VK_KHR_pipeline_library が提供する機能を利用する他の拡張機能に任されています。現在のところ、この唯一の例は VK_KHR_ray_tracing_pipeline です。VK_KHR_pipeline_library は、レイトレーシング拡張機能への依存性を導入することなく、将来的に他の拡張機能で同じ機能を使用する可能性を考慮して、独立した拡張機能として定義されました。

レイトレーシングパイプラインライブラリを作成するには:

  • vkCreateRayTracingPipelineKHR の呼び出し時に、Vk_PIPELINE_CREATE_LIBRARY_BIT_KHRVkRayTracingPipelineCreateInfoKHR::flags に設定します。

レイトレーシングパイプラインライブラリをフルパイプラインにリンクするには:

  • VkRayTracingPipelineCreateInfoKHR::pLibraryInfo を設定して、VkPipelineLibraryCreateInfoKHR のインスタンスを指すようにします。

  • リンクの入力として使用されるパイプラインライブラリで VkPipelineLibraryCreateInfoKHR::pLibraries を入力し、VkPipelineLibraryCreateInfoKHR::libraryCount を適切な値に設定します。

VK_KHR_deferred_host_operations

VK_KHR_deferred_host_operations は、高価な CPU タスクを複数のスレッドに分散させるメカニズムを導入します。スレッドプールを Vulkan ドライバに導入するのではなく、アプリケーションがスレッドを作成して管理できるように設計されています。

VK_KHR_pipeline_library と同様に、VK_KHR_deferred_host_operations は、レイトレーシング拡張機能への依存を導入することなく、将来的に他の拡張機能で同じ機能を使用できる可能性を考慮して、独立した拡張機能として定義されました。

遅延をサポートしていることが明記されている操作のみ、遅延させることができます。現在、遅延をサポートしている操作は、vkCreateRayTracingPipelinesKHRvkBuildAccelerationStructuresKHRvkCopyAccelerationStructureKHRvkCopyMemoryToAccelerationStructureKHRvkCopyAccelerationStructureToMemoryKHR のみです。

操作の遅延を要求するには:

  • vkCreateDeferredOperationKHR を呼び出して VkDeferredOperationKHR オブジェクトを作成します。

  • 遅延させたい操作に、VkDeferredOperationKHR をパラメータとして渡して呼び出します。

  • 上記の操作で返される VkResult を確認します。

    • VK_OPERATION_DEFERRED_KHR は、操作の遅延が成功したことを示します。

    • VK_OPERATION_NOT_DEFERRED_KHR は、操作が正常に即時完了したことを示します。

    • 任意のエラー値は、エラーが発生したことを示します。

遅延操作に対してスレッドをジョインさせ、操作に CPU 時間を与えるには:

  • 操作に参加させたい各スレッドから vkDeferredOperationJoinKHR を呼び出します。

  • vkDeferredOperationJoinKHR が返す VkResult を確認します。

    • VK_SUCCESS は操作が完了したことを示します。

    • VK_THREAD_DONE_KHR は、呼び出したスレッドに割り当てるべき仕事はもうないものの、他のスレッドには完了すべき追加の仕事が残っている可能性があることを示します。現在のスレッドは、vkDeferredOperationJoinKHR を再度呼び出して再参加を試みるべきではありません。

    • VK_THREAD_IDLE_KHR は、呼び出したスレッドに割り当てるべき仕事が一時的に存在しませんが、将来的に追加の仕事が利用可能になる可能性があることを示します。現在のスレッドは、呼び出したスレッドに対して他の有用な作業を行うことができ、後で vkDeferredOperationJoinKHR を再度呼び出して再参加できるかもしれません。

操作が完了した後(つまり、vkDeferredOperationJoinKHRVK_SUCCESS を返した後)、vkGetDeferredOperationResultKHR を呼び出して操作の結果を取得します。

レイトレーシングに関する同期

  • シェーダー内でトレースやクエリを呼び出すには、関連するシェーダステージでアクセラレーション構造に対して VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR を使用します。

  • レイトレーシングパイプラインでシェーダバインディングテーブルにアクセスするには、 VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR と、 VK_ACCESS_SHADER_READ_BIT または VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR のいずれかを使用します。

  • アクセラレーション構造(AS)をビルドするには、VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR と、 アクセスされるリソースに対応するアクセスビットを使用します:

    • 書きこみ対象のASには VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR

    • 読み込み対象のAS(例:更新用)には、VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR

    • スクラッチバッファには VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHRVK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR の両方

    • 頂点/インデックス/インスタンス/トランスフォームバッファには VK_ACCESS_SHADER_READ_BIT

  • アクセラレーション構造のコピーコマンドには、 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR または VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR を使用し、 ソースに応じたアクセスフラグを使用します:

    • 書きこみ対象のASには VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR

    • 読み込み対象のASには VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR

    • 書きこみ対象のバッファには VK_ACCESS_TRANSFER_WRITE_BIT

    • 読み込み対象のバッファには VK_ACCESS_TRANSFER_READ_BIT

  • 間接トレース呼び出しをするには、間接バッファに対して VK_PIPELINE_STAGE_DRAW_INDIRECT_BITVK_ACCESS_INDIRECT_COMMAND_READ_BIT を使用します。

  • アクセラレーション構造の間接ビルドには、間接バッファに対して VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHRVK_ACCESS_INDIRECT_COMMAND_READ_BIT を使用します。

  • マイクロマップのビルドには、 VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT と、 アクセスされるリソースに対応するアクセスビットを使用します:

    • 書きこみ対象のマイクロマップには VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT

    • スクラッチバッファには VK_ACCESS_2_MICROMAP_WRITE_BIT_EXTVK_ACCESS_2_MICROMAP_READ_BIT_EXT の両方

    • 入力バッファには VK_ACCESS_SHADER_READ_BIT

  • マイクロマップのコピーコマンドには、 VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT を使用し、 ソースに応じたアクセスフラグを使用します:

    • 書きこみ対象のマイクロマップには VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT

    • 読み込み対象のマイクロマップには VK_ACCESS_2_MICROMAP_READ_BIT_EXT

    • 書きこみ対象のバッファには VK_ACCESS_TRANSFER_WRITE_BIT

    • 読み込み対象のバッファには VK_ACCESS_TRANSFER_READ_BIT

Note

他のコピー操作とは異なり、VK_PIPELINE_STAGE_TRANSFER_BIT はアクセラレーション構造のコピーには使用できません。

VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR/ VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR の使用には、 VK_KHR_ray_tracing_maintenance1 が必要です。

VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT/ VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT/ VK_ACCESS_2_MICROMAP_READ_BIT_EXT の使用には、VK_EXT_opacity_micromap が必要です。

レイトレーシングのベストプラクティス

同時にアクティブなレイクエリオブジェクトの数を最小限にする

レイクエリオブジェクトは、スレッドプライベートストレージを圧迫することがあるため、 パフォーマンスのためにはできるだけ少なくするのが望ましいです。 ほとんどの場合、複数のレイをトレースするとしても、終了したレイが新しいレイを発行するのであれば、 同じレイクエリオブジェクトを使いまわすことができるはずです。 同じシェーダーで複数のレイクエリが必要になるのは、複数のトラバーサルが同時にアクティブでなければならない場合であり、 シェーダーではアクティブなトラバーサルの数を最小限に抑えるといいでしょう。

レイペイロード、Hit Attribute、およびCallable Dataのサイズを最小限にする

レイトレーシングシェーダーステージは、ステージ間でパラメータと結果をやり取りできます。 レイペイロード構造はすべてのトラバーサルステージ間でやり取りでき、 Hit Attribute構造体はトラバーサル制御シェーダーから、 Callable Data構造体はCallableシェーダーで使用できます。

これらの構造体はドライバーで管理されるメモリを消費し、 構造体のサイズ、同時にアクティブなレイの数、 さらには再帰レベルなどの追加要因に基づいて、メモリ総量が増加する可能性があります。

シェーダーでは、これらの構造体のサイズを小さく保つのが望ましいです。

デバイスローカルメモリを優先する

高速化構造はどのVulkanメモリヒープでも作成できますが、デバイスローカルメモリ上の高速化構造に対するレイトレースが最高のパフォーマンスを期待できるため、優先するといいでしょう。デバイスローカルメモリの容量が不足している場合、ホストローカルメモリ(GPUアクセス可能なシステムメモリ)を使用する必要がありますが、デバイスローカルメモリと同等のパフォーマンスは期待できません。