Version: 2022.1
言語: 日本語
ランタイムのシェーダーの置き換え
エラーシェーダーとローディングシェーダー

コンピュートシェーダー

Compute shaders are shader programs that run on the GPU, 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, 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 をサポートしません。

  • Modern consoles

コンピュートシェーダーのサポートの有無はランタイムに SystemInfo.supportsComputeShaders を使って確認できます。

コンピュートシェーダーアセット

Similar to shader assets, compute shader assets are files in your project. with a .compute file extension. They are written in DirectX 11 style HLSL language, with a minimal number of #pragma compilation directives to indicate which functions to compile as compute shader kernels.

こちらは、コンピュートシェーダーファイルの基本例です。出力テクスチャを赤で塗りつぶします。

// 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);
}

The language is standard DX11 HLSL, with an additional #pragma kernel FillWithRed directive. One compute shader Asset file must contain at least onecompute kernel that can be invoked, and that function is indicated by the #pragma directive. There can be more kernels in the file; just add multiple #pragma kernel lines.

複数の#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 は、リニアフィルターモードとクランプラップモードを持つサンプラーを作成します。

詳細は、サンプラー状態 を参照してください。

クロスプラットフォームのサポート

As with regular shaders, Unity is capable of translating compute shaders from HLSL to other shader languages. Therefore, for the easiest cross-platform builds, you should write compute shaders in HLSL. However, there are some factors that need to be considered when doing this.

クロスプラットフォームでの最良の実践法

DirectX 11 (DX11) は、他のプラットフォーム (MetalOpenGL ES など) ではサポートされていない多くの操作をサポートしています。 したがって、DX11 だけの環境を考えるより、サポートが少ないプラットフォームで、シェーダーの挙動を明確に定義する必要があります。 考慮すべき点は以下のとおりです。

  • アウトオブバンドのメモリアクセスが悪い点。DX11 は、読み込み時に常にゼロを返し、問題なくデータの一部を読み込むかもしれませんが、サポートが少ないプラットフォームでは、これを行う際に GPU がクラッシュする可能性があります。DX11 特有のハック、スレッドグループサイズの倍数と一致しないバッファーサイズ、バッファーの先頭や末尾から隣接するデータ要素を読み取ろうとすること、などの同様の非互換性に注意してください。

  • リソースを初期化する点。 新しいバッファーとテクスチャの内容は未定義です。 プラットフォームの中にはすべてゼロを示すものもありますが、そうでないものでは、NaN を含めどんな値になることもありえます。

  • コンピュートシェーダーが宣言するすべてのリソースをバインドします。シェーダーが分岐のために現在の状態でリソースを使用しないことが確実にわかっていても、リソースがバインドされていることを確認する必要があります。

プラットフォーム特有の相違

  • Metal (iOS と tvOS プラットフォーム用) は、テクスチャのアトミック操作をサポートしません。Metal は、バッファーの GetDimensions クエリもサポートしません。必要な場合は、バッファーサイズの情報を定数としてシェーダーに渡します。
  • OpenGL ES 3.1 (Android, iOS, tvOS プラットフォーム用) は、一度に 4 つのコンピュートバッファーしかサポートしません。実際の実装では、より多くをサポートすることもありますが、一般的には OpenGL ES 用に開発する場合は、それぞれのバッファーに各データを格納するよりも、関連するデータを構造体でグループ化することを検討する必要があります。
  • OpenGL (ES) and Vulkan require an image format qualifier for RWTextures<T> that are not write-only.
    Unity derives this qualifier from the type T in the angle-brackets. The format qualifier needs to match the GraphicsFormat/RenderTextureFormat of the RenderTexture that is bound to the RWTexture. The following table maps Unity RenderTexture GraphicsFormats and RenderTextureFormats to their corresponding HLSL type and image format qualifier:
GraphicsFormat RenderTextureFormat HLSL type GLSL image format qualifier
R32G32B32A32_SFloat ARGBFloat float4 rgba32f
R16G16B16A16_SFloat ARGBHalf min16float4/half4 rgba16f
R32G32_SFloat RGFloat float2 rg32f
R16G16_SFloat RGHalf min16float2/half2 rg16f
B10G11R11_UFloatPack32 RGB111110Float min10float3 r11f_g11g_b10f
R32_SFloat RFloat float r32f
R16_SFloat RHalf min16float/half r16f
R16G16B16A16_UNorm ARGB64 unorm min16float4/half4 rgba16
A2B10G10R10_UNormPack32 ARGB2101010 unorm min10float4 rgb10_a2
R8G8B8A8_UNorm ARGB32 unorm float4 rgba8
R16G16_UNorm RG32 unorm min16float2/half2 rg16
R8G8_UNorm RG16 unorm float2 rg8
R16_UNorm R16 unorm min16float/half r16
R8_UNorm R8 unorm float r8
R16G16B16A16_SNorm unsupported snorm min16float4/half4 rgba16_snorm
R8G8B8A8_SNorm unsupported snorm float4 rgba8_snorm
R16G16_SNorm unsupported snorm min16float2/half2 rg16_snorm
R8G8_SNorm unsupported snorm float2 rg8_snorm
R16_SNorm unsupported snorm min16float/half r16_snorm
R8_SNorm unsupported snorm float r8_snorm
R32G32B32A32_SInt ARGBInt int4 rgba32i
R16G16B16A16_SInt unsupported min16int4 rgba16i
R8G8B8A8_SInt unsupported min12int4 rgba8i
R32G32_SInt RGInt int2 rg32i
R16G16_SInt unsupported min16int2 rg16i
R8G8_SInt unsupported min12int2 rg8i
R32_SInt RInt int r32i
R16_SInt unsupported min16int r16i
R8_SInt unsupported min12int r8i
R32G32B32A32_UInt unsupported uint4 rgba32i
R16G16B16A16_UInt RGBAUShort min16uint4 rgba16ui
R8G8B8A8_UInt unsupported unsupported rgba8ui
R32G32_UInt unsupported uint2 rg32ui
R16G16_UInt unsupported min16uint2 rg16ui
R8G8_UInt unsupported unsupported rg8ui
R32_UInt unsupported uint r32ui
R16_UInt unsupported min16uint r16ui
R8_UInt unsupported unsupported r8ui
A2B10G10R10_UIntPack32 unsupported unsupported rgb10_a2ui

HLSL 専用、または、GLSL 専用のコンピュートシェーダー

通常、コンピュートシェーダーファイルは HLSL で記述され、自動的に、必要なすべてのプラットフォームにコンパイルまたは変換されます。ただし、他の言語への変換を避けたり (つまり、HLSL プラットフォームのみを維持する)、GLSL コンピュートコードを記述することも可能です。

以下の情報は、HLSL 専用、または、GLSL 専用のコンピュートシェーダーにのみ適用され、クロスプラットフォームビルドには適用されません。これは、この情報によってコンピュートシェーダーソースが一部のプラットフォームから除外される可能性があるためです。

  • CGPROGRAM キーワードと ENDCG キーワードで囲まれたコンピュートシェーダーソースは、非 HLSL プラットフォームでは処理されません。

  • GLSLPROGRAM キーワードと ENDGLSL キーワードで囲まれたコンピュートシェーダーソースは、GLSL ソースとして扱われ、そのまま出力されます。これは、OpenGL または GLSL プラットフォームをターゲットとする場合にのみ機能します。また、自動的に変換されたシェーダーはバッファーの HLSL データレイアウトに従いますが、記述された GLSL シェーダーは GLSL レイアウトルールに従うということにも注意する必要があります。

バリアントとキーワード

グラフィックスシェーダーと同じように、キーワードを使ってコンピュートシェーダの複数のバリアントを作ることができます。

For general information on variants, see Shader variants. For information on how to implement these features in compute shaders, see Declaring and using shader keywords in HLSL and the ComputeShader API documentation.

ランタイムのシェーダーの置き換え
エラーシェーダーとローディングシェーダー