Compute shaders are programs that run on the graphics card, outside of the normal rendering pipeline. They can be used for massively parallel GPGPU algorithms, or to accelerate parts of game rendering. In order to efficiently use them, an in-depth knowledge of GPU architectures and parallel algorithms is often needed; as well as knowledge of DirectCompute, OpenGL Compute, OpenCL, CUDA, or OpenCL.
Unity のコンピュートシェーダーは、DirectX 11 DirectCompute テクノロジーと良く似ています。コンピュートシェーダーが使用できるプラットフォームは以下の通りです。
DirectX 11 または DirectX 12 グラフィックス API と Shader Model 5.0 GPU を伴う Windows と Windows ストア
Metal グラフィックス API を使用する macOS と iOS
Vulkan API を伴う Android、Linux、Windows プラットフォーム
現段階で一般的に使用されている OpenGL プラットフォーム (Linux または Windows の OpenGL 4.3、Android の OpenGL ES 3.1)。Mac OS X は OpenGL 4.3 をサポートしません。
現段階で一般的に使用されている多くのコンソール (Sony PS4、Microsoft Xbox One)
コンピュートシェーダーのサポートの有無はランタイムに SystemInfo.supportsComputeShaders を使って確認できます。
通常のシェーダー と同様に、コンピュートシェーダーは、プロジェクトのアセットファイルで .compute ファイル拡張子を持ちます。これらは DirectX 11 スタイルの HLSL 言語で書かれ、最低数の #pragma コンパイラーディレクティブを持ち、コンピュートシェーダーカーネルとしてどの関数をコンパイルするかを示します。
こちらは、コンピュートシェーダーファイルの基本例です。出力テクスチャを赤で塗りつぶします。
// test.compute
#pragma kernel FillWithRed
RWTexture2D<float4> res;
[numthreads(1,1,1)]
void FillWithRed (uint3 dtid : SV_DispatchThreadID)
{
res[dtid.xy] = float4(1,0,0,1);
}
言語は標準の DX11 HLSL で、#pragma kernel FillWithRed
ディレクティブが追加されています。1つのコンピュートシェーダーアセットファイルには、呼び出し可能な1つ以上の コンピュートカーネル
が含まれていなければなりません。そして、その関数は #pragma ディレクティブ
で示されます。 ファイルにはそのほかのカーネルが存在する可能性があります。その場合は、単に 複数の #pragma kernel
を追加するだけです。
複数の#pragma kernel
を使用する場合は、#pragma kernel
ディレクティブと同じ行に//
のコメントは許可されていないことに注意してください。使用すると、コンパイルエラーの原因となります。
#pragma kernel
行はオプションとして、カーネルをコンパイルしている間に複数のプリプロセッサーマクロを後に続けて定義することが可能です。サンプルとしては、
# pragma kernel KernelOne SOME_DEFINE DEFINE_WITH_VALUE=1337
# pragma kernel KernelTwo OTHER_DEFINE
// ...
スクリプトで ComputeShader 型の変数を定義し、アセットへの参照を割り当てます。こうすると ComputeShader.Dispatch 関数を使用してそれらを呼び出すことができます。 詳細は、ComputeShader class を参照してください。
ComputeBuffer クラスはコンピュートシェーダーと密接に関係し、任意のデータバッファ (DX11 用語の 「構造化バッファー」) を定義します。レンダーテクスチャ は、「ランダムアクセス」フラグが設定されている場合 (DX11 の「unordered access view」)、コンピュートシェーダーからの書き込みも可能です。 詳細については、RenderTexture.enableRandomWrite を参照してください。
テクスチャとサンプラーは、Unity では別々のオブジェクトではありません。そのため、コンピュートシェーダでそれらを使用するには、以下の Unity 特有のルールに従う必要があります。
テクスチャ名と同じ名前を使用し、最初にsampler
と表記します (たとえば、Texture2D MyTex
; SamplerState samplerMyTex
)。 この場合、サンプラーはテクスチャの filter/wrap/aniso 設定に初期化されます。
あらかじめ定義されたサンプラーを使用してください。 このため、名前にはLinear
または Point
(フィルタモード用) と、Clamp
または Repeat
(ラップモード用) が必要です。 たとえば、SamplerState MyLinearClampSampler
は、リニアフィルターモードとクランプラップモードを持つサンプラーを作成します。
詳細は、サンプラー状態 を参照してください。
通常のシェーダと同様に、Unity はコンピュートシェーダーを HLSL から他のシェーダー言語に 変換 することができます。したがって、最も簡単なクロスプラットフォームビルドのために、HLSL にコンピュートシェーダーを記述します。ただし、これを行う際に考慮が必要な要因がいくつかあります。
DirectX 11 (DX11) は、他のプラットフォーム (Metal や OpenGL ES など) ではサポートされていない多くの操作をサポートしています。 したがって、DX11 だけの環境を考えるより、サポートが少ないプラットフォームで、シェーダーの挙動を明確に定義する必要があります。 考慮すべき点は以下のとおりです。
アウトオブバンドのメモリアクセスが悪い点。DX11 は、読み込み時に常にゼロを返し、問題なくデータの一部を読み込むかもしれませんが、サポートが少ないプラットフォームでは、これを行う際に GPU がクラッシュする可能性があります。DX11 特有のハック、スレッドグループサイズの倍数と一致しないバッファーサイズ、バッファーの先頭や末尾から隣接するデータ要素を読み取ろうとすること、などの同様の非互換性に注意してください。
リソースを初期化する点。 新しいバッファーとテクスチャの内容は未定義です。 プラットフォームの中にはすべてゼロを示すものもありますが、そうでないものでは、NaN を含めどんな値になることもありえます。
コンピュートシェーダーが宣言するすべてのリソースをバインドします。シェーダーが分岐のために現在の状態でリソースを使用しないことが確実にわかっていても、リソースがバインドされていることを確認する必要があります。
Metal (for iOS and tvOS platforms) does not support atomic operations on Textures. Metal also does not support GetDimensions
queries on buffers. Pass the buffer size info as constant to the shader if needed.
OpenGL ES 3.1 (for (Android, iOS, tvOS, Tizen platforms) only guarantees support for 4 compute buffers at a time. Actual implementations typically support more, but in general if developing for OpenGL ES, you should consider grouping related data in structs rather than having each data item in its own buffer.
通常、コンピュートシェーダーファイルは HLSL で記述され、自動的に、必要なすべてのプラットフォームにコンパイルまたは変換されます。ただし、他の言語への変換を避けたり (つまり、HLSL プラットフォームのみを維持する)、GLSL コンピュートコードを記述することも可能です。
以下の情報は、HLSL 専用、または、GLSL 専用のコンピュートシェーダーにのみ適用され、クロスプラットフォームビルドには適用されません。これは、この情報によってコンピュートシェーダーソースが一部のプラットフォームから除外される可能性があるためです。
CGPROGRAM
キーワードと ENDCG
キーワードで囲まれたコンピュートシェーダーソースは、非 HLSL プラットフォームでは処理されません。
GLSLPROGRAM
キーワードと ENDGLSL
キーワードで囲まれたコンピュートシェーダーソースは、GLSL ソースとして扱われ、そのまま出力されます。これは、OpenGL または GLSL プラットフォームをターゲットとする場合にのみ機能します。また、自動的に変換されたシェーダーはバッファーの HLSL データレイアウトに従いますが、記述された GLSL シェーダーは GLSL レイアウトルールに従うということにも注意する必要があります。
2017–05–18 限られた 編集レビュー で修正されたページ
5.6 に以下を追加: SystemInfo.supportsComputeShaders, platforms macOS, iOS (using Metal), Android, Linux, Windows (with Vulkan)