GPUを使用してフィルタリングを実装する場合、ピクセルシェーダもしくはコンピュートシェーダを使用することができます。

ピクセルシェーダは最も基本的なシェーダであり、テクスチャとパラメータを入力して演算した後、1画素を出力することができます。例えば、ピクセルシェーダで5x5タップのフィルタを実装する場合、25画素を取得して、1画素を返すことになります。テクスチャはランダムリードはできますが、ランダムライトはできません。また、出力は1画素に限定されます。

コンピュートシェーダでは、ピクセルシェーダの機能に加えて、テクスチャへのランダムライトと、共有メモリが使用可能です。また、出力は1画素に限定されません。コンピュートシェーダで5x5タップのフィルタを実装する場合、複数画素の処理をまとめて行うことで、テクスチャのフェッチ回数を削減し、ピクセルシェーダよりも高速化が可能です。例えば、16x16画素をまとめて共有メモリに格納した後、スレッドIDに応じて、5x5タップのフィルタを並列で実行し、12x12画素を書き込むことができます。これにより、ピクセルシェーダでは25in:1outだったテクスチャフェッチ比率を、256in:144out=1.7in:1outまで落とすことができます。

compute

コンピュートシェーダの処理の単位はスレッドで、複数のスレッドが集まってスレッドグループを構成します。共有メモリはスレッドグループ内でのみアクセス可能です。シェーダコードには、3次元で何個のスレッドでグループを構成するかを記述します。共有メモリのアクセス管理はメモリバリアで、GroupMemoryBarrierWithGroupSync();を読んだタイミングで全てのスレッドが完了するまで待ちます。テクスチャのアクセス座標は、スレッドに割り当てられたIDから計算します。

コンピュートシェーダは、ピクセルシェーダよりも初期設定が面倒ですが、Unityを使うと簡単に実験することができます。テクスチャへのランダムアクセスもRenderTextureにrandomAccessフラグを付けるだけでよく、簡単です。ただし、Unityでコンパイル済みのシェーダを使用する方法が存在しないため、シェーダプログラムを秘匿したい場合は、Render PluginとしてDLLを呼び出して、中でfxcを読み込むしかなさそうです。

Render Pluginなど、Unityを使用せず、直接、Direct Computeを使用する場合、ランダムライトが発生するテクスチャには、ShaderResourceViewではなく、UnalignedResourceViewが必要です。UnalignedResourceViewはピクセルシェーダでは読めないので、1つのテクスチャに対して両方のビューを作っておくことで、コンピュートシェーダで書き込み、ピクセルシェーダで読み込むことが可能です。UnityのNativeTexturePtrからもUnalignedResourceViewは作成可能です。