インターフェイスの使用に関する制限
現在の GPU ハードウェアでは、シェーダー実行時のスロット情報の変動はサポートされていません。そのため、if ステートメントや switch ステートメントなどの条件式の中でインターフェイスの参照を変更することはできません。
次のシェーダー コードの例は、この制限が発生する状況と使用可能な代替アプローチを示しています。
インターフェイスが次のように宣言されているとします。
interface A { float GetRatio(); bool IsGood(); }; interface B { float GetValue(); }; A arrayA[6]; B arrayB[6];
クラスが次のように宣言されているとします。
class C1 : A { float var; float GetRatio() { return 1.0f; } bool IsGood() { return true; } }; class C2 : C1, B { float GetRatio() { return C1::GetRatio() * 0.33f; } float GetValue() { return 5.0f; } bool IsGood() { return false; } }; class C3 : B { float var; float GetValue() { return -1.0f; } }; class C4 : A, B { float var; float GetRatio() { return var; } float GetValue() { return var * 2.0f; } bool IsGood() { return var > 0.0f; } };
条件式 (if ステートメント) の中でインターフェイスの参照を変更することはできません。
float main() : wicked { float rev; { A a = arrayA[0]; for( uint i = 0; i < 6; ++i ) { if( arrayA[i].IsGood() ) { // This forces the loop to be unrolled, // since the slot information is changing. a = arrayA[i]; rev -= arrayA[i-2].GetRatio(); } else { // This causes an error since the compiler is // unable to determine the interface slot rev += arrayB[i].GetValue() + a.GetRatio(); } } } return rev; }
インターフェイス宣言とクラス宣言を変更せずに、インデックスを使用することによって、同じ機能を実現しながら、強制的なループの展開を回避できます。
float main() : wicked { float rev; { uint index = 0; for( uint i = 0; i < 6; ++i ) { if( arrayA[i].IsGood() ) { index = i; rev -= arrayA[i-2].GetRatio(); } else { rev += arrayB[i].GetValue() + arrayA[index].GetRatio(); } } } return rev; }