WGSL
WGSL (WebGPU Shader Language) の文法や仕様の日本語解説が少ないので自分用メモ。仕様を網羅しているわけではなく、自分が書く上で必要そうな部分を適当に抜粋してまとめた。
Tour of WGSL と WGSL の仕様 から日本語に訳して簡単にまとめた。 仕様は長すぎて辛いけど困ったら見るべき。全部書いてある。
定数 (const)
const
の型は abstract-int と abstract-float として扱われ、精度は実際の変数に代入する場所で決まる。
変数
let
はイミュータブルな変数の宣言。ミュータブル変数は var
で宣言する。
var
は var<AS>
で宣言する。AS
はアドレス空間 (address spaces)
var<function>
関数内のローカル変数のデフォルトは var<function>
であり、普通ローカル変数では単に var
で宣言する。
初期値を省略した場合、ゼロ初期化される。
var<private>
シェーダーモジュール内でのグローバル変数。同一モジュール内の全ての関数からアクセス可能。 宣言時の初期値は const-expression でなければならない。省略した場合はゼロ初期化される。 モジュールグローバルでのみ宣言可能。
var<workgroup>
workgroup 内で共有されるミュータブル変数。各呼び出し (invocation) の間では atomic
や workgroupBarrier
で同期する必要がある。
モジュールグローバルでのみ宣言可能。
初期化式は必要なく、各ワーキンググループの実行時に自動でゼロ初期化される。
var<uniform>
ユニフォーム変数
var<storage>
(自分が使ってないので調べてない)
var<handle>
(自分が使ってないので調べてない)
let
イミュータブルな変数宣言。初期化子が必須。関数内ローカルでのみ宣言可能。 ポインタ型にすることが可能。
属性
@
から始まるのが属性。
@vertex fn vs_main() -> @builtin(position) vec4<f32> { ... }
行列
行列の引数省略時はゼロ初期化。引数は列優先。メモリ上の表現も列優先。
const zero_init = mat3x4<f32>(); /* | 0 0 0 | | 0 0 0 | | 0 0 0 | | 0 0 0 | */ const column_wise = mat3x2<f32>(vec2<f32>(1, 2), vec2<f32>(4, 5), vec2<f32>(6, 7)); /* | 1 4 6 | | 2 5 7 | */ const scalar_wise = mat2x3<f32>(1, 2, 3, 4, 5, 6); /* | 1 4 | | 2 5 | | 3 6 | */
配列
- Fixed-Sized Array
array<T, N>
- Runtime-Sized Array
array<T>
Fixed-Sized Array の配列長 N
は定数式ならリテラルでなくともよい。
const numbers = array<i32, 7>(1, 4, 2, 3); const three = 3; const foo: array<i32, three * 2 + 1> = numbers;
Runtime-Sized Array は Storage Buffer のリソースとしてのみ使える。 バッファ全体を表すか、バッファ全体を表す構造体の最後のメンバーとして使う。
要素数は実行時に決定され、変数に関連する BufferBinding のサイズに収まる範囲で可能な限り大きくなる。
実行時の配列長は arrayLength
で取得できる。
インデックスによって値を取得できるが、配列自体を変数に代入することはできない。
@group(0) @binding(0) var<storage> weights: array<f32>; struct PointLight { position: vec3f, color: vec3f, } struct LightData { meanIntensity: f32, point: array<PointLight>, } @group(0) @binding(1) var<storage> lights: LightData; fn number_of_lights() -> u32 { return arrayLength(&lights.point); } fn get_point_light(i: i32) -> PointLight { return lights.point[i]; } fn cannot_copy_whole_array() { // 通常の変数に代入はできない // var all_point_lights = lights.point; // Error }
構造体 (struct)
struct Data { a: f32, b: f32, }
constructible な構造体の場合、()
で初期化できる。
constructible とは
- スカラー型 (
u32
,f32
, etc...) - ベクトル型 (
vec2<f32>
,vec3<f32>
, etc...) - 行列型 (
mat2x2<f32>
,mat3x3<f32>
, etc...) - 要素の型が constructible な固定長配列型 (
array<f32, 3>
, etc...) - メンバーの型が全て constructible な構造体型
const data = Data(1.0, 2.0);
原子性 (atomicity)
uniform
, storage
, workgroup
は並列実行において共有されている。
uniform
は読み取り専用なので問題は起こらないが、storage
と workgroup
は書き込みも可能であるため、競合に注意する必要がある。
atomic<T>
は i32
と u32
に対してのみ使える。
atomic<T>
は workgroup
と storage
のアドレス空間の変数でのみ使える。
var<workgroup> counter: atomic<u32>;
atomic<T>
は constructible ではないため、以下の状況では直接使用できない。
- expression に書けない
- 関数の引数、戻り値に書けない
- 変数に代入できない
- 変数の初期化式に書けない
ビルトイン関数でのみ操作可能で、atomicLoad
と atomicStore
で読み書きできる。
他にも atomicAdd
, atomicMin
, atomicMax
, atomicAnd
, atomicOr
, atomicXor
などがある。
fn atomicLoad(atomic_ptr: ptr<AS, atomic<T>, read_write>) -> T fn atomicStore(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T)
ポインタ (pointer)
ポインタは ptr<AS, T, AM>
で表される。
AS
はアドレス空間 (address spaces)uniform
storage
workgroup
private
function
handle
T
はポインターが指す型AM
はアクセスモード。省略可能read
(default)read_write
アロー演算子 a->b
はない。カッコで囲んで (*a).b
のように書く。
ユーザー定義関数の引数にポインタを使う時の制約
- アドレス空間は
function
かprivate
でなければならない - 変数全体へのポインタのみ使える。複合変数の一部のみのアドレスを渡すことはできない
struct Data { aaa: u32, bbb: u32, } var<private> data: Data; fn foo() { //bar(&data.aaa); // Error: 複合変数の一部のみのアドレスを渡すことはできない }
式 (expression)
三つの評価フェーズがある。
- Shader creation time
- Pipeline creation time
- Shader execution time
Shader creation time
const-expressions の値を確定します。
- リテラル
@const
な関数const
宣言された値
Pipeline creation time
override-expressions の値を確定します。
override
宣言された値GPUProgrammableStage.constants
からの値
Shader execution time
runtime-expressions の値を確定します。
let
やvar
宣言された値- 全ての呼び出し関数
- 変数値
- 変数への参照やポインタ
リテラル
サフィックスのないリテラルは abstract-int か abstract-float になり、具体的な型付きの変数に束縛される時に型が決まる。
サフィックス | 型 | 例 |
---|---|---|
u |
u32 |
1u |
i |
i32 |
1i |
f |
f32 |
1.0f |
@const
ビルトイン関数
radians(x: T) -> T
const_assert(x: bool)
const x = 10; const_assert(x == 10); // false ならコンパイルエラー
制御フロー
if
文
if (condition) { ... }
または
if condition { ... }
switch
文
switch (condition) { ... }
または
switch condition { ... }
let a = 4; switch a { case 1, 2, 3: { } default: { } }
for
文
for(var i = 0; i < 10; i++) { }