Open4
MiniShade: シェーダ命令セットの検討
とりあえずUTS2シェーダを実行できるレベルを目指して、シェーダに必要な命令セットを決めたい。
目的
GPUを作りたい。 ... まぁ完全に作るかはともかく、自前のシェーダプロセッサを用意してパフォーマンス解析やリプレイに役立てたい。
例えばシェーダをlookup tableとか整数処理に変換して処理するといった"手抜き"の研究をしたいと考えている。
作戦
シェーダコンパイラを作るのは一見大変そうだが、
- SPIR-Vは元々SSAに近い一時変数セマンティクスを持つ
- SPIR-V Tools https://github.com/KhronosGroup/SPIRV-Tools にインライン化等の最適化機能が一通り揃っている
- WebGL1では定数回数でないループは禁止されている(のでループは全てunrollでき、jumpは命令列のskipのみになる)
という性質があるためそこまで難しくない。はず。SPIR-Vをそのまま実行する形の実装はVulkanを使って作れているので、コンパイラを作る上で欠けているのはレジスタ割り付けの部分だけと言える。
ただシェーダ言語はSIMD的な意味のシャッフルが高機能だったりするので、命令のエンコードには気を使わないといけないかもしれない。
よって:
- 現状のWebGL1-on-Vulkan実装を改造して、SPIR-V命令列を分析できるようにする
- SPIR-V命令列をSPIR-V Toolsで処理し、インライン化によって関数定義やループ等を除去する
- 残った命令列をチェックし、インタプリタが実装するべき命令を列挙する
という流れで作業する。
SPIR-V Toolsの最適化パス
- 一覧: https://github.com/KhronosGroup/SPIRV-Tools/blob/a1d5d67aeb45e4a7681eb41a296561863b2d7519/include/spirv-tools/optimizer.hpp
- いわゆる
-O
オプションで追加される最適化: https://github.com/KhronosGroup/SPIRV-Tools/blob/57e1d8ebe3190c4ba23c1bee5147fe00c83ce358/source/opt/optimizer.cpp#L162-L206
... AggressiveDCE
とか何回実行されるんだよ。。と、同時に割とそれぞれの最適化の制約が厳しいことも気になる。
また strength-reduction
(2^nをビットシフトに変換する等)も -O
に入っていないので、役に立ちそうな最適化を見繕って手動で有効にすることも考えた方が良いかもしれない。もっとも、WebGL1ではシェーダは整数を処理できないのでこれに関しては重要でない可能性が高いが。。
最適化して逆アセンブルする
適当なピクセルシェーダで逆アセンブルを取得してみた。
ここから、サポートすべき命令の洗い出しを行っていくことになる。SPIR-V自体にはかなりの数の命令が定義されているが、まぁ実際にサポートすべき命令は30〜40種類程度なのではないだろうか。
列挙できた
拡張命令10種(SinとかCosとか)、演算命令11種。