レイトレースされた画像のレンダリングを高速化するためにOpenCLを使用したいのですが、WikipediaページではOpen CLでは再帰が禁止されていると主張しています。これは本当ですか?レイトレーシング時に再帰を広範囲に使用するため、高速化のメリットを享受するには、かなりの量の再設計が必要になります。再帰を防ぐ根本的な制限は何ですか?それを回避する方法はありますか?
レイトレースされた画像のレンダリングを高速化するためにOpenCLを使用したいのですが、WikipediaページではOpen CLでは再帰が禁止されていると主張しています。これは本当ですか?レイトレーシング時に再帰を広範囲に使用するため、高速化のメリットを享受するには、かなりの量の再設計が必要になります。再帰を防ぐ根本的な制限は何ですか?それを回避する方法はありますか?
回答:
本質的には、すべてのGPUが関数呼び出しをサポートできるわけではないためです。たとえサポートできる場合でも、関数呼び出しが非常に遅いか、スタック深度が非常に小さいなどの制限がある場合があります。
シェーダーコードとGPU計算コードは、至る所で関数呼び出しを持っているように見えるかもしれませんが、通常の状況では、それらはすべてコンパイラーによって100%インライン化されています。GPUによって実行されるマシンコードには分岐とループが含まれますが、関数呼び出しは含まれません。ただし、明らかな理由により、再帰的な関数呼び出しをインライン化することはできません。(引数の一部がコンパイル時定数である場合を除き、コンパイラーがそれらを折りたたみ、呼び出しツリー全体をインライン化できるようにします。)
真の関数呼び出しを実装するには、スタックが必要です。ほとんどの場合、シェーダーコードはスタックをまったく使用しません。GPUには大きなレジスタファイルがあり、シェーダーはすべてのデータを常にレジスタに保持できます。(a)一度に飛行できる多くのワープすべてを提供するために多くのスタックスペースが必要になり、(b)GPUメモリシステムは多くのバッチ処理に最適化されているため、スタックを動作させるのは困難です。メモリトランザクションを使用して高いスループットを達成しますが、これはレイテンシを犠牲にします。したがって、ローカル変数の保存/復元などのスタック操作は非常に遅いと推測します。
歴史的に、GPUではハードウェアレベルの関数呼び出しはあまり有用ではありませんでした。コンパイラーですべてをインライン化する方が理にかなっているからです。そのため、GPUアーキテクトは、高速化に注力していません。将来的に効率的なハードウェアレベルの呼び出しが必要な場合、おそらくいくつかの異なるトレードオフが行われる可能性がありますが、(エンジニアリングのすべてと同様に)他の場所でコストが発生します。
レイトレーシングに関する限り、人々が通常この種のことを処理する方法は、トレース中の光線のキューを作成することです。再帰する代わりに、レイをキューに追加します。高レベルのどこかに、すべてのキューが空になるまで処理を続けるループがあります。ただし、古典的な再帰的レイトレーサーから始める場合は、レンダリングコードを大幅に再編成する必要があります。詳細については、Wavefront Path Tracingを参照してください。