OpenGL にも SPIR-V のシェーダーコードを使えるようにする GL_ARB_gl_spirv という拡張が存在します。ベンダー拡張ではなくいきなり ARB として定義されているので標準的に使える日もそう遠くないと思っています。
自分が使っているのが NVIDIA Geforce 650 Ti ですが、比較的最近のドライバ (375.57) でこの GL_ARB_gl_spirv が出現していました。この環境で簡単ではありますが、動作の確認やコードの書き方などやってみたいと思います。
準備
まずは SPIR-V のシェーダーバイナリを準備します。
SPIR-V とは何かについての詳しい説明は他に譲るとして、簡単に説明すると環境非依存のシェーダーコードの中間表現です。
ある程度のコンパイルを事前に行っておけるため実行時の負担が少なくなることが期待できます。
SPIR-V の GLSL からのコンパイラは Vulkan SDK に付属していますが、
GitHub の glslang プロジェクト からソースを取得してコンパイルしても作成することができます。
GLSL シェーダーのコンパイル
GLSLからのコンパイルについてですが、ちょっと癖があるようです。
そもそも SPIR-V では全ての GLSL の機能を実装していなかったりもしますし、 compatibility モードもダメなようですし。
varying 変数とか、ユニフォームブロックに属さない uniform 変数も失敗してしまった記憶があります。
あとはシェーダーファイルの拡張子が現時点では固定で、それによりどのシェーダーを示すのかの識別に使っているようです。
以下のような頂点シェーダーを vertexShader.vert ファイルとして記述しました。
#version 400 #extension GL_ARB_shading_language_420pack : enable layout( location=0 ) in vec4 inPosition; layout( location=1 ) in vec3 inNormal; layout( std140, binding = 0) uniform Scene { mat4 matProjView; mat4 matWorld; }; out vec4 color; void main() { gl_Position = matProjView * matWorld * inPosition; vec4 normalw = matWorld * vec4(inNormal, 1); float l = dot( normalize(normalw.xyz), vec3(1.0,1.0,0.0) ); l = 0.5 * (l + 1); color = vec4( l * 0.5 * (inNormal+1), 1 ); }
これを以下のコマンドによって SPIR-V 形式に変換します。
glslangValidator -G -l -o shaderVS.spv vertexShader.vert
コード解説
SPIR-V の内容は OpenGL の Shader オブジェクトになります。
今まで GLSL ソースコードとしての文字列を渡していましたがその代わりにバイナリデータをセットするような感じです。
glShaderSource の代わりに glShaderBinary を使います。
shaderVS = glCreateShader( GL_VERTEX_SHADER ); glShaderBinary( 1, &shaderVS, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, pBinarySPIRV, binarySPIRVSize ); glSpecializeShaderARB( shaderVS, "main", 0, nullptr, nullptr ); glCompileShader( shaderVS );
読み込ませた後 glCompileShader して、正常に作成されたかを確認します。
その後は、いつも通り ShaderProgram に glAttachShader して使うことになります。
注意点としては、glShaderBinary で読み込ませた後で glSpecializeShaderARB を呼び出すことでしょうか。
この関数でシェーダーのエントリポイントがどこにあるかを設定しています。
残りの引数については GLSL 4.50 での specialization constant 関連のものらしくこれについては現在スルーしています。
頂点シェーダーだけ示しましたが、フラグメントシェーダーも同じ手順です。
まとめ
今回は GL_ARB_gl_spirv について確認してみました。
事前コンパイルしてシェーダーバイナリを実行時に読み込ませる方式を取れるようになったことは DirectX の方式に近づいたともいえます。
今までの OpenGL のシェーダーバイナリの仕組みがプラットフォーム依存で使いどころがほとんどなかったので、この SPIR-V バイナリを使えるようになったのは嬉しい限りです。
OpenGL 4.5 を完全サポートする環境ではこの拡張も標準なのかもしれません。OpenGL の赤本の最新版では OpenGL 4.5 となっていますし、この中に SPIR-V の話も入っているようです。
[amazonjs asin=”0134495497″ locale=”JP” title=”OpenGL Programming Guide: The Official Guide to Learning OpenGL, Version 4.5 with SPIR-V (9th Edition)”]
これの日本語版って出たらいいなとは思いますが、どうなんでしょうか。