OpenGL のシェーディング言語 GLSL は、OpenGL の API と同様に
活発な更新が行われています。
Direct3D の HLSL よりも種類が多く、バージョン間には機能差があります。
GPU に関する機能だけでなく、言語の構文なども拡張が続けられているようです。
いくつかの機能に関して GLSL バージョン間の違いをまとめてみました。
下記の表は部分的にピックアップしています。
// GL2 Group OpenGL GLSL version 行 suffix ITC -------------------------------------------------------- OpenGL ES 2.0 GLSL ES 1.0 #version 100 - - OpenGL 2.0 GLSL 1.1 - - OpenGL 2.1 GLSL 1.2 #version 120 f ◎
// GL3/4 Group OpenGL GLSL version 行 suffix ITC UBlock ---------------------------------------------------------------- OpenGL 3.0 GLSL 1.3 #version 130 u,f ◎ - OpenGL 3.1 GLSL 1.4 #version 140 u,f ◎ U OpenGL 3.2 GLSL 1.5 #version 150 u,f ◎ U,I,O OpenGL ES 3.0 GLSL ES 3.0 #version 300 es u,f - U OpenGL 3.3 GLSL 3.3 #version 330 u,f ◎ U,I,O OpenGL 4.0 GLSL 4.0 #version 400 u,f,lf ◎ U,I,O OpenGL 4.1 GLSL 4.1 #version 410 u,f,lf ◎ U,I,O OpenGL 4.2 GLSL 4.2 #version 420 u,f,lf ◎ U,I,O OpenGL 4.3 GLSL 4.3 #version 430 u,f,lf ◎ U,I,O,B OpenGL 4.4 GLSL 4.4 #version 440 u,f,lf ◎ U,I,O,B
GLSL は上位互換性を保っており、コンパイラは
1行目の「#version」行でバージョンを判定しています。
まず OpenGL 2.x 系と OpenGL 3.0 以降で大きな違いがあります。
attribute/varying と in/out のキーワードが変更され、
texture2D() 等の関数名も変わりました。
uint/uvec (unsigned int) や switch 文が使えるようになったのも
OpenGL 3.0 (GLSL 1.3) からです。
double 型の対応は OpenGL 4.0 (GLSL 4.0) 以降。
Uniform Block (Constant Buffer) は OpenGL 3.1 (GLSL 1.4) で追加されましたが、
in/out の Interface Block は 3.2 (GLSL 1.5) で対応しました。
GLSL は C言語や他のシェーダー言語と違い、初期化にはコンストラクタが必要でした。
// GLSL vec3 pos= vec3( 1.0, 2.0, 3.0 ); float a[4]= float[]( 1.0, 2.0, 3.0, 4.0 );
OpenGL 4.2 (GLSL 4.2) 以降は C言語ライクな初期化リスト {~} が使えるように
なっており下記の書式が通ります。
// GLSL vec3 pos= { 1.0, 2.0, 3.0 }; float a[4]= { 1.0, 2.0, 3.0. 4.0 };
予想に反して OpenGL 4.0 の Intel HD 4000 (9.18.10.3165) でもコンパイルが通りました。
OpenGL ES 3.0 はいくつか仕様が削られているようです。
特に暗黙の型変換ができません。↓がエラー。
float a= 1; // int to float
OpenGL ES 2.0 でも自動変換出来なかったので、この場合は 1.0 と記述する
必要がありました。
(OpenGL ES 2.0 だと suffix も使えないので 1.0f と書いてもエラー)
OpenGL ES 3.0 は符号なし整数型でも同様の問題が起こります。
uint i= 32; // int to uint
下記のように ‘u’ が必要です。
uint i= 32u;
暗黙の型変換があるとオーバーロード関数の検索も一気に複雑になるので、
組み込み用途では不要だと判断したのかもしれません。
ただしコンパイラがきちんとエラーを返してくれるので、
これらの問題はすぐに判明します。
●互換性
HD 4000 で Initializer List が使えたので他の GPU でも実験してみました。
GPU OpenGL GLSL version compile ---------------------------------------------------- Intel HD 4000 OpenGL 4.0 #version 400 OK RADEON HD 6750M OpenGL 4.3 #version 430 OK RADEON HD 6750M OpenGL 4.3 #version 400 OK GeForce GTX 650 OpenGL 4.4 #version 440 OK GeForce GTX 650 OpenGL 4.4 #version 400 Error
GLSL の version を下げると GeForce ではエラーになりますが
RADEON では通りました。
GLSL の仕様上はエラーの方が正解です。
A では動くが他社の B では動かないといった違いは、意外にこの辺りが
原因なのかもしれません。