相互に関連する5つの拡張機能により、Vulkan API においてレイトレーシングがサポートされています。
また、SPIR-V や GLSL の拡張機能を追加することで、シェーダに必要なプログラマブルな機能を実現しています。
Note
|
多くのレイトレーシングアプリケーションは、大きな連続したメモリの割り当てを必要とします。アドレス空間のサイズが限られているため、32ビットシステムではこれが困難な場合があります。実装は32ビットシステム上で自由にレイトレーシング拡張機能を公開することができますが、アプリケーションはフラグメンテーションによるアロケーションの失敗など、メモリ関連の問題に断続的に遭遇する可能性があります。さらに、いくつかの実装では、32ビットドライバ上でレイトレーシング拡張機能を公開しないことを選択する場合があります。 |
アクセラレーション構造は、レイトレーシングに使用される、実装に依存した幾何学的オブジェクトの不透明な表現です。オブジェクトをアクセラレーション構造としてビルドすることで、レイトレーシングを既知のデータレイアウトに対して、効率的に行うことができます。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
拡張機能は、レイトレーシングパイプラインを導入します。この新しい形式のレンダリングパイプラインは、従来のラスタライズパイプラインから独立しています。レイトレーシングパイプラインは、従来のバーテックス/ジオメトリ/フラグメントステージとは異なる、専用のシェーダステージのセットを利用します。レイトレーシングパイプラインは、レンダリング作業を送信するための専用コマンド(vkCmdTraceRaysKHR
と vkCmdTraceRaysIndirectKHR
)を利用します。これらのコマンドは、従来のラスタライズパイプラインの描画コマンド(vkCmdDraw
と vkCmdDrawIndirect
)にやや類似しています。
レイをトレースするには:
-
vkCmdBindPipeline
でVK_PIPELINE_BIND_POINT_RAY_TRACING_KHR
を使用してレイトレーシングパイプラインをバインドします。 -
vkCmdTraceRaysKHR
またはvkCmdTraceRaysIndirectKHR
を呼び出します。
レイトレーシングパイプラインは、いくつかの新しいシェーダドメインを導入します。その内容は以下の通りです:
-
Ray generation シェーダはレイトレーシングの出発点を表します。レイトレーシングコマンド(
vkCmdTraceRaysKHR
とvkCmdTraceRaysIndirectKHR
)は、コンピュートシェーダと同様に、シェーダの呼び出しのグリッドを起動します。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
拡張機能は、グラフィックス、コンピュート、レイトレーシングパイプラインを含む、すべてのシェーダタイプからのレイのトレースをサポートします。
レイクエリでは、レイトラバーサルコードがシェーダ内に明示的に含まれている必要があります。これは、レイ生成、交差テスト、およびレイ-ジオメトリヒットの処理が別々のシェーダステージとして表現されるレイトレーシングパイプラインとは異なります。その結果、レイクエリは、より広範なシェーダステージからのレイのトレースを可能にする一方で、Vulkan の実装がレイのスケジューリングとトレースに適用できる最適化の範囲を制限します。
この拡張機能は、追加の API エントリポイントを導入するものではありません。関連する SPIR-V と GLSL の拡張機能(SPV_KHR_ray_query
と GLSL_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_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_KHR
をVkRayTracingPipelineCreateInfoKHR::flags
に設定します。
レイトレーシングパイプラインライブラリをフルパイプラインにリンクするには:
-
VkRayTracingPipelineCreateInfoKHR::pLibraryInfo
を設定して、VkPipelineLibraryCreateInfoKHR
のインスタンスを指すようにします。 -
リンクの入力として使用されるパイプラインライブラリで
VkPipelineLibraryCreateInfoKHR::pLibraries
を入力し、VkPipelineLibraryCreateInfoKHR::libraryCount
を適切な値に設定します。
VK_KHR_deferred_host_operations
は、高価な CPU タスクを複数のスレッドに分散させるメカニズムを導入します。スレッドプールを Vulkan ドライバに導入するのではなく、アプリケーションがスレッドを作成して管理できるように設計されています。
VK_KHR_pipeline_library
と同様に、VK_KHR_deferred_host_operations
は、レイトレーシング拡張機能への依存を導入することなく、将来的に他の拡張機能で同じ機能を使用できる可能性を考慮して、独立した拡張機能として定義されました。
遅延をサポートしていることが明記されている操作のみ、遅延させることができます。現在、遅延をサポートしている操作は、vkCreateRayTracingPipelinesKHR
、vkBuildAccelerationStructuresKHR
、vkCopyAccelerationStructureKHR
、vkCopyMemoryToAccelerationStructureKHR
、vkCopyAccelerationStructureToMemoryKHR
のみです。
操作の遅延を要求するには:
-
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
を再度呼び出して再参加できるかもしれません。
-
操作が完了した後(つまり、vkDeferredOperationJoinKHR
が VK_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_KHR
とVK_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_BIT
とVK_ACCESS_INDIRECT_COMMAND_READ_BIT
を使用します。 -
アクセラレーション構造の間接ビルドには、間接バッファに対して
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR
とVK_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_EXT
とVK_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
|
他のコピー操作とは異なり、
|
レイクエリオブジェクトは、スレッドプライベートストレージを圧迫することがあるため、 パフォーマンスのためにはできるだけ少なくするのが望ましいです。 ほとんどの場合、複数のレイをトレースするとしても、終了したレイが新しいレイを発行するのであれば、 同じレイクエリオブジェクトを使いまわすことができるはずです。 同じシェーダーで複数のレイクエリが必要になるのは、複数のトラバーサルが同時にアクティブでなければならない場合であり、 シェーダーではアクティブなトラバーサルの数を最小限に抑えるといいでしょう。
レイトレーシングシェーダーステージは、ステージ間でパラメータと結果をやり取りできます。 レイペイロード構造はすべてのトラバーサルステージ間でやり取りでき、 Hit Attribute構造体はトラバーサル制御シェーダーから、 Callable Data構造体はCallableシェーダーで使用できます。
これらの構造体はドライバーで管理されるメモリを消費し、 構造体のサイズ、同時にアクティブなレイの数、 さらには再帰レベルなどの追加要因に基づいて、メモリ総量が増加する可能性があります。
シェーダーでは、これらの構造体のサイズを小さく保つのが望ましいです。