OpenCLで再帰が禁止されているのはなぜですか?


19

レイトレースされた画像のレンダリングを高速化するためにOpenCLを使用したいのですが、WikipediaページではOpen CLでは再帰が禁止されていると主張しています。これは本当ですか?レイトレーシング時に再帰を広範囲に使用するため、高速化のメリットを享受するには、かなりの量の再設計が必要になります。再帰を防ぐ根本的な制限は何ですか?それを回避する方法はありますか?


2
GPUは別の方法で動作します。(一部のアーキテクチャ)はグローバルな「プログラムスタック」の概念を持たないため、これらでは再帰的な関数呼び出しはできません。OpenCLはおそらく最小公分母を採用しているため、GPU間での移植性を完全に維持することはできません。新しいCUDAハードウェアは、ある時点で再帰のサポートを導入したようです:stackoverflow.com/q/3644809/1198654
glampert

回答:


27

本質的には、すべてのGPUが関数呼び出しをサポートできるわけではないためです。たとえサポートできる場合でも、関数呼び出しが非常に遅いか、スタック深度が非常に小さいなどの制限がある場合があります。

シェーダーコードとGPU計算コードは、至る所で関数呼び出しを持っているように見えるかもしれませんが、通常の状況では、それらはすべてコンパイラーによって100%インライン化されています。GPUによって実行されるマシンコードには分岐とループが含まれますが、関数呼び出しは含まれません。ただし、明らかな理由により、再帰的な関数呼び出しをインライン化することはできません。(引数の一部がコンパイル時定数である場合を除き、コンパイラーがそれらを折りたたみ、呼び出しツリー全体をインライン化できるようにします。)

真の関数呼び出しを実装するには、スタックが必要です。ほとんどの場合、シェーダーコードはスタックをまったく使用しません。GPUには大きなレジスタファイルがあり、シェーダーはすべてのデータを常にレジスタに保持できます。(a)一度に飛行できる多くのワープすべてを提供するために多くのスタックスペースが必要になり、(b)GPUメモリシステムは多くのバッチ処理に最適化されているため、スタックを動作させるのは困難です。メモリトランザクションを使用して高いスループットを達成しますが、これはレイテンシを犠牲にします。したがって、ローカル変数の保存/復元などのスタック操作は非常に遅いと推測します。

歴史的に、GPUではハードウェアレベルの関数呼び出しはあまり有用ではありませんでした。コンパイラーですべてをインライン化する方が理にかなっているからです。そのため、GPUアーキテクトは、高速化に注力していません。将来的に効率的なハードウェアレベルの呼び出しが必要な場合、おそらくいくつかの異なるトレードオフが行われる可能性がありますが、(エンジニアリングのすべてと同様に)他の場所でコストが発生します。

レイトレーシングに関する限り、人々が通常この種のことを処理する方法は、トレース中の光線のキューを作成することです。再帰する代わりに、レイをキューに追加します。高レベルのどこかに、すべてのキューが空になるまで処理を続けるループがあります。ただし、古典的な再帰的レイトレーサーから始める場合は、レンダリングコードを大幅に再編成する必要があります。詳細については、Wavefront Path Tracingを参照してください


6
私はこの秘密のソースを共有したがりませんが、これを処理するために、固定最大バウンスカウントと固定サイズ(および固定反復回数のループ)を持つという幸運がありました。また(これが本当の秘密のソースです!)マテリアルは反射性または屈折性のどちらかですが、両方は使用しないため、光線が跳ね返っても分割されません。このすべての最終結果は、再帰型ではなく再帰的なタイプのレイトレースレンダリングです。
アランウルフ

末尾再帰が好きですか?
タンメイパティル

末尾再帰関数は反復関数に変換できるため、末尾再帰を実行するのにスタックは必要ありません。OpenCLコンパイラはこれを自動的に行いませんか?
アンダーソングリーン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.