OpenGL Shading Language 4.60 Specification 読書ノート Part 9¶
9. Shading Language Grammar¶
読者ノート
トークン、文法については仕様書該当部分をその都度参照することにする。
文法は字句解析の出力から供給される。字句解析から返されるトークンはこの章の最初のテキストブロックにすべて掲載されている。
読者ノート
トークンが大量に列挙されている。キーワードを大文字で書いたものがほとんどのようだ。
LEFT_OP
, RIGHT_OP
, INC_OP
, DEC_OP
, LE_OP
, など、これまで見たことがないトークンがある。あとで定義される?
上記のトークンに関して OpenGL Shading Language の文法を記述したものが二番目のテキストブロックにある。開始規則は translation_unit だ。空のシェーダー(前処理の後、解析するトークンがないもの)は有効であり、その結果、下記の文法には空のトークンストリームを受け入れる規則がないにも関わらず、コンパイルエラーは発生しない。
読者ノート
これまでのしばしば目にしたような BNF で文法のすべてが定義されている。雰囲気を伝えるために一例を挙げておく:
SEMICOLON など、全部大文字の単語はトークンだと解釈できるように記されているようだ。
一般的に、上記の文法は OpenGL Shading Language の超集合を記述している。文法的には純粋に有効な構成要素も、当仕様書の他の箇所では禁止されている。
10. Acknowledgments¶
本仕様書は、過去のバージョンの Open GL および Open GL ES 言語仕様書に寄稿した人々と、本バージョンに寄稿した以下の人々の仕事に基づいている:
11. Normative References¶
読者ノート
標準 C++ (1998),
Open GL ES 3.2 (2016),
Open GL 4.6 コアプロファイル (2016),
IEEE 754 (2008),
SPIR-V 1.3,
Vulkan 1.1 (2019)
の仕様を挙げている。
12. Non-Normative SPIR-V Mappings¶
この付録の内容:
Vulkan と OpenGLの両方について、SPIR-V を使用した場合と使用しない場合の機能を比較。
GLSL と SPIR-V の両機能が論理的にどのように対応しているか。
12.1. Feature Comparisons¶
OpenGL、Vulkan ともに、以下の機能を削除した:
サブルーチン
共有およびまとめられたブロックレイアウト
すでに非推奨となっているテクスチャー関数 (e.g.
texture2D()
)すでに非推奨となっているノイズ関数 (e.g.
noise1()
)互換性プロファイルの機能
gl_DepthRangeParameters
とgl_NumSamples
Vulkan では以下の機能を削除したが、OpenGL ではまだ残している:
既定の一様変数、不透明型に対して:
UniformConstant
格納クラスは、大域スコープの個々の変数に使用することができる。つまり、一様変数は、GLSL 4.5 以上でブロックになっている組み込みメンバーでない限り、ブロックの中にある必要はない。GLSL 不可分計数器束縛は
offset
レイアウト修飾子を持つ。 → SPIR-V のOffset
装飾を使っているAtomicCounter
格納クラス。GLSL の
origin_lower_left
→ SPIR-V のOriginLowerLeft
頂点シェーダーでの入力倍数の位置に関する特別な規則
gl_VertexID
とgl_InstanceID
OpenGL、Vulkan ともに、以下の機能が追加:
特殊化定数
宣言順とは異なる順序でメンバーを編成できる
offset
一様・バッファーブロックの
offset
およびalign
レイアウト修飾子を、対処していなかったバージョンに対応
Vulkan のみ以下の機能が追加:
押し込み一定バッファー
別々のテクスチャーと採取器のシェーダー混合 (SPIR-V
OpTypeSampler
)記述子集合(存在するならば
DescriptorSet
0でなければならない)gl_VertexIndex
とgl_InstanceIndex
サブパス入力対象と入力付属 (
input_attachment_index
)
OpenGL、Vulkanともに、以下の機能が変更:
gl_FragColor
が暗黙のブロードキャストを示さなくなる。
Vulkan のみ以下の機能が変更:
精度修飾子
mediump
,lowp
はデスクトップ版では削除されず、すべてのバージョンで尊重される(デスクトップ版の既定精度はすべての型でhighp
だ)。一様変数の配列とバッファーブロックの配列は、要素ごとではなく、オブジェクト全体に対して一つの束縛番号しか受け取らなくなった。
既定原点は
origin_lower_left
ではなくorigin_upper_left
となった。
Vulkan は SPIR-V 環境仕様で UBO や SSBO などの資源の多次元配列を許さない。 SPIR-V はそれを対処しており、OpenGL はすでに GLSL シェーダーでこれを許可している。SPIR-V for OpenGL でも許可されている。
12.2. Mapping from GLSL to SPIR-V¶
読者ノート
以下、私には読む必要が全くないトピックのはずだ。
12.2.1. Specialization Constants¶
SPIR-V 特殊化定数は、クライアント API で後から設定することができ、
layout(constant_id=...)
を用いて宣言することができる。例えば、既定値が 12 の特殊化定数を作るには次のようにする:
layout(constant_id = 17) const int arraySize = 12;
上記 17 は API や他のツールが後にこの特定の特殊化定数を参照するための ID だ。 API や中間ツールは、実行コードに完全に下げられる前に、その値を別の定数の整数に変更することができる。最終的に下げられる前に変更されない場合は 12 の値を維持する。
読者ノート
原文の意味がつかめなかった。動詞 lower の意味がわからない。
特殊化定数は、畳み込みがないということ以外は const
のセマンティクスを持つ。したがって、配列は arraySize
で宣言することができる:
vec4 data[arraySize]; // legal, even though arraySize might change
特殊化定数は式の中に入れることができる:
vec4 data2[arraySize + 2];
これにより、シェーダーを実行コードに落とし込む際に、data2
のサイズが
arraySize
の持つ定数値よりも 2 だけ大きくなる。
特殊化定数で形成された式もまた、シェーダー内では特殊化定数のように振る舞う。定数のようにではない。
arraySize + 2 // a specialization constant (with no constant_id)
このような式は定数と同じ場所で使用できる。
constant_id
はスカラー整数、スカラー浮動小数点、スカラー真偽値のどれかにしか適用できない。
基本的な演算子とコンストラクターしか特殊化定数に適用できず、結果として特殊化定数が得られる:
layout(constant_id = 17) const int arraySize = 12;
sin(float(arraySize)); // result is not a specialization constant
SPIR-V 特殊化定数はスカラーしか対象としていないが、ベクトルはスカラーの演算で作ることができる:
layout(constant_id = 18) const int scX = 1;
layout(constant_id = 19) const int scZ = 1;
const vec3 scVec = vec3(scX, 1, scZ); // partially specialized vector
組み込み変数には constant_id
を付けることができる:
layout(constant_id = 18) gl_MaxImageUnits;
これにより特殊化定数のようになる。これは完全な再宣言ではなく、他のすべての特性は元の組み込み宣言からそのまま残されている。
組み込みベクトル gl_WorkGroupSize
は、in
修飾子に適用される特別レイアウト local_size_{xyz}_id
を用いて特化できる。例えば:
layout(local_size_x_id = 18, local_size_z_id = 19) in;
これにより gl_WorkGroupSize.y
は非特殊化定数として残り、
gl_WorkGroupSize
は部分的に特殊化されたベクトルとなる。その x
および
z
成分は、ID の 18 および 19 を使用して後で特殊化することができる。
12.2.2. Vulkan Only: Push Constants¶
プッシュ定数は、一様ブロック宣言に適用される新しい layout-qualifier-id
push_constant
を使って宣言された一様ブロック内に宿る。API は定数の集合を
push-constant
バッファーに書き込み、シェーダーは push_constant
ブロックから定数を読み込む:
layout(push_constant) uniform BlockName {
int member1;
float member2;
...
} InstanceName; // optional instance name
... = InstanceName.member2; // read a push constant
push_constant
一様ブロックに使用されるメモリーアカウンティングは他の一様ブロックとは異なる。それを収める必要がある隔離した小さなメモリープールがある。既定では push_constant
バッファーは std430
の梱包規則に従う。
12.2.3. Vulkan Only: Descriptor Sets¶
記述子集合内の各シェーダー資源には、記述子集合のレイアウト内での位置を定義する集合番号、束縛番号、配列要素の組が割り当てられる。GLSL では、集合番号および束縛番号は、それぞれ set
および binding
レイアウト修飾子を介して割り当てられ、配列要素は、配列の最初の要素のインデックスがゼロに等しい(非配列変数の場合は配列要素がゼロ)ことから、暗黙のうちに連続して割り当てられる:
// Assign set number = M, binding number = N, array element = 0
layout (set=M, binding=N) uniform sampler2D variableName;
// Assign set number = M, binding number = N for all array elements,
// and array element = i for the ith member of an array of size I.
layout (set=M, binding=N) uniform sampler2D variableNameArray[I];
For example, two combined texture/sampler objects can be declared in two different descriptor sets as follows
layout(set = 0, binding = 0) uniform sampler2D ts3;
layout(set = 1, binding = 0) uniform sampler2D ts4;
記述子集合の操作モデルの詳細については API 文書にある。
12.2.4. Vulkan Only: Samplers, Images, Textures, and Buffers¶
Storage Images¶
格納画像は GLSL シェーダーソースの中で、適切な次元の一様画像変数と、必要に応じてフォーマットレイアウト修飾子を用いて宣言される。
layout (set=m, binding=n, r32f) uniform image2D myStorageImage;
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %9 "myStorageImage"
OpDecorate %9 DescriptorSet m
OpDecorate %9 Binding n
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 2D 0 0 0 2 R32f
%8 = OpTypePointer UniformConstant %7
%9 = OpVariable %8 UniformConstant
...
Samplers¶
SPIR-V 採取器は GLSL シェーダーのソースでは一様 sampler
型と samplerShadow
型を使って宣言される:
layout (set=m, binding=n) uniform sampler mySampler;
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %8 "mySampler"
OpDecorate %8 DescriptorSet m
OpDecorate %8 Binding n
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeSampler
%7 = OpTypePointer UniformConstant %6
%8 = OpVariable %7 UniformConstant
...
Textures (Sampled Images)¶
テクスチャーは GLSL シェーダソースでは、適切な次元の一様テクスチャー変数を使って宣言される:
layout (set=m, binding=n) uniform texture2D mySampledImage;
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %9 "mySampledImage"
OpDecorate %9 DescriptorSet m
OpDecorate %9 Binding n
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 2D 0 0 0 1 Unknown
%8 = OpTypePointer UniformConstant %7
%9 = OpVariable %8 UniformConstant
...
Combined Texture and Samplers¶
混合テクスチャーと採取器は GLSL シェーダソースの中では適切な次元の一様テクスチャー混合採取器変数を使って宣言される:
layout (set=m, binding=n) uniform sampler2D myCombinedImageSampler;
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %10 "myCombinedImageSampler"
OpDecorate %10 DescriptorSet m
OpDecorate %10 Binding n
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%9 = OpTypePointer UniformConstant %8
%10 = OpVariable %9 UniformConstant
...
なお、混合画像採取器記述子は、上述の節と同様に、シェーダー内では単なる画像または採取器として参照することができる。
Combining Separate Samplers and Textures¶
キーワード sampler
で宣言された採取器は、フィルタリング情報のみを含み、テクスチャーや画像を含まない:
uniform sampler s; // a handle to filtering information
texture2D
のようなキーワードで宣言されたテクスチャーは、画像情報のみを含み、フィルタリング情報を含まない:
uniform texture2D t; // a handle to a texture (an image in SPIR-V)
コンストラクターを使用して、テクスチャー検索呼び出しを行う際に、採取器とテクスチャーを合成することができる:
texture(sampler2D(t, s), ...);
この機能をわかりやすく示すために、上記で layout()
の情報を省略したことに注意。
Texture Buffers (Uniform Texel Buffers)¶
テクスチャーバッファーは、GLSL シェーダソースでは一様 textureBuffer
変数を使って宣言される:
layout (set=m, binding=n) uniform textureBuffer myUniformTexelBuffer;
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %9 "myUniformTexelBuffer"
OpDecorate %9 DescriptorSet m
OpDecorate %9 Binding n
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 Buffer 0 0 0 1 Unknown
%8 = OpTypePointer UniformConstant %7
%9 = OpVariable %8 UniformConstant
...
Image Buffers (Storage Texel Buffers)¶
画像バッファーは、GLSL シェーダーソース中では一様 imageBuffer
変数を使って宣言される:
layout (set=m, binding=n, r32f) uniform imageBuffer myStorageTexelBuffer;
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %9 "myStorageTexelBuffer"
OpDecorate %9 DescriptorSet m
OpDecorate %9 Binding n
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 Buffer 0 0 0 2 R32f
%8 = OpTypePointer UniformConstant %7
%9 = OpVariable %8 UniformConstant
...
Storage Buffers¶
GLSL シェーダーのソースでは、バッファー格納修飾子とブロック構文を使って格納バッファーを宣言する:
layout (set=m, binding=n) buffer myStorageBuffer
{
vec4 myElement[];
};
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %9 "myStorageBuffer"
OpMemberName %9 0 "myElement"
OpName %11 ""
OpDecorate %8 ArrayStride 16
OpMemberDecorate %9 0 Offset 0
OpDecorate %9 BufferBlock
OpDecorate %11 DescriptorSet m
OpDecorate %11 Binding n
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypeRuntimeArray %7
%9 = OpTypeStruct %8
%10 = OpTypePointer Uniform %9
%11 = OpVariable %10 Uniform
...
Uniform Buffers¶
GLSL シェーダーのソースでは、一様格納修飾子とブロック構文を使って一様バッファーを宣言する:
layout (set=m, binding=n) uniform myUniformBuffer
{
vec4 myElement[32];
};
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %11 "myUniformBuffer"
OpMemberName %11 0 "myElement"
OpName %13 ""
OpDecorate %10 ArrayStride 16
OpMemberDecorate %11 0 Offset 0
OpDecorate %11 Block
OpDecorate %13 DescriptorSet m
OpDecorate %13 Binding n
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypeInt 32 0
%9 = OpConstant %8 32
%10 = OpTypeArray %7 %9
%11 = OpTypeStruct %10
%12 = OpTypePointer Uniform %11
%13 = OpVariable %12 Uniform
...
Subpass Inputs¶
一つのレンダリングパスの中で、サブパスは結果を出力対象に書き込むことができ、その結果を次のサブパスが入力サブパスとして読み取ることができる。「サブパス入力」機能とは、出力対象を読み取る機能だ。
サブパス入力は、断片シェーダーでしか利用できない、新しい型の集合を通して読み込まれる:
subpassInput
subpassInputMS
isubpassInput
isubpassInputMS
usubpassInput
usubpassInputMS
抽出器や画像オブジェクトとは異なり、サブパス入力は断片の (x, y, layer)
座標によって暗黙のうちに指定される。
入力付属物は、記述子集合と束縛番号に加えて、入力付属物のインデックスで装飾される。
layout (input_attachment_index=i, set=m, binding=n) uniform subpassInput myInputAttachment;
これは次の SPIR-V に対応する:
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %9 "myInputAttachment"
OpDecorate %9 DescriptorSet m
OpDecorate %9 Binding n
OpDecorate %9 InputAttachmentIndex i
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 SubpassData 0 0 0 2 Unknown
%8 = OpTypePointer UniformConstant %7
%9 = OpVariable %8 UniformConstant
...
input_attachment_index
が i
の場合、入力パスリストの i 番目の登録を選択する(詳細は API 仕様を参照)。
これらのオブジェクトは、以下の関数によってサブパス入力の読み込みを対処している。
gvec4 subpassLoad(gsubpassInput subpass);
gvec4 subpassLoad(gsubpassInputMS subpass, int sample);
12.2.5. Mapping Variables¶
gl_FragColor
¶
断片段階組み込み gl_FragColor
は、すべての出力へのブロードキャストを意味するが、SPIR-V には存在しない。gl_FragColor
への書き込みが許可されているシェーダーはやはり書き込みが可能だが、
gl_FragColor
と同じ型の位置 0 で装飾されている
組み込みとして装飾されていない
出力への書き込みを意味するだけだ。
暗黙のブロードキャストはない。
Vulkan gl_VertexIndex
and gl_InstanceIndex
¶
既存の組み込み変数 gl_VertexID
と gl_InstanceID
の代わりに、新しい組み込み変数 gl_VertexIndex
と gl_InstanceIndex
が加わる。
インデックスが何らかの基準オフセットに対して相対的である場合、これらの組み込み変数は Vulkan では以下のような値を取るように定義されている:
|
base, base + 1, base + 2, … |
|
base, base + 1, base + 2, … |
基準となるものが何であるかは、状況によって異なる。
読者ノート
これ以降、コード片を引用するのをほとんどやめる。
Storage Classes¶
読者ノート
本文 参照。
Input/Output¶
入力・出力ブロックや変数の対応は、GLSL や ESSL のすべてのバージョンで同じだ。あるバージョンで利用可能な変数やメンバーの位置は次のとおりだ。
これらは SPIR-V の個々の変数に写され、同様の綴り方の組み込み装飾が一緒になる(特記事項を除く):
どの段階でも:
読者ノート
本文 参照。
計算段階:
読者ノート
本文参照。
断片段階:
読者ノート
本文参照。
これらは、疑似コードが暗示するように、SPIR-V ブロックに写され、メンバーには同様の綴り方の組み込み装飾が一緒になる:
非断片段階:
読者ノート
本文参照。
SPIR-V の各段階には、高々一つの入力ブロックと一つの出力ブロックがある。インターフェイスを共有する段階間では、メンバーの部分集合と順序が一致する。
12.2.6. Vulkan Only: Mapping of Precision Qualifiers¶
読者ノート
本文 参照。
12.2.7. Mapping of precise:¶
読者ノート
本文 参照。
12.2.8. OpenGL Mapping of atomic_uint offset layout qualifier¶
読者ノート
本文 参照。
12.2.9. Mapping of Images¶
読者ノート
本文 参照。
12.2.10. Mapping of Layouts¶
読者ノート
本文 参照。
12.2.11. Mapping of barriers¶
読者ノート
本文 参照。
12.2.12. Mapping of atomics¶
読者ノート
本文 参照。
12.2.13. OpenGL Only: Mapping of Atomics¶
読者ノート
本文 参照。
12.2.14. Mapping of other instructions¶
読者ノート
本文 参照。