2016-10-13 4 views
4

WWDC 2016の "What's new in Metal"ビデオでfunction_constantsについて学びました。それはUberShadersにかなりの数の言及がありました。 simplePassThrough、defferredなどのようなパスの異なる種類に使用できる断片的なシェーダを作成したいと考えています。以下は、どのように使用したいかです。Metalのfunction_constantsを使ってUberShaderを作成する正しい方法は何ですか?

constant int passType [[function_constant(0)]]; 
constant bool simplePassThrough = (passType == 0); 
constant bool forwardShading = (passType == 1); 
constant bool deferredShading = (passType == 2); 

fragment FragmentOutStruct UberFragmentShader() 
{ 
FragmentOutputStruct frgOut; 
if (simplePassThrough) { 
    // Update frgOut 
} else if (forwardShading) { 
    // Update frgOut 
} else if (deferredShading) { 
    // Update frgOut 
} 
return frgOut; 
} 

これは正しいアプローチですか?この方法を使用すると、最終的にコンパイルされたMTLFunctionにブランチが多く見えますか?

答えて

6

これは関数定数の正当な使用例であり、実行時に分岐コストは発生しません。これは、(例えば、if(false) { ... }と等価であるため)コンパイラは決して実行できないコードを排除するからです。

6

はい、あなたは正しい方向にあります。 (As @warrenm noted already.しかし、彼の答えを少し拡張する...)

あなたの例は、関数定数を導入するWWDC16 sessionのAppleのショーと本質的に同じです。あなたの "ブランチ"はすべて関数定数値から直接派生しています。シェーダーコンパイラが(あなたのアプリケーションをビルドするときに)関数定数値に依存するコードを通して可能なパスのそれぞれに対してIRバリアントを生成できることを意味します。ここで

、あなたはシェーダにintを渡しているが、それはそれは2つのシェーダ変異体をコンパイルしなければならないという意味ではありません - コンパイラは、いくつかの静的解析を行うと、ベース4つの可能なコードパスがあることがわかりますその値(0,1,2、およびanything-else、最後はifステートメントを完全に削除し、frgOutを返します)。

実行時に、Metalフレームワークは、定数に渡す値に基づいてGPUに送信する4つのシェーダのうち、シェーダ/ GPUに分岐がないことを判断します。あなたが1の値を渡す場合は、基本的に次のようになりシェーダ実行しているたとえば、:

fragment FragmentOutStruct UberFragmentShader() { 
    FragmentOutputStruct frgOut; 
    // Update frgOut per `if (forwardShading)` chunk of original shader source 
    return frgOut; 
} 

そして、あなたが見ることができるように、そのシェーダには分岐はありません。

関連する問題