Standard Portable Intermediate Representation ( SPIR ) は、Khronos Groupによる並列コンピューティングおよびグラフィックス用の中間言語です。シェーダーやカーネルを表現するために、 Vulkanグラフィックス APIやOpenCLコンピュート API など、複数の実行環境で使用されています。また、クロスコンパイル用の交換言語としても使用されています。[ 1 ] [ 2 ]
SPIR-Vは、2015年にKhronos Groupによって発表されたSPIRの新しいバージョンであり、2012年に発表されたオリジナルのSPIRに取って代わった。
2024年9月19日、マイクロソフトはDirect3D InterchangeフォーマットとしてDXILに代わるものとしてSPIR-Vを採用し、Shader Model 7以降からサポートを開始する計画を発表しました。[ 3 ]
SPIR-Vの目的は、計算処理とグラフィックス処理に必要なプリミティブをネイティブに表現すること、高水準言語と計算処理およびグラフィックスドライバへのインターフェースを分離すること、配布形式として完全にコンパイルされたバイナリを配布すること、完全に自己完結型の仕様であること、そして複数のAPIをサポートすることです。また、クロスコンパイルツールの中間ターゲットとしても使用されます。
例えば、SPIR-V では、Vulkan API でGLSLやHLSLを含む任意のシェーディング言語を使用できます。[ 4 ] [ 5 ] SPIR-V は SPIRV-Cross を使用して複数のシェーディング言語 ( GLSL、GLSL ES、MSL、HLSL ) に逆コンパイルできるため、これらの言語を相互に変換できます。[ 6 ]また、 WebGPU、OpenCL、SYCL、C++、Rustへのパスや、これらの言語からのパスも備えています。
ターゲットプラットフォームでは、SPIR-V を取り込むことで、デバイスドライバに高水準言語ソースコンパイラを組み込む必要がなくなり、ドライバの複雑さが軽減されます。[ 2 ]
SPIRは2011年に初導入され、SPIR-Vは2015年に導入された。
SPIR は 2015 年の SPIR-V リリース以前はLLVM 中間表現に基づいていました。SPIR 1.0 の暫定仕様は 2012 年に発表されました。[ 7 ] 2013 年 7 月 22 日、暫定仕様 SPIR 1.2 がSIGGRAPH 2013で発表されました。[ 8 ]最終的な SPIR 1.2 仕様は、2014 年 1 月 21 日に HiPEAC 2014 でリリースされました。[ 9 ] 2014 年 8 月 11 日、暫定仕様 SPIR 2.0 がSIGGRAPH 2014でリリースされました。[ 10 ] SPIR-V は LLVM を使用しません。[ 2 ]
SPIR-V 1.0 は、2015 年 3 月に発表され[ 11 ]、2015 年 11 月 16 日にリリースされたSPIR の新しいバージョンです[ 12 ]。SPIRファミリーには、シェーダーとカーネル機能のネイティブサポートを備えた、Khronos によって完全に定義された真のクロス API 標準が含まれるようになりました。
Khronos Groupによる別のプログラムでは、LLVM IRとの相互変換が可能になっています。[ 13 ]
SPIR-Vの取り込みをサポートする機能は、OpenCL 2.1のコア仕様、Vulkan API、およびOpenGLバージョン4.6に組み込まれています。
SPIR-Vは、バイナリ形式で交換される高レベルの中間言語です。関数は、静的単一代入(SSA)形式を使用した基本ブロックの制御フローグラフで表現されます。データ構造は、高レベルの階層表現を保持します。これは、グラフィカルシェーダーに使用される以前のバイトコードや仮想マシンのような中間表現のように損失がありません。これにより、ターゲットデバイス上でより最適なパフォーマンスを実現できます。[ 17 ]
SPIR-V は、セマンティクスを追加する拡張機能を記述したり、トークン値の範囲をパーティの使用のために予約したりすることで拡張できます。ベンダーは、SPIR-V に独自のセマンティクスを追加できます。[ 18 ]拡張命令セットの追加セットは、別の仕様で提供できます。拡張命令は、セットの ID とセット内の命令の ID を指定することで使用されるため、複数のセットを問題なくインポートできます。[ 18 ]
デバッガーには、RenderDoc、SwiftShader、Amberなどがあります。[ 19 ]
グラフィカルシェーダーは、SPIR-V の構造化制御フローを使用して、制御フローがどのようにネストされるかを示します。これは、並列実行環境における制御フローの分岐と再収束を定義するのに役立ちます。[ 20 ]特殊化により、配布する必要のあるシェーダーのバリアントの数が減少します。[ 21 ]
SPIR-V仕様では、有効なSPIR-Vモジュールを持つために従わなければならないルールが規定されています。これにより、オフライン検証が可能になります。ドライバは、無効なSPIR-Vモジュールを処理する義務はありません。テストでは、適合性テストによって、ドライバが有効なSPIR-Vを使用する際に正しく動作することが検証され、検証ツールによって、フロントエンドがSPIR-Vを適切に生成することが検証されます。[ 22 ]
SPIR-V は、異なるコンパイル ユニット内の関数呼び出しを表現できます。標準バージョンの SPIR-V は、OpenCL の計算カーネルにこの機能を使用しますが、グラフィック API が単一の SPIR-V モジュールに完全にリンクすることを要求するシェーダー ステージには使用しません。[ 23 ]ツールが部分的にリンクされたシェーダーやカーネルを一時的に使用できるようにする拡張機能があります。[ 24 ]
SPIR-Vモジュールは、クライアントAPIによって使用され、そのモジュールの機能をサポートします。これらの機能は、能力によって分類され、モジュールの早い段階で宣言されます。バリデーターは、モジュールが宣言された能力のみを使用していることを確認できます。また、クライアントAPIは、サポートされていない能力を宣言するモジュールを拒否できます。[ 25 ]
SPIR-V は、ソースレベル言語の複数のバージョンを扱う際に役立ってきました。たとえば、OpenGL シェーディング言語 (GLSL) の複数のバージョンでは、WebGL 1.0や Apple の OpenGL 実装など、特定の古いバージョンの GLSL に固定された実装のため、シェーダーの複数のバージョンを配布する必要があります。SPIR-V の注目すべき使用例の 1 つは、GLSL バージョン間の交換フォーマットとして使用できることです。Khronos Groupが保守しているツールを使用して、 GLSL を SPIR-V にコンパイルしたり[ 26 ]glslangValidator、SPIR-V を最適化したり[ 22 ]、SPIR-V を異なる GLSL ターゲットにクロスコンパイルしたりできます[ 27 ]。spirv-optspirv-cross
しかし、フォーマットとして、SPIR-V にはクロスコンパイルに関するいくつかの制限があり、その一つに、すべての SPIR-V モジュールが少なくとも 1 つのエントリ ポイント シンボルを持つ必要があるという要件があります。このため、複雑なシェーダーを部分コンパイルのステップの連続とそれに続くリンク ステップで組み立てる分離コンパイルにこのフォーマットを簡単に使用することはできません。これは、SPIR- V バイナリ コードに完全なリンク機能を提供することを目的とした [spirv-link 22 ]などの一部の SPIR-V ツールの目標とは相反します。