OpenGL 3.1 以降や OpenGL ES 3.0 ではシェーダーが Uniform Buffer に
アクセスすることが出来ます。
OpenGL 4.2 以降はさらにシェーダーが利用できる Buffer Type が増えています。
OpenGL の API は基本的に下記の構造になっています。
●(1) Object を生成したり情報にアクセスするための Bind Point
・(A) (1) に Bind するための命令
・(B) (1) の Bind Point を使った設定や情報アクセス API
●(2) シェーダーに渡すための Bind Point の配列 (Table)
・(C) (2) に Bind するための専用命令
・(D) シェーダーのシンボルが (2) の Table のどこを見るか関連付ける命令
Texture Object は (A) と (C) の Bind 命令が共通なので、
glActiveTexture() で Bind Point ごと切り替えています。
切り替えるだけなので (1) と (2) のエリアが分かれていません。(詳細)
(A) = glBindTexture()
(C) = glActiveTexture() + glBindTexture()
(D) = glUseProgram() + glUniform1i() ( 4.2 以降 layout(binding=n) )
Vertex Buffer (GL_ARRAY_BUFFER) は glVertexAttribPointer() 命令が
内部で (C) を暗黙のうちに行います。
その後 OpenGL 4.3 で明示的に割り付ける命令が追加されました。
(C) の命令は (1) に影響を与えません。(詳細)
(A) = glBindBuffer( GL_ARRAY_BUFFER )
(C) = glBindVertexBuffer()
(D) = glVertexAttribBinding()
Uniform Buffer は 前回 のとおりです。
(1) と (2) は別の領域ですが、(C) の命令は (1)/(2) の両方に設定を行います。
(A) = glBindBuffer( GL_UNIFORM_BUFFER )
(C) = glBindBufferBase( GL_UNIFORM_BUFFER )
(D) = glUniformBlockBinding() ( 4.2 以降 layout(binding=n) )
OpenGL 4.2 以降は Bind Point を Shader 内に記述できるので、
いくつかのケースでは (D) を用いなくても良くなっています。
OpenGL 4.2 で追加された Atomic Counter Buffer も Shader 側で指定します。
● Atomic Counter Buffer (4.2)
Atomic Counter Buffer (GL_ATOMIC_COUNTER_BUFFER) は Uniform として宣言
しますが、シェーダーが値を更新することができます。
// Init struct CounterData { unsigned int Counter1; unsigned int Counter2; }; CounterData counter; memset( &counter, 0, sizeof(CounterData) ); GLuint CounterBlock= 0; glGenBuffers( 1, &CounterBlock ); glBindBuffer( GL_ATOMIC_COUNTER_BUFFER, CounterBlock ); glBufferData( GL_ATOMIC_COUNTER_BUFFER, sizeof(CounterData), &counter, GL_DYNAMIC_DRAW );
// Render // 初期化 CounterData counter; memset( &counter, 0, sizeof(CounterData) ); glBindBuffer( GL_ATOMIC_COUNTER_BUFFER, CounterBlock ); glBufferSubData( GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(CounterData), &counter ); glBindBuffer( GL_ATOMIC_COUNTER_BUFFER, 0 ); ~ glBindBufferBase( GL_ATOMIC_COUNTER_BUFFER, 3, CounterBlock ); // Bind glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0 );
API の構造は Uniform Block と同じです。
atomic_uint は特殊な型で、アクセスには専用の命令が必要となります。
// GLSL : vsh uniform mat4 PVW; uniform mat4 World; layout(binding=3, offset=0) uniform atomic_uint Counter1; in vec3 POSITION; in vec3 NORMAL; out vec3 onormal; void main() { vec4 opos= vec4( POSITION.xyz, 1.0 ) * PVW; opos.z= 2.0 * opos.z - opos.w; gl_Position= opos; atomicCounterIncrement( Counter1 ); onormal= NORMAL.xyz * mat3x3( World ); }
Vertex / Fragment それぞれ実行回数を数えているだけです。
// GLSL : fsh in vec3 onormal; layout(binding=3, offset=4) uniform atomic_uint Counter2; void main() { uint param= atomicCounterIncrement( Counter2 ) & 0xffff; float color= clamp( float( param ) * 0.001, 0.0, 1.0 ); float diff= clamp( dot( vec3( 0.0, 0.0, 1.0 ), normalize( onormal.xyz ) ), 0.0, 1.0 ); out_FragColor.xyz= vec3( color, 1.0, color ) * diff; out_FragColor.w= 1.0; }
RADEON (13.8beta) では Beta 版 Drive のせいか若干挙動に問題がありました。
vsh/fsh のカウンタが加算された値が返ってきます。
また API の Bind Point の構造が Uniform Block と異なっているようで
GL_ATOMIC_COUNTER_BUFFER_BINDING を glGetIntegeri_v() で取るとエラーでした。
GL_SHADER_STORAGE_BUFFER_BINDING の方も、
(1) の Bind が (2) の 0番と共有されているか、もしくは
glGetIntegerv( GL_SHADER_STORAGE_BUFFER_BINDING ) が (2) の
0 番の内容を返しているように見えます。
● Shader Storage Buffer (4.3)
OpenGL 4.3 の GLSL 4.3 では、Uniform Block 同様の構文で buffer 宣言が
追加されています。
当初 Direct3D の HLSL でいう cbuffer に対する tbuffer のことだと
思っていたのですが、直接データを書き換えることもできるようです。
つまり Direct3D の UnorderedAccessView (UAV) に相当する役目も持っています。
// GLSL layout(std140, binding=3) buffer MatBlock { layout(column_major) readonly mat4 MatData1; layout(column_major) readonly mat4 MatData2; };
こちらも簡単な動作を確認したのですが、GeForce では意図したとおりに
動くものの RADEON HD7750 の 13.8beta ではまだ少々不安定でした。
(使い方に問題があった可能性もあります)
● GL_ARB_program_interface_query
Uniform Block には Bind したり Program から情報を得るための専用の API がありました。
OpenGL 4.3 では Buffer Type も増えていることから、
専用の API を増やす代わりにより一般的な API が用意されています。
新しい Shader Storage Buffer だけでなく、Atomic Counter Buffer や
従来の Uniform Block, Uniform, Attribute などもこの API に統合されています。
Uniform Block も下記の通り。
glGetProgramiv( program, GL_ACTIVE_UNIFORM_BLOCKS ) ↓ glGetProgramInterfaceiv( program, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES ) glGetActiveUniformBlockiv( program, index, ~ ); ↓ glGetProgramResourceiv( program, GL_UNIFORM_BLOCK, index, ~ );
下記は実際にいろいろ情報を取り出してみた結果です。
少々わかりにくいですが、Atomic Counter Buffer や Shader Storage Buffer
だけでなく、同じ API で Attribute や出力変数も取り出すことが出来ます。
// RADEON Resource [Uniform] 92e1: 5 (Prog=0012) 0: Loc=0000 FLOAT_MAT4 (8b5c) Array=0 BL=-1 off=-1 ast=-1 mst=-1 RM=0 AC=-1 V_____ "World" 1: Loc=ffff FLOAT_MAT4 (8b5c) Array=0 BL= 0 off= 0 ast= 0 mst=16 RM=0 AC=-1 V_____ "Projection" 2: Loc=ffff FLOAT_MAT4 (8b5c) Array=0 BL= 0 off=64 ast= 0 mst=16 RM=0 AC=-1 V_____ "ViewMatrix" 3: Loc=ffff UNSIGNED_INT_ATOMIC_COUNTER(92db) Array=0 BL=-1 off=-1 ast=-1 mst=-1 RM=0 AC= 0 V_____ "Counter" 4: Loc=ffff UNSIGNED_INT_ATOMIC_COUNTER(92db) Array=0 BL=-1 off=-1 ast=-1 mst=-1 RM=0 AC= 1 ____F_ "Counter2" Resource [Atomic] 92c0: 2 (Prog=0012) 0: Bind=0000 Size= 4 Uni=1 Ind=2 V_____ "" 1: Bind=0001 Size= 4 Uni=1 Ind=3 ____F_ "" Resource [UniformBlock] 92e2: 1 (Prog=0012) 0: Bind=0000 Size= 128 Uni=2 Ind=1 V_____ "Scene" Resource [ShaderStorage] 92e6: 1 (Prog=0012) 0: Bind=0003 Size= 128 Uni=2 Ind=0 ____F_ "MatBlock" Resource [Input] 92e3: 3 (Prog=0012) 0: Loc=ffff FLOAT_VEC3 (8b51) Array=0 BL=899973093 off=53214 ast= 3 mst=128 RM=2 AC= 0 V_____ "NORMAL" 1: Loc=ffff FLOAT_VEC3 (8b51) Array=0 BL=899973093 off=53214 ast= 3 mst=128 RM=2 AC= 0 V_____ "POSITION" 2: Loc=ffff FLOAT_VEC2 (8b50) Array=0 BL=899973093 off=53214 ast= 3 mst=128 RM=2 AC= 0 V_____ "TEXCOORD" Resource [Output] 92e4: 1 (Prog=0012) 0: Loc=ffff FLOAT_VEC4 (8b52) Array=0 BL=899973093 off=53214 ast= 3 mst=128 RM=2 AC= 0 ____F_ "out_FragColor" Resource [Variable] 92e5: 2 (Prog=0012) 0: Loc=ffff FLOAT_MAT4 (8b5c) Array=0 BL= 0 off= 0 ast= 0 mst=16 RM=0 AC= 1 ____F_ "Projection2" 1: Loc=ffff FLOAT_MAT4 (8b5c) Array=0 BL= 0 off=64 ast= 0 mst=16 RM=0 AC= 1 ____F_ "ViewMatrix2"
// GeForce Resource [Uniform] 92e1: 5 (Prog=0012) 0: Loc=ffff UNSIGNED_INT_ATOMIC_COUNTER(92db) Array=0 BL= 0 off= 0 ast= 0 mst= 0 RM=0 AC= 0 V_____ "Counter" 1: Loc=ffff UNSIGNED_INT_ATOMIC_COUNTER(92db) Array=0 BL= 0 off= 4 ast= 0 mst= 0 RM=0 AC= 0 ____F_ "Counter2" 2: Loc=ffff FLOAT_MAT4 (8b5c) Array=0 BL= 0 off= 0 ast= 0 mst=16 RM=0 AC=-1 V_____ "Projection" 3: Loc=ffff FLOAT_MAT4 (8b5c) Array=0 BL= 0 off=64 ast= 0 mst=16 RM=0 AC=-1 V_____ "ViewMatrix" 4: Loc=0004 FLOAT_MAT4 (8b5c) Array=0 BL=-1 off=-1 ast=-1 mst=-1 RM=0 AC=-1 V_____ "World" Resource [Atomic] 92c0: 1 (Prog=0012) 0: Bind=0000 Size= 8 Uni=2 Ind=0 V___F_ "" Resource [UniformBlock] 92e2: 1 (Prog=0012) 0: Bind=0004 Size= 128 Uni=2 Ind=2 V_____ "Scene" Resource [ShaderStorage] 92e6: 1 (Prog=0012) 0: Bind=0003 Size= 128 Uni=1 Ind=0 V_____ "MatBlock" Resource [Input] 92e3: 2 (Prog=0012) 0: Loc=ffff FLOAT_VEC3 (8b51) Array=0 BL=-212702986 off=38875 ast= 3 mst=128 RM=1 AC= 0 V_____ "NORMAL" 1: Loc=ffff FLOAT_VEC3 (8b51) Array=0 BL=-212702986 off=38875 ast= 3 mst=128 RM=1 AC= 0 V_____ "POSITION" Resource [Output] 92e4: 1 (Prog=0012) 0: Loc=ffff FLOAT_VEC4 (8b52) Array=0 BL=-212702986 off=38875 ast= 3 mst=128 RM=1 AC= 0 ____F_ "out_FragColor" Resource [Variable] 92e5: 1 (Prog=0012) 0: Loc=ffff FLOAT_MAT4 (8b5c) Array=0 BL= 0 off=64 ast= 0 mst=16 RM=0 AC=-1 V_____ "ViewMatrix2"
関連エントリ
・OpenGL ES 3.0/OpenGL 4.x Uniform Block
・OpenGL の各バージョンと GLSL の互換性
・OpenGL のエラー判定と OpenGL 4.3 Debug Output
・OpenGL ES 3.0/OpenGL 4.4 Texture Object と Sampler Object
・OpenGL ES 3.0 と Vertex Array Object