日別アーカイブ: 2013年8月13日

OpenGL の各バージョンと GLSL の互換性

OpenGL のシェーディング言語 GLSL は、OpenGL の API と同様に
活発な更新が行われています。
Direct3D の HLSL よりも種類が多く、バージョン間には機能差があります。

GPU に関する機能だけでなく、言語の構文なども拡張が続けられているようです。
いくつかの機能に関して GLSL バージョン間の違いをまとめてみました。

GLSL Version

下記の表は部分的にピックアップしています。

// 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 では動かないといった違いは、意外にこの辺りが
原因なのかもしれません。