1. はじめに
WebGPUシェーディング言語(WGSL)は、[WebGPU]のためのシェーダー言語です。 つまり、WebGPU APIを使用するアプリケーションは、GPU上で実行されるプログラム(シェーダー)をWGSLで記述します。
// テクスチャ付きジオメトリを点光源で照らすフラグメントシェーダー。 // ストレージバッファバインディングからのライト。 struct PointLight { position: vec3f, color : vec3f, } struct LightStorage { pointCount : u32, point : array< PointLight > , } @group ( 0 ) @binding ( 0 ) var < storage> lights : LightStorage ; // テクスチャとサンプラー。 @group ( 1 ) @binding ( 0 ) var baseColorSampler : sampler; @group ( 1 ) @binding ( 1 ) var baseColorTexture : texture_2d< f32> ; // 関数の引数は頂点シェーダーから渡される値。 @fragment fn fragmentMain ( @location ( 0 ) worldPos : vec3f, @location ( 1 ) normal : vec3f, @location ( 2 ) uv : vec2f) -> @location ( 0 ) vec4f{ // テクスチャから表面の基本色をサンプルする。 let baseColor = textureSample ( baseColorTexture , baseColorSampler , uv ); let N = normalize ( normal ); var surfaceColor = vec3f( 0 ); // シーン内の点光源をループ処理。 for ( var i = 0u ; i < lights . pointCount ; i ++ ) { let worldToLight = lights . point [ i ]. position- worldPos ; let dist = length ( worldToLight ); let dir = normalize ( worldToLight ); // このライトの表面色への寄与を算出。 let radiance = lights . point [ i ]. color * ( 1 / pow ( dist , 2 )); let nDotL = max ( dot ( N , dir ), 0 ); // 表面色にライトの寄与を加算。 surfaceColor += baseColor . rgb * radiance * nDotL ; } // 加算した表面色を返す。 return vec4( surfaceColor , baseColor . a ); }
1.1. 概要
WebGPUは、GPUコマンドという形で作業単位をGPUに発行します。 WGSLは、2種類のGPUコマンドに関係します:
-
描画コマンドは、レンダーパイプラインを 入力、出力、および接続されたリソースのコンテキストで実行します。
-
ディスパッチコマンドは、コンピュートパイプラインを 入力と接続されたリソースのコンテキストで実行します。
両方の種類のパイプラインで、WGSLで記述されたシェーダーが使われます。
シェーダーは、 WGSLプログラム内でパイプラインのシェーダーステージを実行する部分です。 シェーダーは次の要素で構成されます:
-
エントリーポイントから開始して呼び出される全関数の推移的閉包。 この集合にはユーザー定義関数と組み込み関数の両方が含まれます。 (より厳密な定義は「シェーダーステージ内の関数」を参照してください。)
-
それらすべての関数によって静的にアクセスされる変数および定数の集合。
-
それらすべての関数、変数、定数を定義または解析するために使われる型の集合。
注意: WGSLプログラムはエントリーポイントを必須としません。ただし、エントリーポイントがないプログラムはAPIによって実行できません。なぜなら、エントリーポイントがGPUProgrammableStageの作成に必要だからです。
シェーダーステージを実行する際、実装は次の処理を行います:
-
モジュールスコープで宣言された定数の値を計算します。
-
シェーダーのリソースインターフェース内の変数にリソースをバインドし、 実行中にそれらのリソース内容を利用できるようにします。
-
その他のモジュールスコープ変数のためのメモリを割り当て、 指定された初期値でそのメモリを初期化します。
-
エントリーポイントに形式的パラメータがある場合、シェーダーステージの入力値でそれらを初期化します。
-
エントリーポイントの返り値がある場合、それをシェーダーステージの出力に接続します。
-
その後、エントリーポイントを呼び出します。
WGSLプログラムは次の要素から構成されます:
-
ディレクティブ(モジュールレベルの振る舞い制御)。
-
関数(実行の振る舞いを定義)。
-
文(宣言または実行単位)。
-
リテラル(純粋な数値を表現するテキスト)。
-
定数(特定のタイミングで計算された値に名前を付与)。
-
変数(値を保持するメモリに名前を付与)。
-
式(値を組み合わせて結果値を生成)。
-
型(以下を記述):
-
値の集合。
-
対応する式の制約。
-
それらの式の意味論。
-
-
属性(以下のような追加情報を指定):
注意: WGSLプログラムは現在、単一のWGSLモジュールで構成されます。
WGSLは命令型言語です。挙動は実行する文の列として記述します。 文は次のことができます:
-
変数の内容を変更する。
-
構造化プログラミング構造を使って実行順序を制御する:
-
上記の挙動の一部として値を計算するために式を評価する。
WGSLは静的型付け言語です。各式で計算される値は、プログラムソースのみから決定される特定の型を持ちます。
WGSLにはブール値や数値(整数と浮動小数点)を記述する型があります。 これらの型は複合型(ベクトル、行列、 配列、構造体)に集約できます。 WGSLには、固有の操作を提供するアトミック型などの特殊な型があります。 WGSLはメモリに格納可能な型をメモリビューとして記述します。 WGSLはテクスチャやサンプラーなど、よく使われるレンダリング型も提供します。 これらの型には、グラフィックスレンダリングのためのGPUハードウェアを活用する組み込み関数が用意されています。
WGSLには、具体型からの暗黙の変換や昇格はありませんが、 抽象型からの暗黙の変換・昇格は許可されます。 ある具体型の数値型やブール型から他の型へ値を変換するには、 明示的な変換や 値コンストラクタ、 ビットの再解釈が必要です。ただし、WGSLはスカラー型からベクトル型への限定的な昇格機能を提供します。 これは複合型にも適用されます。
シェーダーステージの作業は、1つ以上の呼び出しに分割されます。 各呼び出しはエントリーポイントを実行しますが、状況が少し異なります。 シェーダーステージの呼び出しは、特定の変数へのアクセスを共有します:
-
ステージ内のすべての呼び出しは、シェーダーインターフェースのリソースを共有します。
-
コンピュートシェーダーでは、同じ ワークグループ内の呼び出しは、 workgroup アドレス空間の変数を共有します。 異なるワークグループ間ではそれらの変数は共有されません。
ただし、呼び出しはステージ入力(同僚と区別する識別値を提供する組み込み入力を含む)の異なる集合に対して動作します。 各呼び出しは、privateやfunctionアドレス空間の変数として独立したメモリ空間を持ちます。
同じシェーダーステージ内の呼び出しは同時に実行され、多くの場合並列で動作します。 シェーダー作成者は、呼び出しの動的な挙動が次を満たすよう責任を持ちます:
-
テクスチャサンプリングや制御バリアなど、一部の基本操作の均一性要件を満たす。
-
共有変数への競合するアクセスが発生する場合、データ競合を回避するように調整する。
WGSLは、ある機能に対して複数の挙動を許容する場合があります。 これは移植性の問題となり、実装によって異なる挙動が現れることがあります。 WGSLの設計はそのようなケースを最小化することを目指していますが、実現可能性や幅広いデバイスで高性能を発揮するという目標に制約されることもあります。
挙動要件は、 WGSLプログラムの処理や実行時に実装が行うべきアクションです。これらは プログラマーとの契約における実装の義務を示します。 仕様書は、明らかでない場合に明示的にこれらの義務を記載します。
1.2. 構文記法
以下の構文記法はWGSLの構文文法規則の慣例を示します:
-
規則の両端が斜体の場合は構文規則を示します。
-
右辺の始まりと終わりが単一引用符(')で囲まれた太字等幅テキストはキーワードやトークンを示します。
-
普通のテキストのコロン(:)は構文規則の定義を示します。
-
普通のテキストの縦棒(|)は選択肢(オルタナティブ)を示します。
-
普通のテキストの疑問符(?)は、直前のキーワード・トークン・規則・グループが0回または1回現れる(省略可能)ことを示します。
-
普通のテキストのアスタリスク(*)は、直前のキーワード・トークン・規則・グループが0回以上現れることを示します。
-
普通のテキストのプラス(+)は、直前のキーワード・トークン・規則・グループが1回以上現れることを示します。
-
普通のテキストの丸括弧(()())は要素のグループを示します。
1.3. 数学的用語と記法
角度:
-
慣例として、角度はラジアンで計測されます。
-
角度測定の基準光線は、原点 (0,0) から (+∞,0) 方向への光線です。
-
θ を比較光線と基準光線のなす角度とします。 比較光線が反時計回りに動くと θ は増加します。
-
1周(円)は 2π ラジアンです。
-
例:
-
角度0は原点から右 (1,0) 方向
-
角度2πも原点から右 (1,0) 方向
-
角度π/4は原点から (1,1) 方向
-
角度π/2は原点から (0,1) 方向
-
角度πは原点から (-1,0) 方向
-
角度(3/2)πは原点から (0,-1) 方向
-
双曲線角は、従来の角度ではなく単位のない面積です。具体的には:
-
x2 - y2 = 1 かつ x > 0 の双曲線を考えます。
-
R を原点から双曲線上の点 (x, y) への光線とします。
-
a を、R、x軸、双曲線の曲線で囲まれる面積の2倍とします。
-
R がx軸より上なら a を正、下なら負とします。
この面積 a は双曲線角であり、x は a の双曲線余弦、y は双曲線正弦となります。
正の無限大(+∞)はすべての実数より大きい固有の値です。
負の無限大(−∞)はすべての実数より小さい固有の値です。
拡張実数(またはアフィン拡張実数)は実数全体に+∞と−∞を加えた集合です。 コンピューターは浮動小数点型で拡張実数を近似表現し、両方の無限大値も含みます。 § 15.7 浮動小数点評価も参照してください。
区間は下限と上限を持つ連続した数値集合です。 文脈によって、整数・浮動小数点・実数・拡張実数集合の場合があります。
-
閉区間 [a,b] は a ≤ x ≤ b を満たす x の集合です。
-
半開区間 [a,b) は a ≤ x < b の x集合です。
-
半開区間 (a,b] は a < x ≤ b の x集合です。
床関数は、拡張実数 x に対し:
-
⌊ +∞ ⌋ = +∞
-
⌊ −∞ ⌋ = −∞
-
実数 x について、⌊x⌋ = k(k ≤ x < k+1 となる唯一の整数 k)
天井関数は、拡張実数 x に対して:
-
⌈ +∞ ⌉ = +∞
-
⌈ −∞ ⌉ = −∞
-
実数 x について、⌈x⌉ = k(k-1 < x ≤ k となる唯一の整数 k)
切り捨て関数は、拡張実数 x に対して:
-
truncate(+∞) = +∞
-
truncate(−∞) = −∞
-
実数 x について、絶対値が x 以下となる最近接の整数値:
-
x ≥ 0 の場合 truncate(x) = ⌊x⌋、x < 0 の場合 truncate(x) = ⌈x⌉
-
roundUp関数は、正の整数 k と n に対し:
-
roundUp(k, n) = ⌈n ÷ k⌉ × k
転置は、c列 r行の行列 Aを、r列 c行の行列 ATとして Aの行を ATの列へコピーすることで作られます:
-
transpose(A) = AT
-
transpose(A)i,j = Aj,i
列ベクトルの転置は1行の行列として解釈され、同様に行ベクトルの転置は1列の行列として解釈されます。
2. WGSLモジュール
WGSLプログラムは単一のWGSLモジュールから構成されます。
モジュールは、オプションのディレクティブの並びの後に、モジュールスコープの宣言およびアサーションが続きます。 モジュールは以下の要素で構成されます:
-
ディレクティブ(モジュールレベルの振る舞い制御を指定)。
-
関数(実行時の挙動を指定)。
-
文(宣言や実行単位)。
-
リテラル(純粋な数値を表現するテキスト)。
-
変数(値を保持するメモリに名前を付与)。
-
定数(特定のタイミングで計算された値に名前を付与)。
-
式(値を組み合わせて結果値を生成)。
-
型(以下を記述):
-
値の集合。
-
対応する式の制約。
-
それらの式の意味。
-
-
属性(以下のような追加情報を指定):
global_directive * ( global_decl | global_assert | ';' ) *
2.1. シェーダーのライフサイクル
WGSLプログラムとその中のシェーダーが経験するライフサイクルには、4つの主要なイベントがあります。 最初の2つはWGSLプログラムを実行準備するために使われるWebGPU APIメソッドに対応しています。 最後の2つはシェーダーの実行開始と終了です。
イベントは以下の通りです:
-
シェーダーモジュール作成
-
これはWebGPU
createShaderModule()メソッドが呼ばれたときに発生します。 WGSLプログラムのソーステキストはこの時点で提供されます。
-
-
パイプライン作成
-
これはWebGPU
createComputePipeline()メソッド またはWebGPUcreateRenderPipeline()メソッドが呼ばれたときに発生します。 これらのメソッドは、事前に作成された1つ以上のシェーダーモジュールと他の設定情報を使用します。 -
指定されたエントリーポイントの
GPUProgrammableStageのシェーダーを構成するコードのみがパイプライン作成時に考慮されます。 つまり、エントリーポイントに関係しないコードはコンパイル前に実質的に除去されます。 -
注意: 各シェーダーステージは個別にコンパイルされるとみなされるため、 モジュールの異なる部分を含む場合があります。
-
-
シェーダー実行開始
-
これは描画またはディスパッチコマンドがGPUに発行され、 パイプラインの実行が開始され、 シェーダーステージのエントリーポイント関数が呼び出されるときに発生します。
-
-
シェーダー実行終了
これらのイベントは次の理由で順序付けられます:
-
データ依存性:シェーダー実行はパイプラインを必要とし、パイプラインはシェーダーモジュールを必要とします。
-
因果関係:シェーダーは実行開始しなければ終了できません。
2.2. エラー
WebGPUの実装がシェーダーの処理に失敗する理由は2つあります:
-
プログラムエラー は、シェーダーがWGSLやWebGPUの仕様要件を満たしていない場合に発生します。
-
未分類エラーは、 WGSLやWebGPUの要件をすべて満たしている場合でも発生することがあります。 その原因例:
-
シェーダーが複雑すぎて実装の能力を超えている(ただし制限で容易に捕捉できない方法で)。 シェーダーを単純化することで回避できる場合があります。
-
WebGPU実装の不具合。
-
処理エラーはシェーダーのライフサイクルの3段階で発生する場合があります:
-
シェーダー作成エラー は、シェーダーモジュール作成時に現実的に検出可能なエラーです。 検出にはWGSLモジュールのソーステキストと
createShaderModuleAPIメソッドで得られる他の情報のみが利用されます。 この仕様でプログラムが必須とされていることに違反した場合、通常はシェーダー作成エラーとなります。 -
パイプライン作成エラー は、パイプライン作成時に検出可能なエラーです。 検出にはWGSLモジュールのソーステキストと、該当するパイプライン作成APIメソッドで得られる他の情報が利用されます。 これらのエラーは、シェーダーの エントリーポイント用にコンパイルされる
GPUProgrammableStageのコードに対してのみ発生します。 -
動的エラーはシェーダーの実行中に発生するエラーです。 これらのエラーは検出される場合もされない場合もあります。
注意: 例えば、データレースは検出できない場合があります。
各要件willは最も早く検出可能なタイミングでチェックされます。 つまり:
-
シェーダー作成時に検出できる要件違反はシェーダー作成エラーとなります。
-
パイプライン作成時にのみ検出できる要件違反はパイプライン作成エラーとなります。
文脈からはっきりしない場合、この仕様書は 特定の要件の違反が シェーダー作成エラー・パイプライン作成エラー・動的エラーのどれにつながるかを明示します。
エラーの結果は以下の通りです:
-
シェーダー作成エラーやパイプライン作成エラーのあるWGSLモジュールは、 パイプラインに組み込まれず、実行されません。
-
動的エラーが発生した場合:
2.3. 診断
実装はシェーダーモジュール作成またはパイプライン作成の間に診断を生成できます。 診断とは、実装がアプリケーション制作者のために出力するメッセージです。
診断は、特定の条件が満たされたときに作成またはトリガーされます。 この条件をトリガールールと呼びます。 条件が満たされたソーステキスト中の場所(点または範囲)は トリガー位置と呼ばれます。
診断は次のプロパティを持ちます:
診断の重大度は以下のいずれかであり、高い順に並んでいます:
- error(エラー)
-
診断はエラーです。 これはシェーダー作成エラーまたはパイプライン作成エラーに相当します。
- warning(警告)
-
診断は開発者の注意を促す異常を記述しますが、エラーではありません。
- info(情報)
-
診断は開発者の注意を促す注目すべき状態を記述しますが、エラーでも警告でもありません。
- off(無効)
-
診断は無効化されています。アプリケーションには通知されません。
トリガールールの名前は、以下のいずれかです:
-
2つのdiagnostic_name_tokenをピリオド
'.'(U+002E)で区切ったもの
2.3.1. 診断処理
トリガーされた診断はwill次のように処理されます:
-
各診断Dについて、Dのトリガー位置を含み、かつ同じトリガールールを持つ最小の診断フィルターを探す。
-
そのようなフィルターが存在すれば、Dに適用し、Dの重大度を更新する。
-
存在しなければDは変更されません。
-
-
重大度offの診断を破棄します。
-
残った診断のうち、少なくとも1つDIが重大度infoなら:
-
同じトリガールールを持つ他のinfo診断は破棄されることがあり、元の診断DIのみが残ります。
-
-
残った診断のうち、少なくとも1つDWが重大度warningなら:
-
残った診断にerror重大度がある場合:
-
他の診断(error重大度を含む)も破棄されることがあります。
-
プログラムエラーが生成されます。
-
エラーがシェーダーモジュール作成時にトリガーされた場合はシェーダー作成エラーです。
-
エラーがパイプライン作成時にトリガーされた場合はパイプライン作成エラーです。
-
-
-
シェーダーモジュール作成時処理の場合、残った診断はWebGPU
messagesメンバーに格納されます(GPUCompilationInfoオブジェクト)。 -
パイプライン作成時処理の場合、error診断はWebGPUの検証失敗につながります(
GPUProgrammableStageの検証時)。
注意: これらの規則により、実装はエラーを検出した時点でWGSLモジュールの処理を打ち切ることができます。 また、ある種の警告分析は最初の警告で打ち切ることができ、ある種の情報診断分析も最初の発生で打ち切ることができます。 WGSLはさまざまな分析手順の順序や、単一分析内の順序を規定しません。 したがって、同じWGSLモジュールでも、異なる実装は同じ重大度の診断のインスタンスを異なる数だけ報告する場合があります。
2.3.2. フィルタ可能なトリガールール
ほとんどの診断は無条件でWebGPUアプリケーションに報告されます。 一部の診断は、フィルタ可能であり、トリガールールの名前付けにより部分的に制御できます。 以下の表はフィルタ可能な標準的トリガールールを示します。
| フィルタ可能トリガールール | デフォルト重大度 | トリガー位置 | 説明 |
|---|---|---|---|
| derivative_uniformity | error | 微分を計算する組み込み関数の呼び出し位置。 つまり、以下への呼び出しの位置: |
組み込み関数呼び出しで微分を計算するが、均一性解析がその呼び出しが均一な制御フロー内で発生することを証明できない場合。
§ 15.2 均一性も参照。 |
| subgroup_uniformity | error | サブグループやクアッド組み込み関数の呼び出し位置。 |
サブグループまたはクアッド組み込み関数呼び出しだが、均一性解析がその呼び出しが均一な制御フロー内で発生することを証明できない場合。
また、均一性解析が以下のパラメータ値の均一性を証明できない場合:
§ 15.2 均一性も参照。 |
1つのdiagnostic name-tokenで構成される認識されないトリガールールを使うと、ユーザーエージェントは警告をトリガーするべきです。
実装はここで定義されていないトリガールールもサポートしてよいですが、 diagnostic_rule_nameの複数トークン形式で記述されている必要があります。 未認識のトリガールールを複数トークン形式で記述した場合、それ自体が診断をトリガーすることがあります。
将来の仕様書バージョンでは、特定のルールを削除したり、デフォルト重大度を弱めたり(現在のデフォルトより軽くする)しても後方互換性を満たしたとみなされます。
例えば、WGSLの将来バージョンでderivative_uniformityのデフォルト重大度をerrorからwarningまたはinfoに変更することがあります。
このような仕様変更後も、以前は有効だったプログラムは引き続き有効です。
2.3.3. 診断フィルター
フィルタ可能なトリガールールを持つ診断がトリガーされると、WGSLはその診断を破棄したり重大度を変更する仕組みを提供します。
診断フィルター DFは3つのパラメータを持ちます:
診断フィルターDF(AR,NS,TR)を診断Dに適用すると、以下の効果があります:
範囲診断フィルターは、
診断フィルターのうち、影響範囲が指定されたソーステキストの範囲であるものです。
範囲診断フィルターは、影響範囲の先頭に@diagnostic属性として指定します。
@diagnostic属性は他の場所には現れてはなりません。
| 配置 | 影響範囲 |
|---|---|
| 複合文の先頭 | その複合文 |
| 関数宣言の先頭 | 関数宣言 |
| if文の先頭 | if文:if_clauseおよび関連するelse_if_clause、else_clause、制御条件式すべてを含む |
| switch文の先頭 | switch文:セレクター式とswitch_body |
| switch_bodyの先頭 | switch_body |
| loop文の先頭 | loop文 |
| while文の先頭 | while文:条件式とループ本体両方 |
| for文の先頭 | for文:for_headerとループ本体 |
ループ本体の開始波括弧('{')直前
| ループ本体 |
| continuing_compound_statementの先頭 | continuing_compound_statement |
注意: 以下も複合文です: 関数本体、case句、default-alone句、 whileやforループの本体、 if_clause、else_if_clause、else_clauseの本体。
var < private> d : f32; fn helper () -> vec4< f32> { // "if"の本体でderivative_uniformity診断を無効化。 if ( d < 0.5 ) @diagnostic ( off , derivative_uniformity ) { return textureSample ( t , s , vec2( 0 , 0 )); } return vec4( 0.0 ); }
グローバル診断フィルターを使うと、WGSLモジュール全体に診断フィルターを適用できます。
diagnostic ( off , derivative_uniformity ); var < private> d : f32; fn helper () -> vec4< f32> { if ( d < 0.5 ) { // グローバル診断フィルターでderivative_uniformity診断が無効化されています。 return textureSample ( t , s , vec2( 0 , 0 )); } else { // derivative_uniformity診断は'warning'重大度に設定されています。 @diagnostic ( warning , derivative_uniformity ) { return textureSample ( t , s , vec2( 0 , 0 )); } } return vec4( 0.0 ); }
2つの診断フィルター DF(AR1,NS1,TR1)とDF(AR2,NS2,TR2)が 競合するのは以下の場合です:
-
(AR1 = AR2)、かつ
-
(TR1 = TR2)、かつ
-
(NS1 ≠ NS2)。
注意: 競合しない場合、複数のグローバル診断フィルターの利用が可能です。
WGSLの診断フィルターは、その影響範囲が完全に入れ子となるように設計されています。 DF1の影響範囲がDF2の影響範囲と重なる場合、DF1の影響範囲はDF2の影響範囲に完全に含まれるか、その逆です。
ソース位置LとトリガールールTRに対する最も近い囲み診断フィルター(存在する場合)は、DF(AR,NS,TR)で次を満たすものです:
-
Lが影響範囲ARに含まれること
-
他にDF'(AR',NS',TR)がありLがAR'に含まれる場合、ARはAR'に含まれること
影響範囲が入れ子になるため、最も近い囲み診断:
-
唯一の範囲診断フィルターとなる、
-
または重複した(競合しない)グローバル診断フィルターのひとつ、
-
または存在しない。
2.4. 制限
WGSLの実装は以下の制限を満たすシェーダーをサポートするwill必要があります。 WGSLの実装は、指定された制限を超えるシェーダーもサポートしてよいです。
注意: WGSL実装は、指定された制限を超えるシェーダーをサポートしない場合エラーを出すべきです。
| 制限 | 最低サポート値 |
|---|---|
| 構造体型のメンバー最大数 | 1023 |
| 複合型の入れ子深度の最大値 | 15 |
| 関数内の波括弧で囲まれた文の最大入れ子深度 | 127 |
| 関数のパラメータ最大数 | 255 |
| switch文のcaseセレクター値最大数。 各case文のcase値数およびdefault句の合計。 | 1023 |
| privateアドレス空間で1つのシェーダーによって静的にアクセスされる変数すべての合計バイトサイズ最大値 | 8192 |
| functionアドレス空間で1つの関数に宣言された変数すべての合計バイトサイズ最大値 | 8192 |
|
workgroupアドレス空間で1つのシェーダーによって静的にアクセスされる変数すべての合計バイトサイズ最大値
この制限のため、固定フットプリント配列は、オーバーライド値で置き換える際に作成時固定フットプリント配列として扱われます。 これはWebGPUのmaxComputeWorkgroupStorageSize 制限をWGSL独自の制限へマッピングします。 | 16384 |
|
即時データ
変数の最大バイトサイズ。
これは、WebGPU の maxImmediateSize 制限を、 独立した WGSL 制限に対応付ける。 | 64 |
| value constructor式のarray型における要素最大数 | 2047 |
3. テキスト構造
text/wgslメディアタイプは、WGSLモジュールとしてコンテンツを識別するために使われます。
付録A: text/wgslメディアタイプを参照してください。
WGSLモジュールはUTF-8でエンコードされたUnicodeテキストで、バイトオーダーマーク(BOM)はありません。
WGSLモジュールのテキストは、Unicodeのコードポイントの並びであり、連続した空でない集合にグループ化されて以下を形成します:
プログラムテキストはヌルコードポイント(U+0000)を含んではなりません。
3.1. 構文解析
WGSLモジュールを構文解析する手順:
コメントを削除:
最初のコメントをスペースコードポイント(
U+0020)に置換。コメントが残っている限り繰り返す。
テンプレートリスト(template lists)をアルゴリズムにより、§ 3.9 Template Listsで検索します。 このステップで、
'<'(U+003C) と'>'(U+003E) コードポイントがテンプレートリストの区切りとして使われる場合と、比較演算子など他の用途の場合を判別します。全文を、translation_unit構文規則にマッチさせて解析する。 解析にはLALR(1)パーサ(一つ先読み)[DeRemer1969]を使い、以下のカスタマイズがあります:
字句解析(トークン化)は構文解析と交互に行われ、文脈依存です。 パーサが次のトークンを要求したとき:
最初の空白コードポイントの並びを消費して無視する。
次のコードポイントがテンプレートリストの開始なら、それを消費して_template_args_startを返す。
次のコードポイントがテンプレートリストの終了なら、それを消費して_template_args_endを返す。
それ以外の場合:
トークン候補は、残りの未消費コードポイントの非空接頭辞から形成されるWGSLのトークンです。
返すトークンは、現在のパーサ状態に対して有効な先読みトークンでもある、最長のトークン候補です。[VanWyk2007]
次の場合はシェーダー作成エラーとなります:
-
ソーステキスト全体が有限個の有効なトークン列に変換できない場合
-
translation_unit構文規則がトークン列全体にマッチしない場合
代替方法としては、テンプレートリスト探索を字句解析(トークナイズ)と組み合わせる方法があります。 この方法では、テンプレートリストが現れる可能性がある文法規則の任意の場所に合成トークン(_disambiguate_template)を配置します。 スキャナーが_disambiguate_templateトークンの一致を試みるとき:
-
スキャナーは残りのテキストに対してテンプレートリスト探索アルゴリズムを実行し、テンプレートリストの区切り位置を記録します。
-
スキャナーは
_disambiguate_templateトークンの一致に成功したことを通知し、関連するテキストとして空文字列を返します。
今後のトークンスキャン処理では、記録されたテンプレートリスト区切り位置を使って、 _template_args_startおよび_template_args_endトークンを適宜生成します。
この代替方法は規範的ではありません。 標準の文法には、代替方法を使用する実装を助けるために _disambiguate_templateトークンが含まれています。 標準的な方法を使うパーサーは、合成トークンを無視するか、同様に常に空文字列への一致とみなすことができます。
3.2. 空白と改行
空白は、 UnicodeのPattern_White_Spaceプロパティのいずれかのコードポイント1つ以上の組み合わせです。 以下はPattern_White_Spaceに含まれるコードポイントの集合です:
-
スペース(
U+0020) -
水平タブ(
U+0009) -
改行(
U+000A) -
垂直タブ(
U+000B) -
フォームフィード(
U+000C) -
復帰(
U+000D) -
次行(
U+0085) -
左から右マーク(
U+200E) -
右から左マーク(
U+200F) -
行区切り(
U+2028) -
段落区切り(
U+2029)
改行は、 空白コードポイントの連続で、行の終端を示します。 これはUAX14 Section 6.1 Non-tailorable Line Breaking Rules、LB4、LB5で規定される「必須改行」です。 すなわち、改行となるのは以下のいずれかです:
-
改行(
U+000A) -
垂直タブ(
U+000B) -
フォームフィード(
U+000C) -
復帰(
U+000D)で、その後に改行(U+000A)が続かない場合 -
復帰(
U+000D)の直後に改行(U+000A)が続く場合 -
次行(
U+0085) -
行区切り(
U+2028) -
段落区切り(
U+2029)
注意: ソーステキストの行番号で報告する診断は、改行を使って行数を数えるべきです。
3.3. コメント
コメントは、 WGSLプログラムの妥当性や意味に影響しないテキスト範囲ですが、コメントはトークンを分離することができます。 シェーダー作者はコメントを使ってプログラムを記録できます。
行末コメントはコメントの一種で、
次の2つのコードポイント//(U+002F、U+002F)と、その後に続くコードポイントからなります。
ただし、以下のいずれかまで(含まず):
-
次の改行
-
プログラムの終端
ブロックコメントはコメントの一種で、以下からなります:
-
2つのコードポイント
/*(U+002F、U+002A) -
その後、以下のいずれかの並び:
-
*/(U+002A、U+002F)または/*(U+002F、U+002A)を含まないテキスト
-
最後に2つのコードポイント
*/(U+002A、U+002F)
注意: ブロックコメントは入れ子にできます。 ブロックコメントは開始と終了のテキスト一致が必要で、任意の入れ子を許すため、正規表現で認識することはできません。 これは正規言語のポンピング補題の帰結です。
const f = 1.5 ; // これは行末コメントです。 const g = 2.5 ; /* これは複数行にまたがるブロックコメントです /* ブロックコメントは入れ子にできます。 */ ただしすべてのブロックコメントは終了しなければなりません。 */
3.4. トークン
トークンは、以下のいずれかを構成する連続したコードポイントの並びです:
3.5. リテラル
リテラルは以下のいずれかです:
3.5.1. 真偽値リテラル
'true'
| 'false'
3.5.2. 数値リテラル
数値リテラルの形式はパターンマッチングで定義されます。
整数リテラルは以下の通り:
-
整数は次のいずれかで指定:
-
0 -
最初の数字が
0でない10進数字の並び -
0xまたは0Xに続く16進数字の並び
-
-
その後、オプションで
iまたはuサフィックス
注意: 非ゼロ整数リテラルの先頭ゼロ(例:012)は禁止です。他言語の先頭ゼロ=8進数記法との混同を避けるためです。
/0[iu]?/
| /[1-9][0-9]*[iu]?/
/0[xX][0-9a-fA-F]+[iu]?/
浮動小数点リテラルは10進浮動小数点リテラルまたは16進浮動小数点リテラルです。
浮動小数点リテラルは、分数を表す仮数部と、オプションの指数部の2つの論理部分を持ちます。 リテラルの値は概ね、仮数部を基数^指数の値で乗算したものです。 仮数部の数字は、ゼロでない場合、または左と右にゼロでない数字が両方ある場合、有効桁とみなされます。 有効桁は左から右へ数えます。N番目の有効桁は左にN-1個の有効桁があります。
10進浮動小数点リテラルは以下の通り:
-
仮数部は数字の並びで、小数点(
.)がどこかに現れてもよいです。 仮数部は10進表記の分数を表します。 -
その後、オプションで指数部(以下の並び):
-
eまたはE -
符号(
+または-)を先頭に付けてもよい10進数の指数 -
その後、オプションで
fまたはhサフィックス
-
-
小数点、指数、
fまたはhサフィックスのうち、少なくとも1つは必須です。 どれもない場合、そのトークンは整数リテラルです。
/0[fh]/
| /[1-9][0-9]*[fh]/
| /[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?[fh]?/
| /[0-9]+\.[0-9]*([eE][+-]?[0-9]+)?[fh]?/
| /[0-9]+[eE][+-]?[0-9]+[fh]?/
const a = 0.e+4f ; const b = 01. ; const c = .01 ; const d = 12.34 ; const f = .0f ; const g = 0h ; const h = 1e-3 ;
-
significandからeffective_significandを計算:
-
significandが20桁以下の有効桁なら、effective_significandはsignificandです。
-
それ以外:
-
20桁目より右の各桁を0に置換したものがtruncated_significand。
-
20桁目を1増やし、必要に応じて左に桁上げし、右の桁を0にしたものがtruncated_significand_next。
-
effective_significandはtruncated_significandまたはtruncated_significand_next(実装依存)
-
-
-
リテラルの値はeffective_significandを10進分数として解釈し、指数をべき乗した10で乗算したものです。 指数がなければ0とみなします。
注意: 小数部は20桁以降切り捨て、約log(10)/log(2)×20 ≈ 66.4ビットの有効精度が保持されます。
16進浮動小数点リテラルは以下の通り:
-
0xまたは0Xプリフィックス -
その後、16進数字の並びで、どこかに16進小数点(
.)があってもよい 仮数部は16進表記の分数を表します。 -
その後、オプションで指数部(以下の並び):
-
pまたはP -
符号(
+または-)を先頭に付けてもよい10進数の指数 -
その後、オプションで
fまたはhサフィックス
-
/0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+([pP][+-]?[0-9]+[fh]?)?/
| /0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*([pP][+-]?[0-9]+[fh]?)?/
| /0[xX][0-9a-fA-F]+[pP][+-]?[0-9]+[fh]?/
const a = 0xa.fp+2 ; const b = 0x1P+4f ; const c = 0X.3 ; const d = 0x3p+2h ; const e = 0X1.fp-4 ; const f = 0x3.2p+2h ;
-
significandからeffective_significandを計算:
-
significandが16桁以下の有効桁なら、effective_significandはsignificandです。
-
それ以外:
-
16桁目より右の各桁を0に置換したものがtruncated_significand。
-
16桁目を1増やし、必要に応じて左に桁上げし、右の桁を0にしたものがtruncated_significand_next。
-
effective_significandはtruncated_significandまたはtruncated_significand_next(実装依存)
-
-
-
リテラルの値はeffective_significandを16進分数として解釈し、指数をべき乗した2で乗算したものです。 指数がなければ0とみなします。
注意: 16進仮数部は16桁以降切り捨て、約4×16=64ビットの有効精度が保持されます。
数値リテラルにサフィックスがある場合、そのリテラルは特定の具象スカラー型の値を表します。 サフィックスがない場合、リテラルは下記の抽象数値型のいずれかを表します。 いずれの場合も、リテラルの値は型変換後の数学的値であり、 § 15.7.6 浮動小数点変換の規則に従います。
| 数値リテラル | サフィックス | 型 | 例 |
|---|---|---|---|
| 整数リテラル | i
| i32 | 42i |
| 整数リテラル | u
| u32 | 42u |
| 整数リテラル | AbstractInt | 124 | |
| 浮動小数点リテラル | f
| f32 | 42f 1e5f 1.2f 0x1.0p10f |
| 浮動小数点リテラル | h
| f16 | 42h 1e5h 1.2h 0x1.0p10h |
| 浮動小数点リテラル | AbstractFloat | 1e5 1.2 0x1.0p10 |
次の場合はシェーダー作成エラーとなります:
-
整数リテラルに
iやuサフィックスが付き、対象型で表せない場合 -
16進浮動小数点リテラルに
fやhサフィックスが付き、型であふれるか、正確に表現できない場合 -
10進浮動小数点リテラルに
fやhサフィックスが付き、型であふれる場合
注意: 16進浮動小数点値0x1.00000001p0は正確に表すには33有効ビットが必要ですが、f32は明示的有効ビットが23しかありません。
注意:
16進floatリテラルを型指定したい場合、fサフィックスを使うなら2進指数も必要です。例:0x1p0f。0x1fは16進整数リテラルです。
3.6. キーワード
キーワードは、あらかじめ定義された言語概念を指すトークンです。 WGSLキーワード一覧は§ 16.1 キーワード一覧を参照してください。
3.7. 識別子
識別子は、名前として使用されるトークンの一種です。 詳細は§ 5 宣言とスコープを参照してください。
WGSLは用途ごとに2つの文法非終端記号を使い分けています:
-
identは宣言されたオブジェクトの名前に使われます。
-
member_identは構造体型のメンバーの名前に使われます。
識別子の形式は、Unicode Standard Annex #31 (Unicode Version 14.0.0)に基づき、 以下の補足があります。
識別子はUAX31文法で次のプロファイルを使います:
<Identifier> := <Start> <Continue>* (<Medial> <Continue>+)* <Start> := XID_Start + U+005F <Continue> := <Start> + XID_Continue <Medial> :=
つまり、非ASCIIコードポイントを含む識別子も有効です:Δέλτα、réflexion、Кызыл、𐰓𐰏𐰇、朝焼け、سلام、検定、שָׁלוֹם、गुलाबी、փիրուզなど。
ただし以下は例外です:
/([_\p{XID_Start}][\p{XID_Continue}]+)|([\p{XID_Start}])/u
Unicode Character Database for Unicode Version 14.0.0には XID_Startおよび XID_Continueの全有効コードポイントが非規範的に列挙されています。
注意: 一部の組み込み関数の戻り値型は、名前がWGSLソースで使用できない構造体型です。
それらの構造体型は、名前がアンダースコア2文字で始まるものとして事前宣言されたものとみなされます。
結果値は新しく宣言したletやvarに型推論で保存するか、そのメンバーを直接名前指定で抽出できます。
使用例はfrexpやmodfの説明を参照してください。
3.7.1. 識別子の比較
2つのWGSL識別子は、同じコードポイントの並びである場合に限り同一です。
注意: この仕様では比較時のUnicode正規化を認めていません。 見た目や意味が同じでも、異なるUnicode文字列の並びであれば一致しません。 著者は値のエンコード順序を一貫して使うか、問題を起こしそうな文字を避けることが推奨されます。 詳細は[CHARMOD-NORM]参照。
注意: ユーザーエージェントは、識別子のすべての出現箇所を、その同形異義語(ホモグリフ)で置換した場合WGSLモジュールの意味が変わるとき、 開発者向け警告を出すべきです。 (ホモグリフとは、読者に同じに見える可能性のあるコードポイント列のこと。 マッピング検出例は前段落の変換・マッピング・照合アルゴリズムなど。 反復的に部分列をホモグリフで置換することで識別子を変換できる場合、2つの列は同形異義語とみなされます。)
3.8. 文脈依存名
文脈依存名は、特定の文法的文脈でのみ概念の名前として使われるトークンです。 トークンの綴りは識別子と同じ場合もありますが、そのトークンは宣言されたオブジェクトに解決されません。 このセクションでは、文脈依存名として使われるトークンを列挙します。 トークンはキーワードや予約語であってはなりません。
3.8.1. 属性名
§ 12 属性を参照してください。
属性名:
3.8.2. 組み込み値名
組み込み値名トークンは、組み込み値の名前に使われるトークンです。
組み込み値名:
3.8.3. 診断ルール名
診断名トークンは、診断トリガールールの名前に使われるトークンです。
§ 2.3 診断参照。
あらかじめ定義された診断ルール名:
3.8.4. 診断重大度制御名
有効な診断フィルター重大度制御名は§ 2.3 診断に記載されていますが、形式は識別子と同じです:
診断フィルター重大度制御名:
3.8.5. 拡張名
有効な拡張有効化名は§ 4.1.1 拡張の有効化に記載されていますが、一般的には識別子と同じ形式です:
拡張有効化名:
有効な言語拡張名は§ 4.1.2 言語拡張に記載されていますが、一般的には識別子と同じ形式です:
言語拡張名:
3.8.6. 補間型名
補間型名トークンは、補間型の名前に使われるトークンです。 interpolate_type_name用。
補間型名:
3.8.7. 補間サンプリング名
補間サンプリング名トークンは、補間サンプリングの名前に使われるトークンです。
補間サンプリング名:
3.8.8. スウィズル名
/[rgba]/
| /[rgba][rgba]/
| /[rgba][rgba][rgba]/
| /[rgba][rgba][rgba][rgba]/
| /[xyzw]/
| /[xyzw][xyzw]/
| /[xyzw][xyzw][xyzw]/
| /[xyzw][xyzw][xyzw][xyzw]/
3.9. テンプレートリスト
テンプレートパラメータ化は、一般的な概念を修飾するためのパラメータを指定する方法です。 テンプレートパラメータ化を書くには、一般概念の後にテンプレートリストを書きます。
テンプレートパラメータの形式は、下記のテンプレートリスト発見アルゴリズムで暗黙的に定義されます。 一般的には名前、式、または型です。
注:
例えば、vec3<f32>はテンプレートパラメータ化で、vec3が修飾される一般概念、
<f32>がテンプレートリスト(パラメータはf32型)。
vec3<f32>は具体的なベクトル型を表します。
注:
例えば、var<storage,read_write>は一般的なvar概念を、テンプレートパラメータstorageとread_writeで修飾します。
array<vec4<f32>>は2つのテンプレートパラメータ化を持ちます:
-
vec4<f32>は一般的なvec4概念をテンプレートパラメータf32で修飾します。 -
array<vec4<f32>>は一般的なarray概念をテンプレートパラメータvec4<f32>で修飾します。
テンプレートリストを区切る'<'(U+003C)と'>'(U+003E)コードポイントは、以下の場合にも使われます:
-
relational_expressionの比較演算子
-
shift_expressionのシフト演算子
-
compound_assignment_operatorによるシフト+代入演算
構文上の曖昧さはテンプレートリストを優先して解決されます:
-
後段のトークン化時、テンプレートリストの先頭
'<'(U+003C)は_template_args_startトークン、終端'>'(U+003E)は_template_args_endトークンに変換されます。
テンプレートリスト発見アルゴリズムは下記。 以下の前提・性質を使います:
-
テンプレートパラメータは式であり、
'<'(U+003C)や'='(U+003D)で始まらない。 -
式は
';'(U+003B)、'{'(U+007B)、':'(U+003A)を含まない。 -
式には代入文は含まれない。
-
'='(U+003D)が現れるのは比較演算('<=','>=','==','!=')の場合のみ。他は代入の一部。 -
テンプレートリスト区切りは括弧'(...)'や配列インデックス'[...]'による入れ子式に従い、開始・終了は同じ入れ子レベルで現れる。
アルゴリズム: テンプレートリスト発見入力: プログラムのソーステキスト。
レコード型:
UnclosedCandidateは以下を含むレコード型:
position:ソーステキスト上の位置
depth:positionでの式入れ子深度(整数)
TemplateListは以下を含むレコード型:
start_position:このテンプレートリストを開始する
'<'(U+003C)コードポイントのソース位置end_position:このテンプレートリストを終了する
'>'(U+003E)コードポイントのソース位置出力: DiscoveredTemplateLists(TemplateListレコードのリスト)
手順:
DiscoveredTemplateListsを空リストで初期化。
Pending変数をUnclosedCandidateレコードの空スタックで初期化。
CurrentPosition整数変数を0で初期化。 現在調べているコードポイントの位置を、ソーステキスト開始からのコードポイント数として表現。
この変数はアルゴリズム実行中に前方へ進み、テキスト終端に達したら即座にアルゴリズムを終了し、DiscoveredTemplateListsを返す。
NestingDepth整数変数を0で初期化。
以下を繰り返す:
ident_pattern_tokenがCurrentPositionのテキストにマッチした場合:
CurrentPositionをident_pattern_tokenの直後まで進める。
空白・コメントがあればCurrentPositionをさらに進める。
'<'(U+003C)がCurrentPositionに現れたら:
注: このコードポイントはテンプレートリスト開始の候補。 後で終端
'>'(U+003E)と対応付けできるよう状態を保存。UnclosedCandidate(position=CurrentPosition,depth=NestingDepth) をPendingスタックに積む。
CurrentPositionを次のコードポイントに進める。
'<'(U+003C)がCurrentPositionに現れたら:
注: 前提1より、いかなるテンプレートパラメータも
'<'(U+003C)で始まらないので、直前のコードポイントはテンプレートリスト開始ではない。 よって現在・前のコードポイントは'<<'演算子。Pendingスタックからトップをpop。
CurrentPositionを進めて次のループへ。
'='(U+003D)がCurrentPositionに現れたら:
注: 前提1より、いかなるテンプレートパラメータも
'='(U+003C)で始まらないので、直前のコードポイントはテンプレートリスト開始ではない。 よって現在・前のコードポイントは'<='比較演算子。'='(U+003D)を後の代入と誤認しないようスキップ。Pendingスタックからトップをpop。
CurrentPositionを進めて次のループへ。
次のループへ。
'>'(U+003E)がCurrentPositionに現れたら:
注: このコードポイントはテンプレートリスト終端の候補。
Pendingが空でなければトップTを取得し、T.depthがNestingDepthと等しければ:
注: このコードポイントはT記録のテンプレートリストの終端。
TemplateList(start_position=T.position, end_position=CurrentPosition)をDiscoveredTemplateListsに追加。
PendingスタックからTをpop。
CurrentPositionを進めて次のループへ。
それ以外の場合、このコードポイントはテンプレートリスト終端ではない:
CurrentPositionを進める。
'='(U+003D)がCurrentPositionに現れたら:
注: 現在・前のコードポイントは
'>='比較演算子。'='(U+003D)を後の代入と誤認しないようスキップ。CurrentPositionを進める。
次のループへ。
'('(U+0028)または'['(U+005B)がCurrentPositionに現れたら:
注: 入れ子式の開始。
NestingDepthに1加算。
CurrentPositionを進めて次のループへ。
')'(U+0029)または']'(U+005D)がCurrentPositionに現れたら:
注: 入れ子式の終了。
Pendingスタックから、空になるかトップのdepthがNestingDepthより小さいものになるまでpop。
NestingDepthを0またはNestingDepth−1のいずれか大きい方に設定。
CurrentPositionを進めて次のループへ。
'!'(U+0021)がCurrentPositionに現れたら:
CurrentPositionを進める。
'='(U+003D)がCurrentPositionに現れたら:
注: 現在・前のコードポイントは
'!='比較演算子。'='(U+003D)を後の代入と誤認しないようスキップ。CurrentPositionを進める。
次のループへ。
'='(U+003D)がCurrentPositionに現れたら:
CurrentPositionを進める。
'='(U+003D)がCurrentPositionに現れたら:
注: 現在・前のコードポイントは
'=='比較演算子。'='(U+003D)を後の代入と誤認しないようスキップ。CurrentPositionを進めて次のループへ。
注: これは代入の一部で、式中やテンプレートリスト中では現れない。 未閉候補をクリア。
NestingDepthを0に設定。
Pendingスタックを空に。
CurrentPositionを進めて次のループへ。
';'(U+003B)、'{'(U+007B)、':'(U+003A)がCurrentPositionに現れたら:
注: これらは式中やテンプレートリスト中では現れない。未閉候補をクリア。
NestingDepthを0に設定。
Pendingスタックを空に。
CurrentPositionを進めて次のループへ。
'&&'または'||'がCurrentPositionのテキストにマッチした場合:
注: これらは比較より優先度の低い演算子。現在の式レベルの未閉候補を破棄。
注: この規則により、
a<b || c>dのような断片にテンプレートリストは見つからず、2つの比較の短絡ORと認識される。Pendingスタックから、空になるかトップのdepthがNestingDepthより小さいものになるまでpop。
2コードポイント分CurrentPositionを進めて次のループへ。
現在のコードポイント分CurrentPositionを進める。
-
UnclosedCandidateを以下のフィールド追加で修正:
-
parameters:テンプレートパラメータのソース範囲のリスト
-
parameter_start_position:ソース位置
-
-
TemplateListを以下のフィールド追加で修正:
-
parameters:テンプレートパラメータのソース範囲のリスト
-
-
UnclosedCandidateを新たにPendingスタックに積むとき:
-
parametersフィールドは空リストにする
-
parameter_start_positionはCurrentPositionの1コードポイント後に設定
-
-
TemplateList(TL)をDiscoveredTemplateListsに追加するとき:
-
TをPendingスタックのトップに
-
開始位置T.parameter_start_positionから終了位置CurrentPosition−1までの範囲をT.parametersに追加
-
元のアルゴリズム通りにTL準備
-
TL.parametersにT.parametersを設定
-
-
ループ終端直前(現在コードポイント進める前)に次のチェック追加:
-
'
,'(U+002C)がCurrentPositionに現れ、かつPendingが空でなければ:-
TをPendingスタックのトップに
-
開始位置T.parameter_start_positionから終了位置CurrentPosition−1までの範囲をT.parametersに追加
-
T.parameter_start_positionをCurrentPosition+1に設定
-
-
注:
アルゴリズムはリテラルを明示的にスキップします。なぜなら数値リテラルの末尾に文字が来る場合があり、例えば1.0fの末尾fをident_pattern_tokenの開始と誤認しないようにするためです。
注:
A ( B < C, D > ( E ) )のような語では、< C, D >がテンプレートリストです。
注:
アルゴリズムは式の入れ子を尊重します。特定のテンプレートリストの開始と終了が異なる入れ子レベルで現れることはありません。
例えばarray<i32,select(2,3,a>b)>では、テンプレートリストは3つのパラメータを持ち、最後はselect(2,3,a>b)です。
a>bの'>'はテンプレートリスト終端にはならず、select関数呼び出し式の括弧内に囲まれているからです。
注: テンプレートリストの両端は同じインデックス式内で現れる必要があります。例えばa[b<d]>()は有効なテンプレートリストを含みません。
注:
A<B<<C>では、B<<CはB+左シフト演算子'<<'+Cです。
テンプレート発見アルゴリズムはB→'<'(U+003C)と見て、次も'<'(U+003C)なのでテンプレート引数開始とせず、
B直後の'<'はテンプレートリスト開始ではありません。
最初の'<'と最後の'>'のみがテンプレートリスト区切りで、パラメータはB<<Cです。
注:
A<B<=C>も同様に、B<=CはB+小なりイコール演算子'<='+Cです。
テンプレート発見アルゴリズムはB→'<'(U+003C)→'='(U+003D)と見て、'='はテンプレート引数開始にならないので、B直後の'<'はテンプレートリスト開始ではありません。
最初の'<'と最後の'>'のみがテンプレートリスト区切りで、パラメータはB<=Cです。
注:
A<(B>=C)>では、最初の'<'(U+003C)から最後の'>'(U+003E)までがテンプレートリストで、引数はB>=Cです。
B後の'>'(U+003C)コードポイント(誤記?)の後、'='(U+003D)は代入と誤認しないよう特別扱いします。
注:
A<(B!=C)>では、最初の'<'(U+003C)から最後の'>'(U+003E)までがテンプレートリストで、引数はB!=Cです。
B後の'!'(U+0021)コードポイントの後、'='(U+003D)は代入と誤認しないよう特別扱いします。
注:
A<(B==C)>では、最初の'<'(U+003C)から最後の'>'(U+003E)までがテンプレートリストで、引数はB==Cです。
B後の最初の'='(U+003D)コードポイント、次の'='(U+003D)コードポイントもどちらも代入と誤認しないよう特別扱いします。
テンプレートリスト発見完了後、 構文解析は各テンプレートリストをtemplate_list構文規則にマッチさせます。
_template_args_start template_arg_comma_list _template_args_end
template_arg_expression ( ',' template_arg_expression ) * ',' ?
4. ディレクティブ
ディレクティブは、WGSLプログラムの処理方法をWebGPU実装に変更させるトークン列です。
ディレクティブは省略可能です。 指定されている場合は、すべてのディレクティブが宣言やconstアサーションよりも前に現れる必要があります。
4.1. 拡張
WGSLは今後も進化することが期待されています。
拡張は、WGSL仕様の一貫性のある変更をまとめた名前付きグループであり、以下の任意の組み合わせで構成されます:
-
新しい構文による新しい概念や動作の追加、例:
-
宣言、文、属性、組み込み関数など。
-
-
現行標準や既存拡張での制限の除去。
-
許容される動作の範囲を減らすための構文。
-
プログラムの一部で利用可能な機能を制限するための構文。
-
拡張が既存仕様および他の拡張とどのように相互作用するかの説明。
仮に拡張は以下のようなことが可能です:
-
異なるビット幅の整数などの数値スカラー型の追加。
-
浮動小数点の丸めモードを制約する構文の追加。
-
シェーダーがアトミック型を使用しないことを示す構文の追加。
-
新しい種類の文を追加。
-
新しい組み込み関数を追加。
-
シェーダー呼び出しの実行方法を制約する構文の追加。
-
新しいシェーダーステージの追加。
4.1.1. 有効化拡張
有効化拡張は、以下の条件を満たす場合のみ利用可能な拡張です:
-
実装がそれをサポートしていること
-
シェーダーがenableディレクティブで明示的に要求していること
-
対応するWebGPU
GPUFeatureNameがGPUDevice作成時に要求された必須機能のひとつであること
Enable-extensions は、 普遍的にサポートされているわけではないハードウェア機能を公開することを意図しています。
enableディレクティブは、ひとつ以上の有効化拡張を有効にするディレクティブです。 実装が全ての指定された有効化拡張をサポートしていない場合、シェーダー生成エラーとなります。
'enable' enable_extension_list ';'
他のディレクティブ同様、enableディレクティブが存在する場合は、すべての宣言やconstアサーションよりも前に現れる必要があります。 拡張名は識別子ではありません。 宣言に解決されません。
有効な有効化拡張は次の表に示されています。
| WGSL有効化拡張 | WebGPU GPUFeatureName
| 説明 |
|---|---|---|
f16
| "shader-f16" | f16型がWGSLモジュールで利用可能になります。それ以外の場合、f16(直接または間接的に)を使用するとシェーダー生成エラーとなります。 |
clip_distances
| "clip-distances" | 組み込み変数clip_distancesがWGSLモジュールで利用可能になります。それ以外の場合、clip_distancesを使用するとシェーダー生成エラーとなります。 |
dual_source_blending
| "dual-source-blending" | 属性blend_srcがWGSLモジュールで利用可能になります。それ以外の場合、blend_srcを使用するとシェーダー生成エラーとなります。 |
subgroups
| "subgroups" | サブグループ組み込み変数、サブグループ組み込み関数、quad組み込み関数をWGSLモジュールで利用可能です。 それ以外の場合、いずれかを使用するとシェーダー生成エラーとなります。 |
primitive_index
| "primitive-index"
| 組み込み変数primitive_indexがWGSLモジュールで利用可能になります。それ以外の場合、primitive_indexを使用するとシェーダー生成エラーとなります。 |
subgroup_size_control
| "subgroup-size-control"
| 属性 subgroup_size は WGSL モジュール内で使用するのに有効である。 そうでない場合、subgroup_size を使用すると shader-creation error が発生する。 Must は subgroups 拡張とともに有効化されなければならない。 そうでない場合、subgroup_size_control を有効化すると shader-creation error が発生する。 |
// 任意精度浮動小数点型の仮想拡張を有効化 enable arbitrary_precision_float ; enable arbitrary_precision_float ; // 冗長なenableディレクティブも許容されます。 // 丸めモード制御用の仮想拡張を有効化 enable rounding_mode ; // 仮にarbitrary_precision_float拡張により以下が利用可能になる: // - 型f<E,M> // - 関数の戻り値、仮引数、let宣言の型として // - AbstractFloatからの値コンストラクター // - 除算演算子: / のオペランドとして // 仮にrounding_mode拡張で@rounding_mode属性が利用可能になる。 @rounding_mode ( round_to_even ) fn halve_it ( x : f < 8 , 7 > ) -> f < 8 , 7 > { let two = f < 8 , 7 > ( 2 ); return x / 2 ; // 偶数丸めモードで演算される。 }
4.1.2. 言語拡張
言語拡張 は、実装がサポートしている場合に自動的に利用可能となる拡張です。 プログラムが明示的に要求する必要はありません。
言語拡張 は、どの WebGPU 実装でも合理的にサポートできる機能を具現化します。 その機能が普遍的にサポートされていない場合、それは一部の WebGPU 実装がまだ それを実装していないためです。
注: 例えば、do-whileループは言語拡張となり得ます。
wgslLanguageFeatures
メンバーはWebGPU GPU
オブジェクトにおいて、
実装がサポートする言語拡張のセットを一覧します。
requiresディレクティブ は、プログラムが利用する言語拡張を記述するディレクティブです。 実装が提供する機能を変更するものではありません。 実装が必要とされる拡張のいずれかをサポートしていない場合、シェーダー生成エラーとなります。
WGSLモジュールはrequiresディレクティブを使って、非移植性の可能性や、 意図した移植性の最低限の基準を示すことができます。
注: WebGPU実装外のツールは、プログラムで利用されるすべての言語拡張がプログラム内のrequiresディレクティブで網羅されているか確認できます。
'requires' language_extension_list ';'
language_extension_name ( ',' language_extension_name ) * ',' ?
他のディレクティブ同様、requiresディレクティブが存在する場合は、すべての宣言やconstアサーションよりも前に現れる必要があります。 拡張名は識別子ではありません。 宣言に解決されません。
| WGSL 言語拡張 | 説明 |
|---|---|
| readonly_and_readwrite_storage_textures | read および read_write アクセスモードを storage texture とともに使用できるようにする。 さらに、textureBarrier 組み込み関数を追加する。 |
| packed_4x8_integer_dot_product | 4 成分の 8 ビット整数ベクトルをパックした 32 ビット整数スカラーを入力として、 dot4U8Packed および dot4I8Packed 組み込み関数によるドット積命令で 使用することをサポートする。 さらに、pack4xI8、pack4xU8、 pack4xI8Clamp、pack4xU8Clamp、 unpack4xI8、および unpack4xU8 組み込み関数により、4 成分の 8 ビット整数ベクトルをパックおよびアンパックする命令を追加する。 |
| unrestricted_pointer_parameters |
制限を ユーザー定義関数から取り除く:
ユーザー定義関数では、ポインター型のパラメーターは 次のいずれかのアドレス空間になければ ならない: ユーザー定義関数へのポインター型の各引数は、 その root identifier と同じ memory view を持た なければならない。 |
| pointer_composite_access |
根式がポインターである 複合値分解式をサポートし、
参照を生成する。
たとえば、 同様に、 |
| uniform_buffer_standard_layout | uniform アドレス空間のバッファーが、 他のアドレス空間と同じ メモリレイアウト制約を 使用できるようにする。 |
| subgroup_id | subgroups 拡張が有効化されているとき、subgroup_id および num_subgroups 組み込み値の使用を可能にする。 |
| subgroup_uniformity |
一様制御フローに追加のスコープ subgroup を追加し、
subgroup および
quad 組み込み関数が同じ
subgroup 内の
すべての呼び出しを対象とするようにする。
注: subgroup および quad 組み込み関数を使用するには、 subgroups 拡張を有効化する必要がある。 |
| texture_and_sampler_let | let 宣言の effective-value-type が texture 型または sampler 型であることを可能にする。 |
| texture_formats_tier1 | 追加の texel format をサポートする: rgba16unorm、rgba16snorm、rg8unorm、 rg8snorm、rg8uint、rg8sint、 rg16unorm、rg16snorm、rg16uint、 rg16sint、rg16float、r8unorm、 r8snorm、r8uint、r8sint、 r16unorm、r16snorm、r16uint、 r16sint、r16float、rgb10a2unorm、 rgb10a2uint、rg11b10ufloat |
| linear_indexing | global_invocation_index および workgroup_index 組み込み値をサポートする。 |
| immediate_address_space |
immediate アドレス空間を有効化し、
変数を var<immediate> として宣言して、WebGPU API を介してコマンドエンコーダーから直接渡される、
頻繁に更新される少量のデータにバインドできるようにする。
|
注: 将来的には、WGSLは現時点で広くサポートされている言語拡張の機能すべてを含める言語拡張を定義する意図があります。 requiresディレクティブにおいて、これらは全ての共通機能をリストアップするための略記となります。 機能の集合は徐々に増加し、ある種の言語バージョンと考えることもできます。
4.2. グローバル診断フィルター
グローバル診断フィルターは、影響範囲がWGSLモジュール全体となる診断フィルターです。
これはディレクティブであり、すべてのモジュールスコープ宣言よりも前に現れます。
属性形式と同じスペルですが、先頭の@(U+0040)コードポイントがなく、末尾にセミコロンが付きます。
'diagnostic' diagnostic_control ';'
5. 宣言とスコープ
A 宣言は、 識別子を次の種類のオブジェクトのいずれかに関連付ける:
言い換えると、宣言はオブジェクトのための名前を導入する。
宣言がプログラムソース内に現れ、かつ他のどの宣言のテキストの外側にも現れる場合、その宣言はモジュール スコープにある。
関数宣言は モジュールスコープに現れる。 関数宣言は、もしあれば仮パラメーターの宣言を含み、 またその本体内に変数および値の宣言を含むことができる。 したがって、それらの含まれる宣言はモジュールスコープにはない。
注: 他の宣言を含む唯一の種類の宣言は関数宣言である。
特定のオブジェクトは WebGPU 実装によって提供され、 WGSL モジュールソースの開始前に宣言済みであるかのように扱われる。 そのようなオブジェクトは事前宣言済みであるという。 たとえば、WGSL は次を事前宣言する:
-
array、ptr、 およびtexture_2dなどの組み込み型生成子、ならびに -
read_write、 workgroup、および rgba8unorm などの列挙子。
宣言のスコープとは、 宣言された識別子がその関連付けられたオブジェクトを表し得る プログラムソース位置の集合である。 識別子がそれらのソース位置において(宣言の)スコープ内にあるという。
宣言が現れる場所により、そのスコープが決まる:
-
事前宣言済みオブジェクト、およびモジュールスコープで宣言されたオブジェクトは、プログラムソース全体にわたってスコープ内にある。
-
ユーザー宣言関数の各仮 パラメーターは、対応する関数本体全体にわたってスコープ内にある。 § 11.1 ユーザー定義関数の宣言を参照。
-
それ以外の場合、スコープは宣言の終端の直後から始まるテキスト範囲である。 詳細は§ 7 変数および値の宣言を参照。
同じ WGSL ソースプログラム内の 2 つの宣言は、同時に次を満たしてはならない:
-
同じ識別子名を導入すること、および
-
同じスコープ終端を持つこと。
注: 事前宣言済みオブジェクトは WGSL ソース内に宣言を持たない。 したがって、モジュールスコープまたは関数内のユーザー指定の宣言は、事前宣言済み オブジェクトと同じ名前を持つことができる。
識別子は、文法上の文脈で区別され、次のように使用される:
-
ident 文法要素に一致するトークンは、次のいずれかである:
-
宣言内で、宣言されるオブジェクトの名前として使用される、または
-
名前として使用され、別の場所で宣言されたオブジェクトを表す。これは一般的な場合である。
-
-
member_ident 文法要素に一致するトークンは、次のいずれかである:
-
名前として使用され、構造体値のメンバーを表すか、構造体のメンバーへの参照を表す。 § 8.5.4 構造体アクセス式を参照。
ident トークンが、 別の場所で宣言されたオブジェクトを表す名前として現れる場合、 それは何らかの宣言についてスコープ内になければならない。 識別子トークンが表すオブジェクトは次のように決定される:
-
そのトークンが 1 つ以上の非モジュールスコープ宣言についてスコープ内にある場合、 そのトークンは、それらの宣言のうち最も近いものに関連付けられたオブジェクトを表す。
注: そのような最も近い宣言は 識別子トークンより前に現れる。
-
そうでなく、その名前を持つモジュールスコープ宣言がある場合、そのトークンは その宣言されたオブジェクトを表す。
注: モジュールスコープ宣言は、 識別子トークンより前または後に現れてよい。
-
そうでなく、その名前を持つ事前宣言済みオブジェクトがある場合、そのトークンはその オブジェクトを表す。
上記のアルゴリズムを使用して識別子を宣言に対応付けるとき、その識別子はその宣言へ解決されるという。 同様に、その識別子が宣言されたオブジェクトへ解決されるともいう。
モジュールスコープ宣言が再帰的である場合、それはshader-creation errorである。 つまり、宣言間に循環が存在してはならない:
次の有向グラフを考える:
各ノードは宣言 D に対応する。
宣言 D の定義が、T へ解決される識別子に言及している場合、 宣言 D から宣言 T への辺が存在する。
このグラフは循環を持ってはならない。
注: 関数本体は関数宣言の一部であるため、 関数も直接または間接的に再帰的であってはならない。
注: 非モジュールスコープの識別子宣言は、テキスト内でその使用より前に現れなければならない。
// 有効。ユーザー定義変数は組み込み関数と同じ名前を持つことができる。 var < private> modf : f32= 0.0 ; // 有効。foo_1 はプログラム全体でスコープ内にある。 var < private> foo : f32= 0.0 ; // foo_1 // 有効。bar_1 はプログラム全体でスコープ内にある。 var < private> bar : u32= 0u ; // bar_1 // 有効。my_func_1 はプログラム全体でスコープ内にある。 // 有効。foo_2 は関数の終端までスコープ内にある。 fn my_func ( foo : f32) { // my_func_1, foo_2 // 'foo' への任意の参照は関数パラメーターへ解決される。 // 無効。modf はモジュールスコープ変数へ解決される。 let res = modf ( foo ); // 無効。foo_2 のスコープは関数の終端で終了する。 var foo : f32; // foo_3 // 有効。bar_2 は関数の終端までスコープ内にある。 var bar : u32; // bar_2 // 'bar' への参照は bar_2 へ解決される { // 有効。foo_4 は複合文の終端までスコープ内にある。 var foo : f32; // foo_4 // 有効。bar_3 は複合文の終端までスコープ内にある。 var bar : u32; // bar_3 // 'bar' への参照は bar_3 へ解決される // 無効。bar_4 は bar_3 と同じスコープ終端を持つ。 var bar : i32; // bar_4 // 有効。i_1 は for ループの終端までスコープ内にある for ( var i : i32= 0 ; i < 10 ; i ++ ) { // i_1 // 無効。i_2 は i_1 と同じスコープ終端を持つ。 var i : i32= 1 ; // i_2. } } // 無効。bar_5 は bar_2 と同じスコープ終端を持つ。 var bar : u32; // bar_5 // 有効。モジュールスコープ宣言 later_def はプログラム全体でスコープ内にある。 var early_use : i32= later_def ; } // 無効。bar_6 は bar_1 と同じスコープを持つ。 var < private> bar : u32= 1u ; // bar_6 // 無効。my_func_2 は my_func_1 と同じスコープ終端を持つ。 fn my_func () { } // my_func_2 // 有効。my_foo_1 はプログラム全体でスコープ内にある。 fn my_foo ( //my_foo_1 // 有効。my_foo_2 は関数の終端までスコープ内にある。 my_foo : i32// my_foo_2 ) { } var < private> later_def : i32= 1 ;
// この宣言は、事前宣言済みの 'min' 組み込み関数を隠す。 // この宣言はモジュールスコープにあるため、ソース全体でスコープ内にある。 // 組み込み関数にはもはやアクセスできない。 fn min () -> u32{ return 0 ; } const rgba8unorm= 12 ; // これは事前宣言済みの 'rgba8unorm' 列挙子をシャドーイングする。
6. 型
プログラムは値を計算します。
WGSLにおいて、型とは値の集合であり、各値は正確に1つの型に属します。 値の型は、その値に対して行える操作の構文と意味を決定します。
例えば、数学的な数値1はWGSLでは以下の異なる値に対応します:
-
32ビット符号付き整数値
1i -
32ビット符号なし整数値
1u -
32ビット浮動小数点値
1.0f -
(f16拡張が有効な場合)16ビット浮動小数点値
1.0h -
AbstractInt値 1
-
AbstractFloat値 1.0
WGSLはこれらを区別します。なぜなら機械表現や操作が異なるためです。
一部の型は不透明であり、これは その値が実装定義の表現を持ち、 WGSL プログラム内で直接検査、分解、または操作できないことを意味します。
型は事前宣言されているか、WGSLソース内で宣言によって作成されます。
一部の型はテンプレートパラメータ化で表現されます。
型ジェネレーターとは、事前宣言されたオブジェクトで、テンプレートリストでパラメータ化されることで型を示します。
例えば、型atomic<u32>は型ジェネレーターatomicとテンプレートリスト<u32>を組み合わせたものです。
型の概念とWGSLでその型を示す構文は区別されます。 多くの場合、この仕様における型の綴りはWGSL構文と同じです。 例えば:
-
32ビット符号なし整数値の集合は、この仕様でもWGSLモジュールでも
u32と綴ります。 -
構造体型や構造体を含む型の場合は綴りが異なります。
一部のWGSL型は、ソースプログラムの解析や実行時挙動の決定にのみ使われます。 この仕様ではそのような型も説明しますが、WGSLソーステキストには現れません。
注: 参照型はWGSLモジュールに記述されません。§ 6.4.3 参照型とポインター型を参照してください。
6.1. 型検査
WGSL値は式の評価によって算出されます。
式とは、WGSL文法規則のうち「expression」で終わる名前を持つものとして解析されるソーステキストの区間です。
式Eは、外側の式Eに真に内包された式である部分式を含むことがあります。
トップレベル式は、それ自身が部分式でない式です。
§ 8.18 式文法のまとめを参照。
式の評価で生成される値は次に依存します:
-
静的コンテキスト:式を囲むソーステキスト
-
動的コンテキスト:式を評価している呼び出しの状態や実行コンテキスト
特定の式を評価した結果得られる値は必ず特定のWGSL型に属します。 これはその式の静的型と呼ばれます。 WGSLの規則は、式の静的型がその式の静的コンテキストのみに依存するよう設計されています。
型アサーションは、WGSLソース式とWGSL型の対応付けです。 次の記法
e : T
は「eの静的型がTである」という型アサーションです。
注: 型アサーションはプログラムテキストについての事実の記述です。実行時検査ではありません。
文はしばしば式を用い、その式の静的型に要件を課す場合があります。例:
正常に構文解析された WGSL モジュールを型検査することは、 各式をその静的型に対応付け、 各文の型要件が満たされていることを検証する処理である。 型検査が失敗した場合、shader-creation error の特殊な場合である、型エラーが発生する。
型検査は、型規則を構文句に再帰的に適用することで実行できる。 ここで、構文句は、式または文のいずれかである。 型規則は、 構文句の静的文脈が、 その句に含まれる式の静的型をどのように決定するかを記述する。 型規則は 2 つの部分を持つ:
-
結論
-
前提条件(以下を含む):
-
式の場合:
-
部分式があれば、その部分式の型アサーション。 これは直接満たしてもよいし、実現可能な自動変換によって満たしてもよい(§ 6.1.2 変換ランク参照)。 WGSLは定数式をすべて評価し、プログラムの静的型を決定します。
-
その式が文でどのように使われるか。
-
-
文の場合:
-
文の構文形式、および
-
文中のトップレベル式の型アサーション。
-
-
その他の模式パラメータに対する条件(もしあれば)。
-
オプションでその他の静的コンテキスト。
-
型規則は、前提条件や結論に型パラメータを持つことがあります。 型規則の結論や前提条件に型パラメータが含まれる場合、その規則はパラメータ化されているといいます。 含まれない場合は完全展開されているといいます。 パラメータ化された型規則に対し、各型パラメータに型を代入することで完全展開された型規則を作ることができます。 規則の型パラメータへの型の割り当てを代入と呼びます。
例えば、論理否定(!e形式の式)の型規則は次のとおりです:
| 前提条件 | 結論 |
|---|---|
| e: T TはboolまたはvecN<bool> | !e: T
|
これは型パラメータTを含むためパラメータ化された規則です。
Tは4つの型、bool、vec2<bool>、vec3<bool>、vec4<bool>のいずれかになり得ます。
例えばTにvec3<bool>を割り当てると、完全展開された型規則は次のようになります:
| 前提条件 | 結論 |
|---|---|
e: vec3<bool> | !e: vec3<bool>
|
パラメータ化された規則に対し、条件を満たす代入によって得られる完全展開規則をそれぞれオーバーロードと呼びます。 例えば、この論理否定規則は型パラメータTの割り当て方法が4通りなので、オーバーロードは4つあります。
注: つまり、パラメータ化された型規則は、異なる代入によって生成される完全展開型規則の集合のパターンを提供します。
型規則が構文的フレーズに適用されるのは、次の場合です:
-
規則の結論が構文的フレーズの有効な構文解析に一致し、
-
規則の前提条件が満たされている
パラメータ化された型規則は、ある式に対し、 代入によって完全展開型規則を生成でき、 その型規則がその式に適用できる場合に適用されます。
例えば、式1u+2uを考えます。
これは2つのリテラル部分式(1uと2u、どちらもu32型)を持ちます。
トップレベル式は加算です。
§ 8.7 算術式の規則を参照すると、加算の型規則がこの式に適用されます。なぜなら:
-
1u+2uはe1+e2という形式にパースされ、e1が1u、e2が2uとなり、 -
e1はu32型であり、
-
e2もu32型であり、
-
型規則の型パラメータTにu32を代入できるので、式全体に適用できる完全展開規則が得られる
構文的フレーズを解析する際、以下の3つの場合があります:
-
どの型規則もその式に適用できない→型エラーとなる。
-
完全展開された型規則がちょうど1つだけその式に適用できる→その規則の結論が主張され、式の静的型が決定される。
-
複数の型規則が適用できる(複数のオーバーロードが前提条件を満たす)→§ 6.1.3 オーバーロード解決で競合解決を行う。
上記の例の通り、式1u+2uには型規則が一つだけ適用できるため、型検査はその型規則の結論(1u+2uがu32型)を受け入れます。
WGSLソースプログラムが型安全であるとは、次のときです:
-
全ての式について型規則を適用して静的型が決定でき、
-
すべての文の型要件が満たされている。
そうでない場合は型エラーとなり、そのソースプログラムはWGSLモジュールとして有効ではありません。
WGSLは静的型付け言語です。 なぜならWGSLモジュールの型検査は、プログラムソーステキストのみを調べて成功するか型エラーを発見するからです。
6.1.1. 型規則表
WGSLの式の型規則は、型規則表として整理されており、各行が1つの型規則を表します。
式の意味は、その式を評価したときの効果であり、主に結果値の生成です。 式に適用される型規則の説明列には、その式の意味が記載されます。 意味は通常、型規則パラメータの値や、部分式の想定値に依存します。 場合により、式の意味には結果値以外の効果(部分式の副作用など)が含まれることもあります。
fn foo ( p : ptr< function, i32> ) -> i32{ let x = * p ; * p += 1 ; return x ; } fn bar () { var a : i32; let x = foo ( & a ); // fooの呼び出しは値を返し、 // aの値を更新する }
6.1.2. 変換ランク
型アサーションe:Tが型規則の前提条件として使われる場合、次で満たされます:
-
eがすでに型Tである場合
-
eが型Sであり、型Sが型Tに自動変換可能な場合(以下定義)
この規則は、下表で定義される型の組に対するConversionRank関数で定式化されます。 ConversionRank関数は、一方の型(Src)からもう一方の型(Dest)への自動変換の優先度と実現可能性を表します。 ランクが低いほど望ましいです。
実現可能な自動変換は、型Srcから型Destへの値変換であり、 ConversionRank(Src,Dest)が有限の場合に許可されます。 これらの変換は値を保全しますが、詳細は§ 15.7 浮動小数点評価で説明される制限があります。
注: 自動変換は2つの場合のみ発生します。 1つ目は定数式をGPUで利用できる型付き数値値に変換する場合。 2つ目はメモリ参照からロードが発生し、そのメモリに格納された値が得られる場合です。
注: ランクが無限大の変換は実現不可能、つまり許可されません。
注: 変換を行わない場合、変換ランクは0です。
| Src | Dest | ConversionRank(Src,Dest) | 説明 |
|---|---|---|---|
| T | T | 0 | 恒等。変換は行われない。 |
| ref<AS,T,AM> アドレス空間 AS について、 かつ アクセスモード AM が read または read_write である場合。 | T | 0 | ロード規則を適用して、 メモリ参照から値をロードする。 |
| AbstractFloat | f32 | 1 | § 15.7.6 浮動小数点変換を参照 |
| AbstractFloat | f16 | 2 | § 15.7.6 浮動小数点変換を参照 |
| AbstractInt | i32 | 3 | 値が i32 内にある場合は恒等。 それ以外の場合は shader-creation error を生成する。 |
| AbstractInt | u32 | 4 | 値が u32 内にある場合は恒等。 それ以外の場合は shader-creation error を生成する。 |
| AbstractInt | AbstractFloat | 5 | § 15.7.6 浮動小数点変換を参照 |
| AbstractInt | f32 | 6 | AbstractInt から AbstractFloat、 そして AbstractFloat から f32 への変換として振る舞う |
| AbstractInt | f16 | 7 | AbstractInt から AbstractFloat、 そして AbstractFloat から f16 への変換として振る舞う |
| vecN<S> | vecN<T> | ConversionRank(S,T) | 成分型から変換ランクを継承する。 |
| matCxR<S> | matCxR<T> | ConversionRank(S,T) | 成分型から変換ランクを継承する。 |
| array<S,N> | array<T,N> | ConversionRank(S,T) | 成分型から変換ランクを継承する。 注: 固定サイズ配列のみが抽象成分型を持つことができる。 |
| __frexp_result_abstract | __frexp_result_f32 | 1 | |
| __frexp_result_abstract | __frexp_result_f16 | 2 | |
| __frexp_result_vecN_abstract | __frexp_result_vecN_f32 | 1 | |
| __frexp_result_vecN_abstract | __frexp_result_vecN_f16 | 2 | |
| __modf_result_abstract | __modf_result_f32 | 1 | |
| __modf_result_abstract | __modf_result_f16 | 2 | |
| __modf_result_vecN_abstract | __modf_result_vecN_f32 | 1 | |
| __modf_result_vecN_abstract | __modf_result_vecN_f16 | 2 | |
| S | T 上記の場合が適用されない場合 | infinity | 他の型の間には自動変換は存在しない。 |
型Tは型Sの具象化であるのは、次の場合です:
-
Tが具象型であり -
Tが参照型でない -
ConversionRank(
S,T)が有限である -
他の非参照型
T2について、ConversionRank(S,T2) > ConversionRank(S,T)
型Tの値eの具象化は、
TからTの具象化への実現可能な変換をeに適用した結果です。
注: f32 への変換は常に f16 より優先されるため、 自動変換によって f16 値が生成されるのは、 モジュールで f16 拡張 が有効な場合に限られます。
6.1.3. オーバーロード解決
複数の型規則が構文的フレーズに適用できる場合、 どれを適用するかを決定するための競合解決手順が用いられます。 この手順をオーバーロード解決と呼びます。 型検査によって部分式の静的型がすでに決定されていることを前提とします。
構文的フレーズPと、Pに適用できるすべての型規則を考えます。 オーバーロード解決アルゴリズムはこれらの型規則をオーバーロード候補と呼びます。 各候補について:
Pのオーバーロード解決は以下の手順で進み、最も望ましいオーバーロード候補を1つ見つけることを目的とします:
-
各候補Cについて、構文的フレーズ内の部分式ごとに変換ランクを列挙します。 候補の前提条件は満たされているため、P内のi番目の部分式について:
-
その静的型は計算済み。
-
その式の静的型から前提条件の型アサーションが要求する型への実現可能な自動変換が存在する。 C.R(i)をその変換のConversionRankとする。
-
-
部分式のいずれかが自動変換後に抽象型になるが、 その候補の他の部分式が定数式でない場合、その候補を除外する。
注: 結果として、フレーズ内のいずれかの部分式が定数式でない場合、フレーズ内のすべての部分式は具象型でなければなりません。
-
候補を順位付けする:2つのオーバーロード候補C1とC2について、C1が優先されるのは:
-
P内の各式位置iについて、C1.R(i) ≤ C2.R(i)
-
つまり、C1をPに適用するために必要な各式変換が、C2に必要な対応する式変換と同等以上に望ましい。
-
-
少なくとも1つの式位置iで、C1.R(i) < C2.R(i)
-
つまり、C1に必要な式変換のうち少なくとも1つは、C2に必要な対応する変換よりも厳密に望ましい。
-
-
-
他のすべてより優先される候補Cが1つだけあれば、オーバーロード解決は成功し、その型規則Cを返す。 そうでなければ、オーバーロード解決は失敗する。
6.2. プレーン型
プレーン型は、ブール値、数値、ベクトル、行列、またはそれらの値の集約の機械表現用の型です。
プレーン型は、スカラー型、アトミック型、 または合成型のいずれかです。
注: WGSLのプレーン型はC++のPlain-Old-Data型に似ていますが、 アトミック型や抽象数値型も含みます。
6.2.1. 抽象数値型
これらの型は WGSL ソース内で記述できない。これらは型検査でのみ使用される。
特定の式はshader-creation timeに評価され、 GPU によって直接実装されるものよりも大きい数値範囲と精度で評価されることがある。
WGSL は、これらの評価のために 2 つの抽象数値型を定義する:
-
AbstractInt 型は、最上位ビット位置に符号ビットを持つ 64 ビット 2 の補数形式で 表現可能な整数の集合である。
-
AbstractFloat 型は、IEEE-754 binary64(倍精度)形式で 表現可能な有限浮動小数点数の集合である。
これらの型のいずれかで式を評価するとき、オーバーフローしたり、無限大または NaN 値を生成してはならない。
型が抽象数値型であるか、または抽象数値型を含む場合、その型は抽象である。 型が抽象でない場合、その型は具象である。
-
iまたはu接尾辞のない整数リテラルは、 AbstractInt 値を表す。 -
fまたはh接尾辞のない浮動小数点リテラルは、AbstractFloat 値を表す。
例: 式 log2(32) は次のように解析される:
-
log2(32)は、オペランド AbstractInt 値 32 を持つlog2組み込み関数への関数呼び出しとして構文解析される。 -
log2には、整数スカラー仮パラメーターを持つオーバーロードは存在しない。 -
代わりにオーバーロード 解決が適用され、3 つの可能なオーバーロードと実行可能な 自動変換が考慮される:
-
AbstractInt から AbstractFloat へ。(変換ランク 4)
-
AbstractInt から f32 へ。(変換ランク 5)
-
AbstractInt から f16 へ。(変換ランク 6)
-
-
結果として得られる計算は AbstractFloat として行われる(例:
log2(32.0))。
例: 式 1 + 2.5 は次のように解析される:
-
1 + 2.5は、部分式 AbstractInt 値 1 と、AbstractFloat 値 2.5 を持つ加算演算として構文解析される。 -
e が整数型で f が浮動小数点である場合の e+f に対するオーバーロードは存在しない。
-
しかし、実行可能な自動変換を使用すると、3 つの潜在的なオーバーロードがある:
-
1は AbstractFloat 値1.0に変換され(ランク 4)、2.5は AbstractFloat のままである(ランク 0)。
-
-
最初のオーバーロードが優先候補であり、型検査は成功する。
-
結果として得られる計算は AbstractFloat
1.0 + 2.5として行われる。
例: let x = 1 + 2.5;
-
この例は上記と似ているが、
xは抽象数値型へ解決できない点が異なる。 -
この宣言の効果は、
let x : f32 = 1.0f + 2.5f;と書かれている場合と同じである。
例: 1u + 2.5 は shader-creation error になる:
-
1u項は型 u32 の式である。 -
2.5項は型 AbstractFloat の式である。 -
有効なオーバーロード候補は存在しない:
例: -1 * i32(-2147483648) は shader-creation error にならない:
-
-1項は型 AbstractInt の式である。 -
i32(-2147483648)項は型 i32 の式である。 -
これら 2 つの型に対する乗算演算子のオーバーロードはなく、i32 項は AbstractInt へアップコンバートできない。
-
唯一の実行可能な自動変換は、AbstractInt を i32 に変換することである。したがって:
// 明示的に型付けされた符号なし整数リテラル。 var u32_1 = 1u ; // 変数は u32 を保持する // 明示的に型付けされた符号付き整数リテラル。 var i32_1 = 1i ; // 変数は i32 を保持する // 明示的に型付けされた浮動小数点リテラル。 var f32_1 = 1f ; // 変数は f32 を保持する // 明示的に型付けされた符号なし整数リテラルは否定できない。 var u32_neg = - 1u ; // 無効: 単項マイナスは u32 をサポートしない // 具象型が必要だが、文または式のどの部分も // 特定の具象型を強制しない場合、整数リテラルは // i32 値として解釈される: // let 宣言の初期化子は構築可能(またはポインター)でなければならない。 // AbstractInt から構築可能型への最も優先される自動変換は // 変換ランク 2 の AbstractInt から i32 である。したがって '1' は i32 と推論される。 let some_i32 = 1 ; // let some_i32: i32 = 1i; と同様 // 宣言型から推論される。 var i32_from_type : i32= 1 ; // 変数は i32 を保持する。AbstractInt から i32、変換ランク 2 var u32_from_type : u32= 1 ; // 変数は u32 を保持する。AbstractInt から u32、変換ランク 3 // 接尾辞のない整数リテラルは、必要な場合に浮動小数点へ変換できる: // AbstractInt を f32 へ自動変換する。変換ランクは 5。 var f32_promotion : f32= 1 ; // 変数は f32 を保持する // 無効: 浮動小数点から整数への実行可能な変換はない var i32_demotion : i32= 1.0 ; // 無効 // 式から推論される。 var u32_from_expr = 1 + u32_1 ; // 変数は u32 を保持する var i32_from_expr = 1 + i32_1 ; // 変数は i32 を保持する // 値は表現可能でなければならない。 let u32_too_large : u32= 1234567890123456890 ; // 無効、オーバーフロー let i32_too_large : i32= 1234567890123456890 ; // 無効、オーバーフロー let u32_large : u32= 2147483649 ; // 有効 let i32_large : i32= 2147483649 ; // 無効、オーバーフロー let f32_out_of_range1 = 0x1p500 ; // 無効、範囲外 let f32_hex_lost_bits = 0x1.0000000001p0 ; // 無効、f32 で正確に表現できない // 最小整数: AbstractInt 上の単項否定、その後 i32 と推論。 // AbstractInt から構築可能型への最も優先される変換(最小の // 変換ランクを持つ)は AbstractInt から i32 である。 let i32_min = - 2147483648 ; // 型は i32 // 無効。上記のように AbstractInt から i32 が選択されるが、値が // 範囲外であり、shader-creation error を生成する。 let i32_too_large_2 = 2147483648 ; // 無効。 // 部分式は AbstractInt および AbstractFloat へ解決できる。 // 次の例はすべて有効であり、変数の値は 6u である。 var u32_expr1 = ( 1 + ( 1 + ( 1 + ( 1 + 1 )))) + 1u ; var u32_expr2 = 1u + ( 1 + ( 1 + ( 1 + ( 1 + 1 )))); var u32_expr3 = ( 1 + ( 1 + ( 1 + ( 1u + 1 )))) + 1 ; var u32_expr4 = 1 + ( 1 + ( 1 + ( 1 + ( 1u + 1 )))); // 組み込み関数パラメーターに基づく推論。 // 最も優先される候補は clamp(i32,i32,i32)->i32 let i32_clamp = clamp ( 1 , - 5 , 5 ); // 最も優先される候補は clamp(u32,u32,u32) である。 // リテラルは AbstractInt から u32 への自動変換を使用する。 let u32_clamp = clamp ( 5 , 0 , u32_from_expr ); // 最も優先される候補は clamp(f32,f32,f32)->f32 // リテラルは AbstractInt から f32 への自動変換を使用する。 let f32_clamp = clamp ( 0 , f32_1 , 1 ); // 次の例はすべて、初期値 10f で f32 へ昇格する。 let f32_promotion1 = 1.0 + 2 + 3 + 4 ; let f32_promotion2 = 2 + 1.0 + 3 + 4 ; let f32_promotion3 = 1f + (( 2 + 3 ) + 4 ); let f32_promotion4 = (( 2 + ( 3 + 1f )) + 4 ); // 型規則違反。 // 無効。初期化子は f32 にのみ解決できる: // AbstractFloat から u32 への実行可能な自動変換はない。 let mismatch : u32= 1.0 ; // 無効。符号が混在したパラメーターを許可する clamp のオーバーロードは存在しない。 let ambiguous_clamp = clamp ( 1u , 0 , 1i ); // 推論は文レベルで完了する。 // let 宣言の初期化子は構築可能(またはポインター)でなければならない。 // AbstractInt から構築可能型への最も優先される自動変換は // 変換ランク 2 の AbstractInt から i32 である。したがって '1' は i32 と推論される。 let some_i32 = 1 ; // let some_i32: i32 = 1i; と同様 let some_f32 : f32= some_i32 ; // 型エラー: i32 は f32 に代入できない // 別のオーバーフローの場合 let overflow_u32 = ( 1 - 2 ) + 1u ; // 無効、-1 は u32 の範囲外 // 理想値は 32 ビットの範囲外だが、再び範囲内に戻される let out_and_in_again = ( 0x1ffffffff / 8 ); // 同様だが無効 let out_of_range = ( 0x1ffffffff / 8u ); // 計算を 32 ビットで行う必要があり、 // 0x1ffffffff が範囲外になる。
6.2.2. ブール型
bool型はtrueとfalseの値を持ちます。
| 前提条件 | 結論 | 説明 |
|---|---|---|
true: bool
| true値 | |
false: bool
| false値 |
6.2.3. 整数型
u32型は32ビット符号なし整数の集合です。
i32型は32ビット符号付き整数の集合です。 2の補数表現を用い、符号ビットは最上位ビット位置にあります。
整数型(具象型)の式でオーバーフローが発生した場合、結果は2bitwidthで剰余を取った値になります。
| 型 | 最小値 | 最大値 |
|---|---|---|
| i32 | i32(-2147483648) | 2147483647i |
| i32(-0x80000000) | 0x7fffffffi | |
| u32 | 0u | 4294967295u |
| 0x0u | 0xffffffffu |
注: AbstractIntも整数型です。
6.2.4. 浮動小数点型
f32 型は、 IEEE-754 binary32(単精度)形式の 32 ビット浮動小数点値の集合である。 詳細は § 15.7 浮動小数点評価 を参照。
f16 型は、
IEEE-754 binary16(半精度)形式の
16 ビット浮動小数点値の集合である。プログラムに
f16 拡張を有効化する
enable f16; ディレクティブが含まれていない限り、f16
型を使用すると shader-creation
error
になる。詳細は § 15.7 浮動小数点評価 を参照。
以下の表は浮動小数点型の極値を示します。各値には対応する負の値も存在します。
| 型 | 最小正の非正規化数 | 最小正の正規化数 | 最大正の有限値 | 最大の有限2のべき乗 |
|---|---|---|---|---|
| f32 | 1.40129846432481707092e-45f | 1.17549435082228750797e-38f | 3.40282346638528859812e+38f | 0x1p+127f |
| 0x1p-149f | 0x1p-126f | 0x1.fffffep+127f | ||
| f16 | 5.9604644775390625e-8h | 0.00006103515625h | 65504.0h | 0x1p+15h |
| 0x1p-24h | 0x1p-14h | 0x1.ffcp+15h |
注: AbstractFloatも浮動小数点型です。
6.2.5. スカラー型
スカラー型は、bool、AbstractInt、 AbstractFloat、i32、u32、f32、f16です。
数値スカラー型は、AbstractInt、 AbstractFloat、i32、u32、f32、f16です。
整数スカラー型は、AbstractInt、i32、u32です。
スカラー変換は、あるスカラー型の値を別のスカラー型の値へ写像します。 一般に、変換後の値は変換前の値に近く、変換先型の制限内で表現されます。 スカラー変換は次の場合に発生します:
-
値コンストラクター組み込み関数を明示的に呼び出す場合
6.2.6. ベクトル型
ベクトルは2, 3, 4個のスカラー 要素をまとめたものです。
| 型 | 説明 |
|---|---|
| vecN<T> | 型 T の N 個の成分からなるベクトル。 N は {2, 3, 4} のいずれかでなければならず、T はなければならない スカラー型のいずれかである。 T はベクトルの成分型であるという。 |
ベクトルの要素型が数値スカラーであれば、そのベクトルは数値ベクトルです。
ベクトルの主な利用例:
-
方向と大きさの両方を表現する
-
空間中の位置を表現する
-
色空間で色を表現する 例えば、要素は赤・緑・青の強度で、4つ目の要素はアルファ(不透明度)値となることがあります。
ベクトル(および行列)に対する多くの操作は 要素ごとに行われます。つまり、各スカラー要素ごとに独立して操作します。
let x : vec3< f32> = a + b ; // a, bはvec3<f32> // x[0] = a[0] + b[0] // x[1] = a[1] + b[1] // x[2] = a[2] + b[2]
| 事前宣言エイリアス | 元型 | 制限 |
|---|---|---|
| vec2i | vec2<i32> | |
| vec3i | vec3<i32> | |
| vec4i | vec4<i32> | |
| vec2u | vec2<u32> | |
| vec3u | vec3<u32> | |
| vec4u | vec4<u32> | |
| vec2f | vec2<f32> | |
| vec3f | vec3<f32> | |
| vec4f | vec4<f32> | |
| vec2h | vec2<f16> | f16拡張が必要。 |
| vec3h | vec3<f16> | |
| vec4h | vec4<f16> |
6.2.7. 行列型
行列は2, 3, 4個の浮動小数点ベクトルをまとめたものです。
| 型 | 説明 |
|---|---|
| matCxR<T> | C列×R行、型Tの行列。C, Rは{2, 3, 4}のいずれかで、Tはf32、f16、AbstractFloatのいずれかでなければなりません。 同等に、C個のvecR<T>型の列ベクトルと考えることもできます。 |
行列の主な用途は線形変換の表現です。 この解釈では、行列のベクトルは列ベクトルとして扱われます。
乗算演算子(*)は以下の用途で使われます:
-
変換をスカラーの大きさでスケールする
-
ベクトルに変換を適用する
-
他の行列と変換を合成する
§ 8.7 算術式を参照してください。
| 事前宣言エイリアス | 元型 | 制限 |
|---|---|---|
| mat2x2f | mat2x2<f32> | |
| mat2x3f | mat2x3<f32> | |
| mat2x4f | mat2x4<f32> | |
| mat3x2f | mat3x2<f32> | |
| mat3x3f | mat3x3<f32> | |
| mat3x4f | mat3x4<f32> | |
| mat4x2f | mat4x2<f32> | |
| mat4x3f | mat4x3<f32> | |
| mat4x4f | mat4x4<f32> | |
| mat2x2h | mat2x2<f16> | f16拡張が必要。 |
| mat2x3h | mat2x3<f16> | |
| mat2x4h | mat2x4<f16> | |
| mat3x2h | mat3x2<f16> | |
| mat3x3h | mat3x3<f16> | |
| mat3x4h | mat3x4<f16> | |
| mat4x2h | mat4x2<f16> | |
| mat4x3h | mat4x3<f16> | |
| mat4x4h | mat4x4<f16> |
6.2.8. アトミック型
アトミック型は、 具象の整数スカラー型をカプセル化し、 次を満たす:
-
アトミックオブジェクトは、並行する観測者に対して一定の保証を提供し、
-
アトミックオブジェクトに対する唯一の有効な操作は、アトミック 組み込み関数である。
| 型 | 説明 |
|---|---|
| atomic<T> | 型 T のアトミック。T は u32 または i32 のいずれかでなければならない。 |
式はアトミック型へ評価されてはならない。
アトミック型は、workgroup
アドレス空間内の変数、または read_write アクセスモードを持つstorage
buffer変数によってのみインスタンス化できる。
その型に対する操作のメモリスコープは、
それがインスタンス化されるアドレス空間によって決定される。
workgroup アドレス空間内のアトミック型は
Workgroup のメモリスコープを持ち、一方
storage
アドレス空間内のものは QueueFamily のメモリスコープを持つ。
アトミック 変更とは、アトミックオブジェクトに対する、そのオブジェクトの内容を設定する任意の 操作である。 新しい値がそのオブジェクトの既存値と同じであっても、その操作は変更として数えられる。
WGSL では、アトミック変更は各オブジェクトごとに相互に順序付けられる。 つまり、シェーダーステージの実行中、各アトミックオブジェクト A について、すべての エージェントは A に適用される変更操作の同じ順序を観測する。 異なるアトミックオブジェクト間の順序付けは、いかなる形でも関連していない場合があり、 因果関係は含意されない。 workgroup 空間内の変数は workgroup 内で共有されるが、異なる workgroup 間では共有されないことに注意。
6.2.9. 配列型
配列は、インデックス可能な 要素値のシーケンスである。
| 型 | 説明 |
|---|---|
| array<E,N> | 型 E の N 個の要素を持つ固定サイズ
配列。 N は配列の要素数と呼ばれる。 |
| array<E> | 型 E の要素からなる実行時サイズ配列。
これらは特定の文脈でのみ現れることができる。 |
配列の最初の要素はインデックス 0 にあり、後続の各要素は次の整数インデックスにある。 § 8.5.3 配列アクセス式を参照。
式は実行時サイズ配列型へ評価されてはならない。
固定サイズ配列の要素数式 N には、次の制約が課される:
-
N が 0 より大きくない場合:
-
N がconst-expressionである場合、それはshader-creation errorである。
-
それ以外の場合、それはpipeline-creation errorである。
-
注: 要素数の値は、N が何らかのoverride-declarationsに依存する場合はパイプライン作成 時に完全に決定され、それ以外の場合はシェーダーモジュール作成 時に決定される。
注: 型等価性を満たすには、const expression ではない任意の override expression は識別子でなければならない。 オーバーライド可能定数によってサイズ指定される workgroup 変数を参照。
実行時サイズ配列内の要素数は、 対応するstorage buffer変数に関連付けられた バッファーバインディングのサイズによって決定される。 § 13.3.4 バッファーバインディングが 実行時サイズ配列の要素数を決定するを参照。
配列の要素型は、次のいずれかでなければならない:
-
スカラー型
-
ベクトル型
-
行列型
-
作成時固定フットプリントを持つ配列型
-
作成時固定フットプリントを持つ構造体型。
注: 要素型はプレーン型でなければなりません。
2つの配列型が同じかどうかは、以下すべてが満たされた場合のみです:
-
同じ要素型を持つ
-
要素数指定が一致する。すなわち、以下のいずれかが成り立つ:
-
両者とも実行時サイズ
-
両者とも生成時固定フットプリント付き固定長で、要素数が同値(符号違いでも可。要素数は常に正なので比較可能)
-
両者とも識別子で指定されており、同じパイプラインオーバーライド可能定数宣言に解決される
-
// array<f32,8>とarray<i32,8>は型が異なる:要素型が違う var < private> a : array< f32, 8 > ; var < private> b : array< i32, 8 > ; var < private> c : array< i32, 8u > ; // array<i32,8>とarray<i32,8u>は同じ型 const width = 8 ; const height = 8 ; // array<i32,8>、array<i32,8u>、array<i32,width>は同じ型。要素数評価は8 var < private> d : array< i32, width > ; // array<i32,height>とarray<i32,width>は同じ型 var < private> e : array< i32, width > ; var < private> f : array< i32, height > ;
注: オーバーライド可能定数でサイズ指定した配列型の有効な利用は、 workgroupアドレス空間でのメモリビューとしてのみです。 これはworkgroup変数の格納型を含みます。 § 7 変数と値の宣言参照。
override blockSize = 16 ; var < workgroup> odds : array< i32, blockSize > ; var < workgroup> evens : array< i32, blockSize > ; // 同じ型 // 以下はすべて'odds'および'evens'と型が異なる // 違う型:識別子'blockSize'でない var < workgroup> evens_0 : array< i32, 16 > ; // 違う型:算術式で要素数指定 var < workgroup> evens_1 : array< i32,( blockSize * 2 / 2 ) > ; // 違う型:括弧付き識別子 var < workgroup> evens_2 : array< i32,( blockSize ) > ; // 無効例:オーバーライド要素数は最外部のみ // var<workgroup> both: array<array<i32,blockSize>,2>; // 無効例:オーバーライド要素数はworkgroup変数でのみ有効 // var<private> bad_address_space: array<i32,blockSize>;
6.2.10. 構造体型
構造体は、名前付きの メンバー 値を名前付きでまとめたものである。
| 型 | 説明 |
|---|---|
struct AStructName {M1 : T1, ... MN : TN, } |
識別子
AStructName によって名付けられ、
N 個のメンバーを持つ構造体型の宣言。
ここでメンバー i は識別子 Mi
によって名付けられ、型 Ti である。
N は少なくとも 1 でなければならない。 同じ構造体型の 2 つのメンバーは、同じ名前を持ってはならない。 |
構造体型はモジュールスコープで宣言される。 プログラムソース内の他の場所では、構造体型はその識別子名によって表される。 § 5 宣言とスコープを参照。
2 つの構造体型は、同じ名前を持つ場合に限り同じである。
構造体メンバー型は、次のいずれかでなければならない:
注: すべてのユーザー宣言構造体型は具象である。
注: 各メンバー型はプレーン型でなければならない。
構造体メンバー型および配列要素型に対する制限の帰結としては、次のものがある:
-
ポインター、テクスチャー、またはサンプラーは、配列 または構造体内のいかなる入れ子レベルにも現れてはならない。
-
実行時サイズ 配列がより大きな型の一部である場合、それは構造体の最後の要素としてのみ現れることができ、 その構造体自体は外側の配列または構造体の一部になることはできない。
// 3つのメンバーを持つ構造体 struct Data { a : i32, b : vec2< f32> , c : array< i32, 10 > , // 最後のカンマは省略可能 } // Data型値を格納する変数を宣言 var < private> some_data : Data ;
'struct' ident struct_body_decl
'{' struct_member ( ',' struct_member ) * ',' ? '}'
構造体メンバーに適用できる属性:
属性builtin、location、blend_src、 interpolate、 invariantは IO属性です。 構造体SのメンバーにIO属性がある場合、Sが仮引数や戻り値型としてエントリーポイントで使われる場合のみ効果があります。 § 13.3.1 ステージ間入出力インターフェース参照。
属性alignとsizeはレイアウト属性であり、 構造体型がユニフォームバッファやストレージバッファを定義する際に必要となる場合があります。 § 14.4 メモリレイアウト参照。
// 実行時配列 alias RTArr = array< vec4< f32>> ; struct S { a : f32, b : f32, data : RTArr } @group ( 0 ) @binding ( 0 ) var < storage> buffer : S ;
6.2.11. 合成型
型は、他の型を合成して内部構造を持つ場合合成型です。 内部部分は重複せず、構成要素と呼ばれます。 合成値は構成要素に分解可能です。§ 8.5 合成値分解式参照。
合成型は以下の通りです:
合成型Tについて、入れ子深度(NestDepth(T))は:
-
ベクトル型なら1
-
行列型なら2
-
要素型Eの配列型なら 1 + NestDepth(E)
-
メンバー型M1,...,MNを持つ構造体型Tなら 1 + max(NestDepth(M1),..., NestDepth(MN))
6.2.12. 構築可能型
多くの種類の値は生成、ロード、格納、関数への渡し、関数からの返却が可能です。 これらを構築可能と呼びます。
型が次のいずれかであれば、構築可能です:
注: すべての構築可能型は生成時固定フットプリントを持ちます。
注: アトミック型や実行時サイズ配列型は構築可能ではありません。 アトミックや実行時サイズ配列を含む複合型も構築可能ではありません。
6.2.13. 固定フットプリント型
変数のメモリフットプリントは、その変数の内容を格納するために使われるメモリ位置の数です。 メモリフットプリントは変数の格納型に依存し、シェーダーライフサイクルのある段階で確定します。 ほとんどの変数は、シェーダー生成時にサイズが決まります。 一部の変数は、パイプライン生成時、 またはシェーダー実行開始時に決まることもあります。
型が生成時固定フットプリントを持つとは、その具象化のサイズがシェーダ生成時に完全に決定される場合を指します。
型が固定フットプリントを持つとは、そのサイズがパイプライン生成時に完全に決まる場合です。
注: すべての具象生成時固定フットプリント型・固定フットプリント型は格納可能型です。
注: パイプライン生成はシェーダー生成に依存するので、生成時固定フットプリントを持つ型は、必ず固定フットプリントも持ちます。
生成時固定フットプリントを持つ型は:
注: 構築可能型は生成時固定フットプリントを持ちます。
-
生成時固定フットプリントを持つ型
-
固定長配列型(要素数への追加制約なし)
注: 定数式でないoverride式による要素数指定の固定長配列型が有効なのは、 workgroupアドレス空間でのメモリビューのみです。 これはworkgroup変数の格納型も含みます。
注: 固定フットプリント型は直接または間接的にアトミック型を含み得ますが、構築可能型は含みません。
注: 固定フットプリント型には実行時サイズ配列、およびそれを含む構造体は含まれません。
6.3. 列挙型
列挙型は、限定された名前付き値の集合です。 列挙型は、例えば有効なテクセルフォーマットの集合など、特定の概念の可能性の集合を区別するために使われます。
列挙値は、列挙型内の名前付き値のひとつです。 各列挙値は他のすべての列挙値、および他の種類の値と区別されます。
WGSLソースで新しい列挙値や列挙型を宣言する方法はありません。
注: 列挙値はテンプレートパラメータとして使われます。
6.3.1. 事前宣言列挙値
次の表は、WGSLにおける列挙型の種類、その事前宣言済み列挙子、および列挙型に必要な言語拡張を示しています。 これらの列挙型は存在しますが、WGSLのソースコードでは綴ることができません。
6.4. メモリビュー
プレーン 値で計算することに加えて、WGSL プログラムは メモリから値を読み取ったり、メモリアクセス操作を介してメモリへ値を書き込んだりすることも多い。 各メモリアクセスは、メモリビューを介して実行される。
メモリビューは、次のものから構成される:
メモリビューのアクセスモードは、そのアドレス空間でサポートされていなければならない。§ 7 変数および値の宣言を参照。
6.4.1. 格納可能型
変数に含まれる値は、格納可能型でなければならない。 格納可能型は、§ 14.4.4 値の内部レイアウトで説明されるように、 WGSL によって定義される明示的な表現を持つこともあれば、 テクスチャーやサンプラーのように 不透明であることもある。
型が格納可能であるとは、 それが具象であり、かつ次のいずれかである場合をいう:
注: すなわち、格納可能型は具象のプレーン型、テクスチャー型、および サンプラー型である。
6.4.2. ホスト共有型
ホスト共有型は、ホストとGPU間で共有されるバッファの内容を記述する型や、フォーマット変換せずにホストとGPU間でコピーされる型です。 この目的で使う場合、型にはレイアウト属性が適用されることがあります(§ 14.4 メモリレイアウト参照)。 § 7.3 var宣言の通り、ユニフォームバッファやストレージバッファ 変数の格納型は必ずホスト共有型でなければなりません。
型が具象型で、以下のいずれかであればホスト共有型です:
-
行列型
-
固定長配列型(生成時固定フットプリントがあり、要素型がホスト共有型の場合)
-
実行時サイズ配列型(要素型がホスト共有型の場合)
-
すべてのメンバーがホスト共有型の構造体型
注: ステージ間入出力型の制約は§ 13.3.1 ステージ間入出力インターフェースおよびそれ以降の節に記載されています。 それらの型もサイズが決まりますが、カウント方法が異なります。
注: テクスチャと サンプラもホストと GPU の間で共有できますが、その内容は不透明です。 このセクションのホスト共有可能な型は、特にストレージバッファおよびユニフォームバッファで使用するためのものです。
6.4.3. 参照型とポインター型
WGSLにはメモリビューを表現する型が2種類あります: 参照型とポインター型です。
| 制約 | 型 | 説明 |
|---|---|---|
| ASはアドレス空間、 Tは格納可能型、 AMはアクセスモード | ref<AS,T,AM> |
参照型
であり、AS内のメモリ位置でT型の値を保持し、
AMモードによるメモリアクセスをサポートするメモリビューの集合に対応します。
ここでTは格納型です。 参照型はWGSLソースでは書かれません。モジュール解析時に使われます。 |
| ASはアドレス空間、 Tは格納可能型、 AMはアクセスモード | ptr<AS,T,AM> |
ポインター型
であり、AS内のメモリ位置でT型の値を保持し、
AMモードによるメモリアクセスをサポートするメモリビューの集合に対応します。
ここでTは格納型です。 ポインター型はWGSLソースで記述可能です。 |
2つのポインター型は、アドレス空間・格納型・アクセスモードがすべて同じ場合のみ同じ型です。
WGSLモジュール解析時、参照型・ポインター型はアドレス空間・格納可能型・アクセスモードで完全にパラメータ化されます。 本仕様のコード例では、コメントでこの完全パラメータ化形を示します。
ただしWGSLソーステキストでは:
-
参照型は現れてはならない。
-
ポインター型は現れてよい。
-
ポインター型は、次によるパラメーター化を伴って記述される:
-
ストア型、 および
-
§ 14.3 アドレス空間で指定されるように、場合によってはアクセスモード。
-
ポインター型がプログラムソース内に現れる場合、 そのポインター型のアドレス空間、ストア型、およびアクセスモードを用いて、 プログラム内のどこかで変数を宣言することも有効でなければならない。
注: この制限は、実行時に決して使用できない特定の型エイリアス および関数の仮パラメーターの宣言を禁止する。 この制限がなければ、ポインター型へのエイリアスを宣言することは有効になるが、 その型のポインター値を作成することは決してできない。 同様に、ポインター仮パラメーターを持つ関数を宣言することは有効になるが、 その関数を呼び出すことは決してできない。
-
fn my_function ( /* 'ptr<function,i32,read_write>'は、'function'アドレス空間のメモリ位置でi32値を保持する ポインター値の型です。ここで'i32'は格納型です。 アクセスモードは暗黙で'read_write'です。 デフォルトは「アドレス空間」節参照。 */ ptr_int : ptr< function, i32> , // 'ptr<private,array<f32,50>,read_write>'は、'private'アドレス空間のメモリ位置で // f32型50要素の配列を保持するポインター値の型です。 // 格納型は'array<f32,50>'。 // アクセスモードは暗黙で'read_write'。 // デフォルトは「アドレス空間」節参照。 ptr_array : ptr< private, array< f32, 50 >> ) { }
参照型・ポインター型はいずれもメモリビューの集合であり、特定のメモリビューは一意な参照値と一意なポインター値に対応します:
ptr<AS,T,AM型の各ポインター値pは、ref<AS,T,AM型の一意な参照値rに対応し、 逆も同様で、pとrは同じメモリビューを表します。
6.4.4. 有効・無効なメモリ参照
参照は§ 6.4.8 参照とポインター値の形成で詳しく説明されているように形成されます。 一般に、有効な参照は次の方法で形成されます:
-
変数を名前で指定する
一般に、無効なメモリ参照は次の方法で形成されます:
-
間接参照演算子を無効なポインターに適用する
有効なポインターは有効な参照に対応するポインターです。 無効なポインターは無効なメモリ参照に対応するポインターです。
6.4.5. 起源変数
ポインター値の起源変数は、対応する参照値の起源変数として定義されます。
注: 起源変数は動的な概念です。 関数の仮引数の起源変数は、その関数の呼び出し元によります。 呼び出し元が異なれば、異なる起源変数へのポインターが渡されることがあります。
有効な参照は必ず、ある変数のメモリ位置の一部または全部に対応する非空のメモリビューとなります。
次の例では、参照the_particle.position[i]は、iが0または1のときのみ有効です。
iが2の場合、その参照は無効なメモリ参照ですが、参照先はthe_particle.color_indexのメモリ位置となります。
6.4.6. 範囲外アクセス
メモリアクセス操作が無効なメモリ参照をアクセスすると、範囲外アクセスとなります。
範囲外アクセスはプログラム不具合です。もしそのまま実行された場合、一般的には:
このため、実装は決してそのままアクセスを実行しません。 範囲外アクセスの実行は動的エラーとなります。
注: ストア型を誤って解釈する例は、
前のセクションの例で発生する。
i が 2 のとき、式 the_particle.velocity[i] は
型 ref<storage,f32,read_write> を持つ。これは、f32 を
そのストア型とするメモリビューであることを意味する。
しかし、メモリ位置は
color_index メンバーに割り当てられているため、格納されている値は実際には型 i32 である。
その結果には以下が含まれます(限定されません):
- トラップ
-
シェーダー呼び出しは直ちに終了し、シェーダーステージ出力は0値となる。
- 無効ロード
-
無効参照からのロードは次のいずれかを返す:
- 無効ストア
-
無効参照へのストアは次のいずれか:
共有アドレス空間内の変数の別の位置へ無効なロードやストアがリダイレクトされた場合、データ競合が発生する可能性があります。 例えば、複数の並行実行呼び出しが配列の最初の要素へリダイレクトされ、少なくとも1つが書き込みなら同期されていない限りデータ競合=動的エラーとなります。
範囲外アクセスは均一性解析の前提を破棄します。 例えば、範囲外アクセスで呼び出しが早期終了すると、集合演算に参加できなくなります。 特にworkgroupBarrier呼び出しがシェーダーをハングさせたり、微分値が不正になることがあります。
6.4.7. 参照型とポインター型の利用例
参照型とポインター型は用途で区別されます:
-
変数の型は 参照型である。
-
address-of 操作 (単項
&)は、参照値を対応するポインター値へ変換する。 -
間接参照操作 (単項
*)は、ポインター値を対応する参照値へ変換する。 -
let 宣言は ポインター型であり得るが、参照型ではあり得ない。
-
仮 パラメーターはポインター型であり得るが、参照型ではあり得ない。
-
ロード規則: 関数内では、 参照は型規則を満たすために自動的に逆参照される(読み取られる):
-
関数内で、ストア型 T を持つ参照式 r が 文または式で使用され、かつ
-
r が read または read_write のアクセスモードを持ち、かつ
-
一致する可能性のある唯一の型規則が、r に型 T の値を持つことを要求する場合、
-
その型規則の要件は満たされたものとみなされ、かつ
-
その文脈で r を評価した結果は、評価時に r によって参照されるメモリ位置に格納されている値 (型 T)である。 すなわち、結果値を生成するために読み取り アクセスが実行される。
-
このような参照型定義により、変数の簡便な利用が可能となります:
@compute @workgroup_size ( 1 ) fn main () { // 'i'はref<function,i32,read_write>型 // 'i'のメモリ位置にはi32値0が格納されている。 var i : i32= 0 ; // 'i + 1'は'i'部分式がi32型でなければ型規則に一致しない。 // よって'i + 1'式はi32型。評価時、'i'部分式はその時点でメモリ位置に格納されたi32値となる。 let one : i32= i + 1 ; // 'i'のメモリ位置値を2に更新 i = one + 1 ; // 'i'のメモリ位置値を5に更新。右辺は代入前に評価される。 i = i + 3 ; }
var < private> age : i32; fn get_age () -> i32{ // return文の式の型は'i32'でなければならない(関数の戻り値型に一致)。 // 'age'式は型ref<private,i32,read_write>。 // 参照の格納型が要求される型と一致し、他の型規則が適用されないため、Load規則を適用。 // この文脈での'age'評価はreturn文実行時に参照するメモリ領域からロードされたi32値。 return age ; } fn caller () { age = 21 ; // copy_age定数にはi32値21が代入される。 let copy_age : i32= get_age (); }
ポインター型定義により、2つの主要な用途が可能となります:
-
ポインター型の let 宣言を使用して、変数の内容の一部に対する短い名前を形成する。
-
関数の仮パラメーターを使用して、呼び出し元関数からアクセス可能な 変数のメモリを参照する。
-
そのような関数の呼び出しは、そのオペランドにポインター値を与えなければならない。 これは多くの場合、変数の内容へのポインターを取得するために、address-of 操作(単項
&)を使用する必要がある。
-
struct Particle { position: vec3< f32> , velocity : vec3< f32> } struct System { active_index : i32, timestep : f32, particles : array< Particle , 100 > } @group ( 0 ) @binding ( 0 ) var < storage, read_write> system : System ; @compute @workgroup_size ( 1 ) fn main () { // ストレージメモリ内の特定Particleへのポインターを形成 let active_particle = & system . particles [ system . active_index ]; let delta_position : vec3< f32> = ( * active_particle ). velocity * system . timestep ; let current_position : vec3< f32> = ( * active_particle ). position; ( * active_particle ). position= delta_position + current_position ; }
fn add_one ( x : ptr< function, i32> ) { /* 'x' の場所に次の大きい整数値を格納するように更新する、 (もしくは、最大の負の i32 値にラップアラウンドする)。 左辺では、単項 '*' はポインタを参照に変換し、 それに代入できるようにする。デフォルトでは read_write アクセスモードを持つ。 /* 右辺について: - 単項 '*' はポインタを参照に変換し、read_write アクセスモードを持つ。 - 一致する型ルールは加算 (+) のみで、'*x' が i32 型である必要がある。 これは '*x' のストア型である。よってロードルールが適用され、 評価時点で '*x' に格納されている値、すなわち i32 の 0 となる。 - 0 に 1 を加算し、右辺の最終値として 1 になる。*/ 1 を '*x' のメモリに格納する。*/ * x = * x + 1 ; } @compute @workgroup_size ( 1 ) fn main () { var i : i32= 0 ; // 'i' の内容を修正し、1 にする。 // 単項 '&' を使い、'i' のポインタ値を取得する。 // 呼び出し先の関数が 'i' のメモリにアクセスでき、修正可能であることを明確に示す。 add_one ( & i ); let one : i32= i ; // 'one' の値は 1 となる。 }
6.4.8. 参照値とポインター値の生成
参照値は次のいずれかの方法で生成されます:
-
ポインターに間接参照(単項
*)演算を適用する。 -
-
ストア型がベクトルの場合、1文字のベクトルアクセス句を追加すると、その成分への参照値になります。 § 8.5.1.3 ベクトルメモリビューからの成分参照参照。
-
ストア型が構造体の場合、メンバーアクセス句を追加すると、そのメンバーへの参照値になります。 § 8.5.4 構造体アクセス式参照。
-
-
-
ストア型がベクトルの場合、配列インデックスアクセス句を追加すると、その成分への参照値になります。 § 8.5.1.3 ベクトルメモリビューからの成分参照参照。
-
ストア型が行列の場合、配列インデックスアクセス句を追加すると、その列ベクトルへの参照値になります。 § 8.5.2 行列アクセス式参照。
-
ストア型が配列の場合、配列インデックスアクセス句を追加すると、その要素への参照値になります。 § 8.5.3 配列アクセス式参照。
-
全ての場合で、結果のアクセスモードは元の参照のものと同じです。
struct S { age : i32, weight : f32} var < private> person : S ; // 別の場所で'person'は変数の基底メモリへの参照を表し、型はref<private,S,read_write>となる。 fn f () { var uv : vec2< f32> ; // この関数本体では'uv'はその基底メモリへの参照を表し、型はref<function,vec2<f32>,read_write>となる。 // 代入の左辺を評価: // 'uv.x'を評価して参照値を得る: // 1. まず'uv'を評価し、変数'uv'のメモリへの参照(型ref<function,vec2<f32>,read_write>)を得る。 // 2. '.x'ベクトルアクセス句を適用し、参照値の指すベクトルの第1成分メモリへの参照(型ref<function,f32,read_write>)を得る。 // 右辺を評価するとf32値1.0となる。1.0をuv.xのストレージメモリ位置に格納。 uv . x = 1.0 ; // 代入の左辺を評価: // 'uv[1]'を評価して参照値を得る: // 1. まず'uv'を評価し、変数'uv'のメモリへの参照(型ref<function,vec2<f32>,read_write>)を得る。 // 2. '[1]'配列インデックス句を適用し、参照値の指すベクトルの第2成分メモリへの参照(型ref<function,f32,read_write>)を得る。 // 右辺はf32値2.0。2.0をuv[1]のストレージメモリ位置に格納。 uv [ 1 ] = 2.0 ; var m : mat3x2< f32> ; // 'm[2]'の評価: // 1. 'm'を評価し、変数'm'のメモリへの参照(型ref<function,mat3x2<f32>,read_write>)を得る。 // 2. '[2]'配列インデックス句を適用し、参照値の指す行列の第3列ベクトルメモリへの参照(型ref<function,vec2<f32>,read_write>)を得る。 // let宣言はvec2<f32>型なので、初期化子はvec2<f32>型でなければならない。 // ロード規則が適用され、'm[2]'参照位置からロードした値が初期化子となる。 let p_m_col2 : vec2< f32> = m [ 2 ]; var A : array< i32, 5 > ; // 'A[4]'の評価: // 1. 'A'を評価し、変数'A'のメモリへの参照(型ref<function,array<i32,5>,read_write>)を得る。 // 2. '[4]'配列インデックス句を適用し、参照値の指す配列の第5要素メモリへの参照(型ref<function,i32,read_write>)を得る。 // let宣言はi32型なので、右辺はi32型でなければならない。 // ロード規則が適用され、'A[4]'参照位置からロードした値が初期化子となる。 let A_4_value : i32= A [ 4 ]; // 'person.weight'の評価: // 1. 'person'を評価し、モジュールスコープ変数のメモリへの参照(型ref<private,S,read_write>)を得る。 // 2. '.weight'メンバーアクセス句を適用し、参照値の指すメモリの第2メンバー位置への参照(型ref<private,f32,read_write>)を得る。 // let宣言はf32型なので、右辺はf32型でなければならない。 // ロード規則が適用され、'person.weight'参照位置からロードした値が初期化子となる。 let person_weight : f32= person . weight ; // また、ポインターからも同じ構文で参照値が生成できる。 let uv_ptr = & uv ; // この関数本体では'uv_ptr'は'uv'基底メモリへのポインターで、型はptr<function,vec2<f32>,read_write>となる。 // 代入左辺を評価: // '*uv_ptr'を評価して参照値を得る: // 1. 'uv_ptr'を評価し、'uv'基底メモリへのポインター(型ptr<function,vec2<f32>,read_write>)を得る。 // 2. 間接参照演算子を適用し、'uv'のメモリへの参照を得る。 // 右辺はvec2<f32>値(1.0, 2.0)。'uv'のストレージメモリ位置に(1.0, 2.0)を格納。 * uv_ptr = vec2f( 1.0 , 2.0 ); // 代入左辺を評価: // 'uv_ptr.x'を評価して参照値を得る: // 1. 'uv_ptr'を評価し、'uv'基底メモリへのポインター(型ptr<function,vec2<f32>,read_write>)を得る。 // 2. '.x'ベクトルアクセス句を適用し、参照値の指すベクトルの第1成分メモリへの参照(型ref<function,f32,read_write>)を得る。 // 右辺はf32値1.0。uv.xのストレージメモリ位置に1.0を格納。 uv_ptr . x = 1.0 ; // 代入左辺を評価: // 'uv_ptr[1]'を評価して参照値を得る: // 1. 'uv_ptr'を評価し、'uv'基底メモリへのポインター(型ptr<function,vec2<f32>,read_write>)を得る。 // 2. '[1]'配列インデックス句を適用し、参照値の指すベクトルの第2成分メモリへの参照(型ref<function,f32,read_write>)を得る。 // 右辺はf32値2.0。uv[1]のストレージメモリ位置に2.0を格納。 uv_ptr [ 1 ] = 2.0 ; let m_ptr = & m ; // 'm_ptr[2]'の評価: // 1. 'm_ptr'を評価し、'm'基底メモリへのポインター(型ptr<function,mat3x2<f32>,read_write>)を得る。 // 2. '[2]'配列インデックス句を適用し、参照値の指す行列の第3列ベクトルへの参照(型ref<function,vec2<f32>,read_write>)を得る。 // let宣言はvec2<f32>型なので、初期化子はvec2<f32>型でなければならない。 // ロード規則が適用され、'm[2]'参照位置からロードした値が初期化子となる。 let p_m_col2 : vec2< f32> = m_ptr [ 2 ]; let A_ptr = & A ; // 'A[4]'の評価: // 1. 'A_ptr'を評価し、'A'基底メモリへのポインター(型ptr<function,array<i32,5>,read_write>)を得る。 // 2. '[4]'配列インデックス句を適用し、参照値の指す配列の第5要素メモリへの参照(型ref<function,i32,read_write>)を得る。 // let宣言はi32型なので、右辺はi32型でなければならない。 // ロード規則が適用され、'A[4]'参照位置からロードした値が初期化子となる。 let A_4_value : i32= A_ptr [ 4 ]; let person_ptr = & person ; // 'person.weight'の評価: // 1. 'person_ptr'を評価し、モジュールスコープ変数のメモリへのポインター(型ptr<private,S,read_write>)を得る。 // 2. '.weight'メンバーアクセス句を適用し、参照値の指すメモリの第2メンバー位置への参照(型ref<private,f32,read_write>)を得る。 // let宣言はf32型なので、右辺はf32型でなければならない。 // ロード規則が適用され、'person.weight'参照位置からロードした値が初期化子となる。 let person_weight : f32= person_ptr . weight ; }
ポインター値は次のいずれかの方法で生成されます:
全ての場合で、結果のアクセスモードは元のポインターのものと同じです。
// privateアドレス空間にf32値を格納する変数を宣言 var < private> x : f32; fn f () { // functionアドレス空間にi32値を格納する変数を宣言 var y : i32; // 'x'はモジュールスコープ変数'x'に解決され、型はref<private,f32,read_write>となる。 // 単項'&'演算で参照をポインターに変換。 // アクセスモードは元変数のものと同じ。完全型はptr<private,f32,read_write>。 // functionアドレス空間のデフォルトアクセスモードはread_writeなので明記不要。 let x_ptr : ptr< private, f32> = & x ; // 'y'は関数スコープ変数'y'に解決され、型はref<private,i32,read_write>となる。 // 単項'&'演算で参照をポインターに変換。アクセスモードはデフォルトでread_write。 let y_ptr : ptr< function, i32> = & y ; // 新しい変数。モジュールスコープ変数と別物。 var x : u32; // ここで'x'は直前に宣言された関数スコープ変数で、型はref<function,u32,read_write>。 // 単項'&'演算で参照をポインターに変換。アクセスモードはデフォルトでread_write。 let inner_x_ptr : ptr< function, u32> = & x ; }
6.4.9. 他言語における参照型・ポインター型との比較
この節は参考情報であり、規範的ではありません。
WGSLの参照型・ポインター型は他言語よりも制限されています。特に:
-
WGSL では、参照を別の参照または変数へのエイリアスとして直接宣言することはできない。 それは変数としても仮パラメーターとしてもできない。
-
WGSL では、ポインターおよび参照は格納可能ではない。 すなわち、WGSL の変数宣言の内容は、ポインターまたは 参照を含むことができない。
-
WGSL では、関数はポインターまたは参照を返してはならない。
-
WGSL では、整数値とポインター値の間で変換する方法はない。
-
WGSL では、ポインター値の型を別のポインター型へ強制的に変更する方法はない。
-
複合成分参照式は異なる: それは複合値への参照を取り、その複合値内の 成分または要素の 1 つへの参照を生成する。 これらは WGSL では異なる参照と見なされる。ただし、より低い実装抽象レベルでは 同じマシンアドレスを持つ場合がある。
-
-
WGSL では、参照値の型を別の参照型へ強制的に変更する方法はない。
-
WGSL では、ポインターまたは参照のアクセスモードを変更する方法はない。
-
比較すると、C++ は非 const ポインターを const ポインターへ自動的に変換し、 const 値を非 const 値へ変換するための
const_castを持つ。
-
-
WGSL では、"heap" から新しいメモリを割り当てる方法はない。
-
WGSL では、変数を明示的に破棄する方法はない。 WGSL 変数のメモリは、その変数がスコープ外になったときにのみアクセス不能になる。
注: 上記規則から「ダングリング」ポインター、すなわち「生存」起源変数のメモリを参照しないポインターを生成することはできません。 メモリビューは無効なメモリ参照となる場合がありますが、 決して 起源変数またはバッファに関連しないメモリ位置へアクセスしません。
6.5. テクスチャ型・サンプラー型
テクセルはテクスチャの最小単位として個別にアクセス可能なスカラーまたはベクトルです。 texelはtexture elementの略です。
テクスチャは、レンダリングに有用な特殊な操作をサポートするテクセル集合です。 WGSLではこれらの操作はテクスチャ組み込み関数で呼び出します。 全リストは§ 17.7 テクスチャ組み込み関数参照。
WGSLのテクスチャはWebGPUのGPUTextureに対応します。
テクスチャには以下の特徴があります:
- テクセルフォーマット
-
各テクセルのデータ表現。§ 6.5.1 テクセルフォーマット参照。
- 次元性
-
グリッド座標の次元数と座標の解釈方法。次元数は1, 2, 3のいずれかです。 多くのテクスチャは直交座標を使います。 キューブテクスチャは6つの正方形面を持ち、三次元座標は原点からキューブ中心への方向ベクトルとして解釈されます。
WebGPUの
GPUTextureViewDimension参照。 - サイズ
-
各次元のグリッド座標の範囲。ミップレベルによって決まります。
- ミップレベル数
-
ミップレベル数はサンプルテクスチャや深度テクスチャでは1以上、ストレージテクスチャでは1です。
ミップレベル0がテクスチャのフルサイズ版を保持し、各次レベルは前レベルをフィルタした半分サイズ(切り上げ)です。
テクスチャをサンプリングする際、明示的または暗黙的な詳細度(LOD)でミップレベルを選択し、フィルタリングで合成値を生成します。 - 配列化
-
テクスチャが配列化されているかどうか。
-
非配列テクスチャはテクセルのグリッドです。
-
配列化テクスチャは同種グリッドの配列です。
-
- 配列サイズ
-
配列化テクスチャの場合、グリッド数。
- サンプル数
-
テクスチャがマルチサンプルの場合のサンプル数。
テクスチャ内の各テクセルには一意な論理テクセルアドレスが関連付けられており、これは整数タプルで:
テクスチャの物理的な構造は描画最適化のために設計されており、データレイアウトや型、内部処理はシェーダ言語から直接指定できません。
その結果、シェーダーはテクスチャ変数内のテクセルメモリに直接アクセスできません。 代わりに、アクセスは不透明なハンドルを介して仲介されます:
-
シェーダー内では:
-
WebGPU パイプラインを構築するとき、テクスチャー変数のストア型とバインディングは、 対応するバインドグループレイアウトエントリーと互換でなければならない。
このように、テクスチャ型でサポートされる操作は、テクスチャ組み込み関数にそのテクスチャ型の仮引数が存在するかで決まります。
注: テクスチャ変数が持つハンドルはシェーダで変更できません。 すなわち、変数自体はread-onlyですが、アクセス先の基底テクスチャが可変(例:write-only ストレージテクスチャ)でも同様です。
テクスチャ型は以下の型です:
サンプラは、不透明なハンドルであり、テクセルがサンプリング済み テクスチャまたは深度テクスチャからどのようにアクセスされるかを制御します。
WGSLサンプラーはWebGPUのGPUSamplerに対応します。
テクセルアクセスはサンプラーの複数のプロパティで制御されます:
- アドレッシングモード
-
テクスチャ境界・範囲外座標の処理方法を制御。 次元ごとに独立して設定可能。 WebGPU
GPUAddressMode参照。 - フィルタモード
-
最終結果を得るためにどのテクセルを使うか制御。 最近傍テクセルまたは複数テクセル間で補間可。 複数フィルタモードは独立設定可能。 WebGPU
GPUFilterMode参照。 - LODクランプ
-
アクセスする詳細度(LOD)の最小・最大値を制御。
- 比較
-
比較サンプラー用の比較方法を制御。 WebGPU
GPUCompareFunction参照。 - 最大異方性
-
サンプラーで使用する最大異方性値を制御。
サンプラーはWGSLモジュール内で生成できず、上記プロパティ等の状態はシェーダ内では不変であり、WebGPU APIのみで設定可。
フィルタリングサンプラー(補間フィルタ使用サンプラー)を非フィルタ対応フォーマットのテクスチャで使うとパイプライン生成エラーとなります。
注: サンプラー変数が持つハンドルはシェーダで変更できません。
6.5.1. テクセルフォーマット
WGSLでは、特定のテクスチャ型がテクセルフォーマットによってパラメータ化されます。
テクセルフォーマットは、次の特徴を持ちます:
- チャンネル
-
各チャンネルはスカラー値を含みます。 テクセルフォーマットは最大4つのチャンネル(
r、g、b、a)を持ち、 通常は赤・緑・青・アルファチャンネルの概念に対応します。 - チャンネルフォーマット
-
チャンネルのビット数とそのビットの解釈方法。
WGSLの各テクセルフォーマットは、同名のWebGPU GPUTextureFormatに対応します。
WGSLソースコードでは、特定のテクセルフォーマットのみが使用されます。 これらのテクセルフォーマットを定義するために使われるチャンネルフォーマットは、 チャンネルフォーマット表に一覧されています。 下から2番目の列は、格納されたチャンネルビットからシェーダーで使用される値への変換を指定します。 これはチャンネル転送関数(CTF)とも呼ばれます。 3番目の列は、シェーダー値から格納されるチャンネルビットへの変換を指定します。 これは逆チャンネル転送関数(ICTF)とも呼ばれます。 最後の列は、そのテクセルフォーマットで必要な言語拡張を指定します。
注: 8unormのチャンネル転送関数は{0,...,255}を浮動小数点区間[0.0, 1.0]に写像します。
注: 8snormのチャンネル転送関数は{-128,...,127}を浮動小数点区間[-1.0, 1.0]に写像します。
| チャンネルフォーマット | 格納ビット数 | 格納ビットの解釈 | シェーダ型 | シェーダ値(チャンネル転送関数) | 書き込み値 T(逆チャンネル転送関数)
|
|---|---|---|---|---|---|
| 8unorm | 8 | 符号なし整数 v ∈ {0,...,255} | f32 | v ÷ 255 | max(0, min(1, T))
|
| 8snorm | 8 | 符号付き整数 v ∈ {-128,...,127} | f32 | v ÷ 127 | max(-1, min(1, T))
|
| 8uint | 8 | 符号なし整数 v ∈ {0,...,255} | u32 | v | min(255, T)
|
| 8sint | 8 | 符号付き整数 v ∈ {-128,...,127} | i32 | v | max(-128, min(127, T))
|
| 16unorm | 16 | 符号なし整数 v ∈ {0,...,65535} | f32 | v ÷ 65535 | max(0, min(1, T))
|
| 16snorm | 16 | 符号付き整数 v ∈ {-32768,...,32767} | f32 | v ÷ 32767 | max(-1, min(1, T))
|
| 16uint | 16 | 符号なし整数 v ∈ {0,...,65535} | u32 | v | min(65535, T)
|
| 16sint | 16 | 符号付き整数 v ∈ {-32768,...,32767} | i32 | v | max(-32768, min(32767, T))
|
| 16float | 16 | IEEE-754 binary16 16ビット浮動小数点値 v | f32 | v | quantizeToF16(T)
|
| 32uint | 32 | 32ビット符号なし整数値 v | u32 | v | T
|
| 32sint | 32 | 32ビット符号付き整数値 v | i32 | v | T
|
| 32float | 32 | IEEE-754 binary32 32ビット浮動小数点値 v | f32 | v | T
|
| 2unorm | 2 | 符号なし整数 v ∈ {0,...,3} | f32 | v ÷ 3 | max(0, min(1, T))
|
| 2uint | 2 | 符号なし整数 v ∈ {0,...,3} | u32 | v | min(3, T)
|
| 10unorm | 10 | 符号なし整数 v ∈ {0,...,1023} | f32 | v ÷ 1023 | max(0, min(1, T))
|
| 10uint | 10 | 符号なし整数 v ∈ {0,...,1023} | u32 | v | min(1023, T)
|
| 10float | 10 | 10ビット浮動小数点値:5ビットバイアス指数、5ビット仮数 v | f32 | v | max(0, T)
|
| 11float | 11 | 11ビット浮動小数点値:5ビットバイアス指数、6ビット仮数 v | f32 | v | max(0, T)
|
以下のストレージテクスチャ用テクセルフォーマット表のテクセルフォーマットは、WebGPU plain color formatsに対応し、WebGPU STORAGE_BINDING用途で少なくとも1つのアクセスモードをサポートします。
これらのテクセルフォーマットはストレージテクスチャ型(§ 6.5.5
ストレージテクスチャ型)のパラメータとして使われます。
テクセルフォーマットが4チャンネルすべてを持たない場合:
-
テクセルの読み出し時、チャンネル転送関数が成分ごとに適用されます:
-
緑チャンネルがない場合、シェーダ値の第2成分は0。
-
青チャンネルがない場合、シェーダ値の第3成分は0。
-
アルファチャンネルがない場合、シェーダ値の第4成分は1。
-
-
テクセルの書き込み時、逆チャンネル転送関数が成分ごとに適用され、欠落チャンネル用のシェーダ値成分は無視されます。
下表の最後の列は、チャンネルフォーマット表のフォーマット固有チャンネル転送関数を使用しています。
| テクセルフォーマット | チャンネルフォーマット | メモリ順のチャンネル | 対応するシェーダー値 | 必要な言語拡張 |
|---|---|---|---|---|
| rgba8unorm | 8unorm | r, g, b, a | vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rgba8snorm | 8snorm | r, g, b, a | vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rgba8uint | 8uint | r, g, b, a | vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rgba8sint | 8sint | r, g, b, a | vec4<i32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rgba16unorm | 16unorm | r, g, b, a | vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) | texture_formats_tier1 |
| rgba16snorm | 16snorm | r, g, b, a | vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) | texture_formats_tier1 |
| rgba16uint | 16uint | r, g, b, a | vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rgba16sint | 16sint | r, g, b, a | vec4<i32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rgba16float | 16float | r, g, b, a | vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rg8unorm | 8unorm | r, g | vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) | texture_formats_tier1 |
| rg8snorm | 8snorm | r, g | vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) | texture_formats_tier1 |
| rg8uint | 8uint | r, g | vec4<u32>(CTF(r), CTF(g), 0u, 1u) | texture_formats_tier1 |
| rg8sint | 8sint | r, g | vec4<i32>(CTF(r), CTF(g), 0, 1) | texture_formats_tier1 |
| rg16unorm | 16unorm | r, g | vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) | texture_formats_tier1 |
| rg16snorm | 16snorm | r, g | vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) | texture_formats_tier1 |
| rg16uint | 16uint | r, g | vec4<u32>(CTF(r), CTF(g), 0u, 1u) | texture_formats_tier1 |
| rg16sint | 16sint | r, g | vec4<i32>(CTF(r), CTF(g), 0, 1) | texture_formats_tier1 |
| rg16float | 16float | r, g | vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) | texture_formats_tier1 |
| r32uint | 32uint | r | vec4<u32>(CTF(r), 0u, 0u, 1u) | |
| r32sint | 32sint | r | vec4<i32>(CTF(r), 0, 0, 1) | |
| r32float | 32float | r | vec4<f32>(CTF(r), 0.0, 0.0, 1.0) | |
| rg32uint | 32uint | r, g | vec4<u32>(CTF(r), CTF(g), 0u, 1u) | |
| rg32sint | 32sint | r, g | vec4<i32>(CTF(r), CTF(g), 0, 1) | |
| rg32float | 32float | r, g | vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) | |
| rgba32uint | 32uint | r, g, b, a | vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rgba32sint | 32sint | r, g, b, a | vec4<i32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| rgba32float | 32float | r, g, b, a | vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| bgra8unorm | 8unorm | b, g, r, a | vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) | |
| r8unorm | 8unorm | r | vec4<f32>(CTF(r), 0.0, 0.0, 1.0) | texture_formats_tier1 |
| r8snorm | 8snorm | r | vec4<f32>(CTF(r), 0.0, 0.0, 1.0) | texture_formats_tier1 |
| r8uint | 8uint | r | vec4<u32>(CTF(r), 0u, 0u, 1u) | texture_formats_tier1 |
| r8sint | 8sint | r | vec4<i32>(CTF(r), 0, 0, 1) | texture_formats_tier1 |
| r16unorm | 16unorm | r | vec4<f32>(CTF(r), 0.0, 0.0, 1.0) | texture_formats_tier1 |
| r16snorm | 16snorm | r | vec4<f32>(CTF(r), 0.0, 0.0, 1.0) | texture_formats_tier1 |
| r16uint | 16uint | r | vec4<u32>(CTF(r), 0u, 0u, 1u) | texture_formats_tier1 |
| r16sint | 16sint | r | vec4<i32>(CTF(r), 0, 0, 1) | texture_formats_tier1 |
| r16float | 16float | r | vec4<f32>(CTF(r), 0.0, 0.0, 1.0) | texture_formats_tier1 |
| rgb10a2unorm | r, g, b: 10unorm a: 2unorm | r, g, b, a | vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) | texture_formats_tier1 |
| rgb10a2uint | r, g, b: 10uint a: 2uint | r, g, b, a | vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a)) | texture_formats_tier1 |
| rg11b10ufloat | r, g: 11float b: 10float | r, g, b | vec4<f32>(CTF(r), CTF(g), CTF(b), 1.0) | texture_formats_tier1 |
WGSLは、表内の各テクセルフォーマットについて事前宣言列挙値を用意しています。
6.5.2. サンプルテクスチャ型
サンプルテクスチャは、 サンプラーと組み合わせてアクセスできます。 サンプラーを使わずにアクセスすることも可能です。 サンプルテクスチャは読み出しアクセスのみ許可します。
テクセルフォーマットは、テクスチャ変数にバインドされた
GPUTexture
の format
属性です。
WebGPU は、テクスチャ、バインドグループレイアウトの sampleType、
およびテクスチャ変数の サンプル型 の互換性を
検証します。
テクスチャーはサンプリング型によってパラメーター化され、
f32、i32、または u32 でなければならない。
| 型 | 次元性 | 配列化 |
|---|---|---|
| texture_1d<T> | 1D
| なし |
| texture_2d<T> | 2D
| なし |
| texture_2d_array<T> | 2D
| あり |
| texture_3d<T> | 3D
| なし |
| texture_cube<T> | Cube
| なし |
| texture_cube_array<T> | Cube
| あり |
-
Tはサンプル型です。
-
画像のパラメータ化型はサンプリング後の変換型です。 例えば、8bit unorm成分のテクセル画像でも、サンプリングすると32ビット浮動小数点(またはvec-of-f32)になります。
6.5.3. マルチサンプルテクスチャ型
マルチサンプルテクスチャは サンプル数が1以上です。 名前に反して、サンプラーと組み合わせて使うことはできません。 実質的に、サンプルインデックスを無視すれば各論理テクセルアドレスごとに複数のテクセル分のデータを保持します。
テクセルフォーマットは、テクスチャ変数にバインドされた
GPUTexture
の format
属性です。
WebGPU は、テクスチャ、バインドグループレイアウトの sampleType、
およびテクスチャ変数の サンプル型 の互換性を
検証します。
texture_multisampled_2d はサンプリング型によってパラメーター化され、
f32、i32、または u32 でなければならない。
| 型 | 次元性 | 配列化 |
|---|---|---|
| texture_multisampled_2d<T> | 2D
| なし |
| texture_depth_multisampled_2d | 2D
| なし |
-
Tはサンプル型です。
6.5.4. 外部サンプルテクスチャ型
外部テクスチャは、不透明な
2 次元の float-サンプリング済みテクスチャ型であり、texture_2d<f32>に似ていますが、
潜在的に異なる表現を持ちます。
これは、これらの異なる表現を扱うtextureLoadまたは
textureSampleBaseClampToEdge組み込み
関数を使用して読み取ることができます。
WebGPU § 6.4 GPUExternalTexture参照。
| 型 | 次元性 | 配列化 |
|---|---|---|
| texture_external | 2D
| なし |
6.5.5. ストレージテクスチャ型
ストレージテクスチャは、サンプラーを使わず個別テクセル値へのアクセスをサポートします。
-
書き込み専用ストレージテクスチャ は、個別テクセルへの書き込みをサポートし、シェーダ値から格納テクセル値への自動変換を行います。
-
読み出し専用ストレージテクスチャ は、個別テクセルの読み出しをサポートし、格納テクセル値からシェーダテクセル値への自動変換を行います。
-
読書き両用ストレージテクスチャ は、個別テクセルの読み出し・書き込みをサポートし、シェーダ値・格納値間の自動変換を行います。
storage texture 型は、storage texture 用の texel format のいずれかによってパラメーター化されなければならない。 texel format は、§ 6.5.1 Texel Formats で指定される変換関数を決定する。
ストレージテクスチャへテクセルを書き込む際は、変換関数の逆が用いられ、シェーダ値が格納テクセル値に変換されます。
| 型 | 次元性 | 配列化 |
|---|---|---|
| texture_storage_1d<Format, Access> | 1D
| なし |
| texture_storage_2d<Format, Access> | 2D
| なし |
| texture_storage_2d_array<Format, Access> | 2D
| あり |
| texture_storage_3d<Format, Access> | 3D
| なし |
-
Format は、storage texture 用の texel format のいずれかに対する列挙子でなければならない
-
Format と Access の無効な組み合わせによってshader-creation error は発生しない。 Format と Access の組み合わせは、パイプライン作成中のshader binding validation ステップで検査される。 無効な組み合わせはpipeline-creation errorを発生させることになる。
6.5.6. 深度テクスチャ型
深度テクスチャは、 sampler_comparisonと組み合わせてアクセス可能です。 サンプラーを使わずにアクセスすることもできます。 深度テクスチャは読み出しアクセスのみ許可されます。
テクスチャのテクセルフォーマットはGPUTextureBindingLayoutで定義されます。
| 型 | 次元性 | 配列化 |
|---|---|---|
| texture_depth_2d | 2D
| なし |
| texture_depth_2d_array | 2D
| あり |
| texture_depth_cube | Cube
| なし |
| texture_depth_cube_array | Cube
| あり |
6.5.7. サンプラー型
サンプラーは、サンプルテクスチャ や深度テクスチャへのアクセスを調整し、以下の操作を組み合わせて行います:
サンプラー型は以下の通りです:
| 型 | 説明 |
|---|---|
| sampler | サンプラー。サンプルテクスチャへのアクセスを調整します。 |
| sampler_comparison | 比較サンプラー。深度テクスチャへのアクセスを調整します。 |
サンプラーはWebGPU APIで生成時にパラメータ化され、WGSLモジュールでは変更できません。
サンプラーはテクスチャ組み込み関数でのみ使用できます。
sampler sampler_comparison
6.6. AllTypes型
AllTypes型は、WGSLのすべての型の集合です。
AllTypes型はWGSLソースで記述する方法はありません。
すべての§ 6.9 事前宣言型・型ジェネレータ一覧を参照してください。
AllTypes型が存在する理由は、型チェック規則が、通常の値を含み得る句に適用されるようにするためです。 WGSLでは型も値の一種と定義し、式が型を表せるようにすることで、規則を一貫性のあるものにしています。
主な例はテンプレートパラメータであり、様々な文脈で型、列挙値、プレーン値など複数のものを表します。 特にtemplate_arg_expression文法規則はexpression文法非終端記号に展開されます。
6.7. 型エイリアス
type alias は、既存の型に対する新しい 名前を宣言する。 この宣言は モジュールスコープ に出現しなければならない。そして、その スコープ はプログラム全体である。
型Tが構造体型Sの型エイリアスとして定義された場合、 Sのメンバーのすべての属性を含むプロパティはTにも継承されます。
注: エイリアスされる型が value constructor の組み込み関数をサポートしている場合、 型エイリアスが スコープ内 であり、関数呼び出しが他の点で有効な場合は、 その関数を元の型名ではなくエイリアス名から呼び出すことができます。
'alias' ident '=' type_specifier
alias Arr = array< i32, 5 > ; alias RTArr = array< vec4< f32>> ; alias single = f32; // f32のエイリアス宣言 const pi_approx : single = 3.1415 ; fn two_pi () -> single { return single ( 2 ) * pi_approx ; }
6.8. 型指定子文法
§ 8.17 型式参照。
注:式も型を表すことができます。これはprimary_expression文法規則からtemplate_elaborated_identに展開され、括弧付き式経由でも表せます。
6.9. 事前宣言型・型ジェネレータ一覧
WGSLはfrexp、 modf、atomicCompareExchangeWeak組み込み関数の戻り値型も事前宣言しますが、WGSLソースで記述することはできません。
事前宣言型ジェネレータは下表の通りです:
| 事前宣言型ジェネレータ | 参照先 |
|---|---|
| array | § 6.2.9 配列型参照 |
| atomic | § 6.2.8 アトミック型参照 |
| mat2x2 |
§ 6.2.7 行列型参照(行列型の型エイリアスも一覧)
注:これらは値コンストラクタ式でも行列生成に使われます。 |
| mat2x3 | |
| mat2x4 | |
| mat3x2 | |
| mat3x3 | |
| mat3x4 | |
| mat4x2 | |
| mat4x3 | |
| mat4x4 | |
| ptr | § 6.4.3 参照型・ポインター型参照 |
| texture_1d | § 6.5.2 サンプルテクスチャ型参照 |
| texture_2d | |
| texture_2d_array | |
| texture_3d | |
| texture_cube | |
| texture_cube_array | |
| texture_multisampled_2d | § 6.5.3 マルチサンプルテクスチャ型参照 |
| texture_storage_1d | § 6.5.5 ストレージテクスチャ型参照 |
| texture_storage_2d | |
| texture_storage_2d_array | |
| texture_storage_3d | |
| vec2 |
§ 6.2.6 ベクトル型参照(ベクトル型の型エイリアスも一覧)
注:これらは値コンストラクタ式でもベクトル生成に使われます。 |
| vec3 | |
| vec4 |
7. 変数・値の宣言
値宣言は値に名前を付け、その値は宣言後不変です。
値宣言にはconst、override、let、仮引数宣言の4種があり、詳細は下記(§ 7.2 値の宣言)参照。
変数宣言は、値を格納するメモリ位置に名前を付けます。
ここに格納された値は、変数がread_writeアクセスモードの場合、更新可能です。
変数宣言はvarの1種ですが、アドレス空間やアクセスモードの組み合わせ指定が可能です。詳細は下記(§ 7.3 var宣言)参照。
注: 値宣言には対応するメモリ位置はありません。例えば、WGSL式で値へのポインターを作ることはできません。
関数定義外で宣言されたものはモジュールスコープとなり、その名前はプログラム全体でスコープ内です。
関数定義内で宣言されたものは関数スコープです。 名前は宣言直後の文から、宣言を囲む波括弧付き文リストの末尾まで有効です。 関数スコープ宣言は動的コンテキストです。
[...]は省略可能、...*は0回以上の繰り返し、...+は1回以上の繰り返しを示します。詳細な構文規則は各要素の該当節を参照してください。
// 特定の値宣言 const name [: type ] = initializer ; [ attribute ] * override name [: type ] [ = initializer ]; let name [: type ] = initializer ; // 一般的な変数宣言 [ attribute ] * var [ < address_space [, access_mode ] > ] name [: type ] [ = initializer ]; // 特定の変数宣言 // 関数スコープ var [ < function> ] name [: type ] [ = initializer ]; // モジュールスコープ var < private> name [: type ] [ = initializer ]; var < workgroup> name : type ; [ attribute ] + var < uniform> name : type ; [ attribute ] + var name : texture_type ; [ attribute ] + var name : sampler_type ; [ attribute ] + var < storage[, access_mode ] > name : type ;
これらの宣言は必ず型または初期化子を明示指定しなければなりません。 型・初期化子の両方指定も可能です。 これらの宣言は関連データ値の型、すなわち宣言の有効値型を決定します。 有効値型は以下の通りです:
-
型を明示指定した場合はその型。
-
そうでない場合、初期化子式の型が
Tなら:-
const宣言の場合は有効値型はT。 -
override、let、var宣言の場合、有効値型はTの具象化。
-
値宣言・変数宣言の各種は、初期化子式や有効値型に追加の制約を課す場合があります。
| 宣言 | 可変性 | スコープ | 実効値型1 | 初期化子のサポート | 初期化式2 | リソースインターフェイスの一部 |
|---|---|---|---|---|---|---|
| const | 不変 | モジュールまたは関数 | 構築可能(具体または抽象) | 必須 | const-expression | いいえ |
| override | 不変 | モジュール | 具体スカラー | 任意3 | const-expressionまたはoverride-expression | いいえ4 |
| let | 不変 | 関数 | 具体構築可能または ポインター型。 さらに、texture_and_sampler_let 機能が サポートされる場合、テクスチャまたはサンプラー型。 | 必須 | const-expression、override-expression、または runtime expression | いいえ |
|
var<storage, read> var<storage> | 不変 | モジュール | 具体ホスト共有可能 | 許可されない | はい。 storage バッファ | |
| var<storage, read_write>5,6 | 可変 | モジュール | 具体ホスト共有可能 | 許可されない | はい。 storage バッファ | |
| var<uniform> | 不変 | モジュール | 具体構築可能ホスト共有可能 | 許可されない | はい。 uniform バッファ | |
| var<immediate> | 不変 | モジュール | 具体構築可能ホスト共有可能。 配列および配列メンバーを含む構造体を除く | 許可されない | はい。 即時 データ | |
| var6 | 不変7 | モジュール | テクスチャ | 許可されない | はい。 テクスチャ リソース | |
| var | 不変 | モジュール | サンプラー | 許可されない | はい。 サンプラー リソース | |
| var<workgroup>6,8 | 可変 | モジュール | 具体プレーン型で、固定 フットプリントを持つもの9 | 許可されない10 | いいえ | |
| var<private> | 可変 | モジュール | 具体構築可能 | 任意10 | const-expressionまたはoverride-expression | いいえ |
| var<function> var | 可変 | 関数 | 具体構築可能 | 任意10 | const-expression、override-expression、または runtime expression | いいえ |
-
初期化子未指定の場合、パイプライン生成時に値を与える必要あり。
-
override宣言はシェーダインターフェースの一部だが、バインドリソースではない。
-
ストレージバッファやストレージテクスチャは、read以外のアクセスモードでは静的アクセスできません。WebGPU
createBindGroupLayout()参照。 -
アトミック型は可変ストレージバッファかworkgroup変数のみ可。
-
ストレージテクスチャはwriteやread_writeアクセスモードでデータが可変だが、変更はtextureStore組み込み関数のみ可能。変数自体は変更不可。
-
workgroupアドレス空間の変数はコンピュートシェーダステージでのみ静的アクセス可能。
-
初期化子がない場合、変数はデフォルト初期化される。
7.1. 変数と値の違い
変数宣言はWGSLモジュールで唯一可変なデータです。 値宣言は常に不変です。 変数は参照型やポインター型値の基礎となりますが、値宣言はポインターや参照型値の基礎にはなりません。
変数の利用は値宣言より一般にコストが高く、変数利用は変数に紐付くメモリ位置への読み出しや書き込み操作が追加されるためです。
一般に、次の順で宣言を使うのが推奨されます(上ほど推奨):
この順に使うことで、シェーダ全体の性能が最も高くなります。
7.2. 値の宣言
識別子が解決されて値宣言を指す場合、その識別子はその値を表します。
WGSLは複数種の値宣言を提供します。 それぞれの宣言種の値は、シェーダライフサイクルの異なるタイミングで確定します。 宣言種ごとに値が確定するタイミングは以下の通りです:
7.2.1. const宣言
const 宣言は、 シェーダー作成時に固定されるデータ値に対して名前を指定する。 各 const 宣言には初期化子が必要である。 const 宣言は、モジュールまたは関数スコープで宣言できる。 初期化子式はしなければならない、 const-expressionである。 const 宣言の型は、具体または 抽象の構築可能型でなければならない。 const 宣言は、実効値型が 抽象であってよい唯一の宣言である。
注: 抽象数値型はWGSLで記述できないため、型推論経由のみ使用可能です。
const a = 4 ; // 値が 4 の AbstractInt。 const b : i32= 4 ; // 値が 4 の i32。 const c : u32= 4 ; // 値が 4 の u32。 const d : f32= 4 ; // 値が 4 の f32。 const e = vec3( a , a , a ); // 値が (4, 4, 4) の AbstractInt の vec3。 const f = 2.0 ; // 値が 2 の AbstractFloat。 const g = mat2x2( a , f , a , f ); // AbstractFloat の mat2x2 の値: // ((4.0, 2.0), (4.0, 2.0))。 // AbstractInt a は AbstractFloat に変換される。 // AbstractFloat は AbstractInt に変換できない。 const h = array( a , f , a , f ); // 4 要素の AbstractFloat の array: // (4.0, 2.0, 4.0, 2.0)。
7.2.2. override宣言
override 宣言は、 パイプラインで上書き可能な定数値に対して名前を指定する。 override 宣言は、モジュールスコープでのみ宣言されなければならない。 パイプラインで上書き可能な定数の値は、 パイプライン作成 時に固定される。 値は、指定されている場合は WebGPU パイプライン作成メソッドによって提供される値であり、 そうでない場合は、その具体化された初期化子式の値である。 override 宣言の実効値型は、具体 スカラー型でなければならない。
初期化子式は省略可能です。 ある場合はoverride式でなければならず、これはパイプライン上書き可能定数のデフォルト値を表します。 初期化子がない場合、パイプライン生成時に値が与えられないとパイプライン生成エラーとなります。
宣言にid属性が付与されている場合、そのリテラルはパイプライン定数IDと呼ばれ、0〜65535の一意な整数でなければなりません。 2つのoverride宣言が同じパイプライン定数IDを使うことはできません。
アプリケーションは、パイプライン生成時にoverride宣言に対して独自の値を指定できます。 パイプライン生成APIは、上書き可能な定数からその定数型の値へのマッピングを受け付けます。 定数はパイプライン上書き可能定数識別子文字列によって識別されます。これは、パイプライン定数IDが指定されていればその10進表現、指定されていなければ宣言された名前です。
@id ( 0 ) override has_point_light : bool= true ; // アルゴリズム制御 @id ( 1200 ) override specular_param : f32= 2.3 ; // 数値制御 @id ( 1300 ) override gain : f32; // 必ず上書きされる必要あり override width : f32= 0.0 ; // APIレベルで"name"で指定 override depth : f32; // APIレベルで"depth"で指定。必ず上書き必要 override height = 2 * depth ; // デフォルト値(APIで未指定の場合)、他の上書き可能定数に依存
7.2.3. let宣言
let 宣言は、 実行時に文が実行されるたびに固定される値に対して名前を指定する。 let 宣言は関数スコープでのみ宣言されなければならず、そのため 動的コンテキストである。 let 宣言は初期化子式を持たなければならない。 その値は、初期化子の具体化された値である。 let 宣言の実効値型は、具体の構築可能型、または ポインター型のいずれかでなければならない。 texture_and_sampler_let 機能が サポートされる場合、 実効値型はテクスチャ型またはサンプラー型でもよい。
// 'blockSize' は i32 の値 1024 を表します。 let blockSize : i32= 1024 ; // 'row_size' は u32 の値 16u を表します。型は推論されます。 let row_size = 16u ;
7.3. var宣言
変数は、特定の格納可能型の値を保持できるメモリへの名前付き参照です。
変数には2つの型が関連付けられます:格納型(参照メモリに格納可能な値の型)と参照型(変数自体の型)。
変数の格納型がT、アドレス空間がAS、アクセスモードがAMなら、参照型はref<AS,T,AM>となります。
変数の格納型は常に具象型です。
変数宣言は以下を行います:
-
変数の名前を指定します。
-
変数のアドレス空間、格納型、およびアクセスモードを決定します。これらをまとめて変数の参照型と呼びます。
-
格納型は、変数宣言の実効値型です。
-
-
実行環境が、変数の有効期間の間、指定されたアドレス空間と指定されたアクセスモードで格納型の値のためにメモリを割り当てることを保証します。
-
変数がprivateまたはfunctionアドレス空間にある場合、初期化子式を持つことができます。存在する場合、初期化子は変数の格納型に評価されなければなりません。private変数の初期化子が存在する場合、それは定数式またはoverride式でなければなりません。functionやprivate以外のアドレス空間の変数は初期化子を持ってはなりません。
識別子が変数宣言に解決される場合、その識別子は変数のメモリの参照メモリビューを表す式であり、その型は変数の参照型です。§ 8.11 変数識別子式を参照してください。
プログラムソースで変数宣言のアドレス空間またはアクセスモードを指定する場合は、varキーワードの後ろにテンプレートリストとして記述します:
-
アドレス空間は最初に指定され、あらかじめ宣言されたアドレス空間列挙子のいずれかとなります。
-
アクセスモードは、存在する場合は2番目に指定され、あらかじめ宣言されたアドレスモード列挙子のいずれかとなります。
-
アクセスモードを指定する場合は、アドレス空間の指定が必須です。
-
private、storage、 uniform、workgroup、およびhandleアドレス空間内の変数は、モジュールスコープでのみ 宣言されなければならない。一方、functionアドレス空間内の変数は、関数スコープでのみ 宣言されなければならない。 アドレス空間は、handle および function を除くすべてのアドレス空間について指定しなければならない。 handle アドレス空間は指定してはならない。 function アドレス空間を指定することは任意である。
アクセスモードは常に 既定値を持ち、storage アドレス空間内の変数を除き、WGSL ソース内で指定してはならない。 § 14.3 アドレス空間を参照。
uniformアドレス空間内の変数は、uniform バッファ変数である。 その格納型は、ホスト共有可能な構築可能型でなければならず、 アドレス空間レイアウト制約を満たさなければならない。
storageアドレス空間内の変数は、storage バッファ変数である。 その格納型はホスト共有可能型でなければならず、 アドレス空間レイアウト制約を満たさなければならない。 その変数は、read またはread_write アクセスモードで宣言してよい。既定は read である。
immediateアドレス空間内の変数は、即時データ変数である。 その格納型は、ホスト共有可能な構築可能型でなければならず、 配列および配列メンバーを含む構造体を除く。 各エントリーポイントは、 多くとも 1 つの即時データ変数に静的にアクセスしなければならない。 immediate 変数の値は、WebGPU API コマンドエンコーダーによって記録されたsetImmediatesコマンドを介して設定され、 シェーダー実行中は一定のままである。 変数サイズは、パイプラインレイアウトのimmediateSize構成によって制限される。
テクスチャリソースは、 その有効値型がテクスチャ型である変数です。 これはモジュールスコープで宣言されます。 これは、テクスチャ内の基礎となるテクセルのグリッドにアクセスするために使用される、不透明なハンドルを保持します。 ハンドル自体はハンドルアドレス空間にあり、常に読み取り専用です。 多くの場合、基礎となるテクセルは読み取り専用であり、そのテクスチャ変数は不変であると言います。 書き込み専用ストレージテクスチャおよび読み書きストレージ テクスチャの場合、基礎となるテクセルは可変であり、慣例として、 そのテクスチャ変数は可変であると言います。
サンプラーリソースは、 実効値型がサンプラー型である変数である。 これはモジュールスコープで宣言され、 handleアドレス空間内に存在し、 不変である。
§ 13.3.2 リソースインターフェイスで説明されるように、uniform バッファ、storage バッファ、 テクスチャ、およびサンプラーは、シェーダーのリソースインターフェイスを形成する。
変数の生存期間は、 シェーダー実行中にメモリ位置がその変数に関連付けられている期間である。 モジュールスコープ変数の生存期間は、 シェーダーステージの実行全体である。 privateおよびfunctionアドレス空間内の変数には、各呼び出しごとに独立した版が存在する。 関数スコープ変数は 動的コンテキストである。 関数スコープ変数の生存期間は、そのスコープによって決まる:
-
制御がその変数の宣言に入ると開始する。
-
その名前が動的コンテキストのどの部分のスコープ内でもなくなったときに終了する。 すなわち、生存期間には、その名前がスコープ内にある間に呼び出された関数も含まれる。
2 つのリソース変数は重複するメモリ位置を持ってよいが、 それらの変数のいずれかが可変である場合、それは動的エラーである。 生存期間が重複するその他の変数は、重複するメモリ位置を持たない。 変数の生存期間が終了すると、そのメモリは別の変数に使用されてよい。
注: WGSL は、変数の内容が その変数の生存期間中にのみ観測可能であることを保証する。
private、function、 またはworkgroupアドレス空間内の変数が作成されるとき、その変数は初期値を持つことになる。 初期化子が指定されていない場合、初期値は既定の 初期値である。 初期値は次のように計算される:
-
function アドレス空間内の変数について:
-
private アドレス空間内の変数について:
-
そうでない場合、具体化された初期化子式を評価した結果である。 初期化子はoverride-expressionでなければならず、したがってその値は 遅くともパイプライン作成時までに固定される。
-
workgroup アドレス空間内の変数について:
その他のアドレス空間内の変数は、draw コマンドまたはdispatch コマンド内のバインディングによって設定されるリソースである。
次の WGSL の断片を考える:
var i : i32; // 初期値は 0。推奨されないスタイル。 loop { var twice : i32= 2 * i ; // 各反復で再評価される。 i ++ ; if i == 5 { break ; } }
i は値 0、1、2、3、4、5 を取り、変数 twice は
値 0、2、4、6、8 を取る。
次の WGSL の断片を考える:
x は変数であるため、それへのすべてのアクセスはロードおよびストア操作に変換される。
ただし、ブラウザーまたはドライバーのいずれかがこの中間表現を最適化し、
冗長なロードが削除されることが期待される。
var < private> decibels : f32; var < workgroup> worklist : array< i32, 10 > ; struct Params { specular : f32, count : i32} // Uniform バッファ。常に読み取り専用で、より制限的なレイアウト規則を持つ。 @group ( 0 ) @binding ( 2 ) var < uniform> param : Params ; // uniform バッファ // 読み書き用の storage バッファ @group ( 0 ) @binding ( 0 ) var < storage, read_write> pbuf : array< vec2< f32>> ; // テクスチャとサンプラーは常に "handle" 空間内にある。 @group ( 0 ) @binding ( 1 ) var filter_params : sampler;
// Storage バッファ @group ( 0 ) @binding ( 0 ) var < storage, read> buf1 : Buffer ; // 読み取り可、書き込み不可。 @group ( 0 ) @binding ( 0 ) var < storage> buf2 : Buffer ; // 読み取り可、書き込み不可。 @group ( 0 ) @binding ( 1 ) var < storage, read_write> buf3 : Buffer ; // 読み取りと書き込みの両方が可。 struct ParamsTable { weight : f32} // Uniform バッファ。常に読み取り専用で、より制限的なレイアウト規則を持つ。 @group ( 0 ) @binding ( 2 ) var < uniform> params : ParamsTable ; // 読み取り可、書き込み不可。
fn f () { var < function> count : u32; // function アドレス空間内の変数。 var delta : i32; // function アドレス空間内の別の変数。 var sum : f32= 0.0 ; // 初期化子を持つ function アドレス空間変数。 var pi = 3.14159 ; // 初期化子から f32 格納型を推論する。 }
7.4. 変数・値宣言の文法まとめ
| variable_decl '=' expression
| 'let' optionally_typed_ident '=' expression
| 'const' optionally_typed_ident '=' expression
'var' _disambiguate_template template_list ? optionally_typed_ident
ident ( ':' type_specifier ) ?
attribute * variable_decl ( '=' expression ) ?
'const' optionally_typed_ident '=' expression
| attribute * 'override' optionally_typed_ident ( '=' expression ) ?
8. 式
式は値の計算方法を指定します。
値式の種類ごとに、評価タイミングと表現力とのトレードオフがあります。 早い評価ほど操作が制約されますが、値の利用できる場所が増えます。このトレードオフにより、値宣言ごとに異なる柔軟性が生じます。 定数式とoverride式は、GPUの実行前に評価されるため、最終GPUコードには式の計算結果のみが必要です。 また、定数式はシェーダ生成時に評価されるため、override式より多くの場面で利用できます(例:関数スコープ変数の配列サイズ指定など)。 実行時式は、定数式でもoverride式でもない式です。 実行時式はシェーダ実行中GPU上で計算されます。 実行時式は利用できる文法要素が少ないですが、他の実行時値などより広い式から計算可能です。
8.1. 早期評価式
WGSLは実行時前に評価可能な2種類の式を定義します:
8.1.1. const式
シェーダ生成時に評価できる式をconst式と呼びます。 式がconst式となるのは、そのすべての識別子が以下のいずれかに解決される場合です:
const式の型は必ず型規則により生成時固定フットプリント型に決定されなければなりません。
注: 抽象型はconst式の型推論で用いられることがあります。
const式Eは、以下の場合のみ評価されます:
注:
この評価規則により、短絡評価演算子&&や||は右辺部分式の評価をガードします。ただし、部分式が静的型決定のために評価を要する場合は除きます。
const-expression は、WebGPU API メソッドを実装する CPU によって評価される場合がある。 したがって、AbstractFloat 値に対する演算の精度要件は、 WebAssembly [WASM-CORE-2] や ECMAScript [ECMASCRIPT] などの一般的な WebGPU ランタイム環境で 要求されるものより厳格ではない。 具体浮動小数点型(f32 など)の精度要件は、§ 15.7.4.1 具体浮動小数点式の精度で指定される。
例:(42) の解析:
-
42はAbstractInt値42です。 -
それを括弧で囲むことで、型がAbstractIntで値42の新しい式
(42)となります。
例:-5 の解析:
-
5はAbstractInt値5です。 -
その前に '
-' を付すことで、型がAbstractIntで値-5の新しい式-5となります。
例:-2147483648 の解析:
-
2147483648はAbstractInt値2147483648です。 この値は32ビット符号付き整数には収まりません。 -
その前に '
-' を付すことで、型がAbstractIntで値-2147483648の新しい式-2147483648となります。
例:const minint = -2147483648; の解析:
-
上述の通り、
-2147483648はAbstractInt値-2147483648です。 -
結果として、
minintはAbstractInt値-2147483648として宣言されます。
例:let minint = -2147483648; の解析:
-
上記のとおり、
-2147483648は AbstractInt 値 -2147483648 に評価される。 -
let 宣言には明示的な型がないため、オーバーロード解決が使用される。 適用されるオーバーロード候補は、AbstractInt から i32、u32、または f32 への実行可能な自動変換を使用する。 最もランクが低いものは i32 への変換であるため、 AbstractInt -2147483648 値は i32 値 -2147483648 に変換される。
-
その結果、
minintは i32 値 -2147483648 として宣言される。
例:false && (10i < i32(5 * 1000 * 1000 * 1000)) は次のように解析される:
-
式全体は const-expression である。
-
しかし、
&&演算子の短絡規則が適用される: 左辺はfalseに評価されるため、右辺は評価 されない。 -
i32(5 * 1000 * 1000 * 1000) の評価は、シェーダー作成エラーを 引き起こしていたはずである。これは、AbstractInt 値 5000000000 が i32 型をオーバーフローするためである。
例:false && array<u32, 1 + 2>(0, 1, 2)[0] == 0
-
式全体がconst式です。
-
型チェックでは
e1 : bool && e2 : boolが要求されます:-
falseはbool値です。 -
右辺の型チェックも進み、配列要素数式の
1 + 2が評価されます。
-
-
1 + 2はi32値3に評価されます。-
配列型は
array<u32, 3i>となります。
-
-
配列アクセス式や等価演算子は評価されません。
8.1.2. override式
パイプライン生成時に評価できる式はoverride式と呼びます。 式がoverride式となるのは、そのすべての識別子が以下のいずれかに解決される場合です:
注: すべてのconst式はoverride式でもあります。
const式以外のoverride式は、パイプライン生成時にのみ検証・評価され、APIで提供された値がoverride宣言に代入された後のみです。 override宣言がAPI経由で値を代入された場合、初期化子式があっても評価されません。 それ以外の場合、override式Eは以下の場合のみ評価されます:
-
Eが
GPUProgrammableStageで指定されたエントリポイント用シェーダの一部であり: -
次のいずれかが真である:
-
Eが値代入後のトップレベル式である場合
-
Eが式OuterEの部分式で、OuterE が評価され、かつOuterEの評価にEの評価が必要な場合
-
Eが式OuterEの部分式で、OuterEがパイプライン生成エラーを生じるためにEの評価が必要な場合 (例:整数除算)
-
注: すべてのoverride式がoverride宣言の初期化子として使えるわけではありません。なぜなら、初期化子は型規則で具象スカラー型に決定されなければならないためです。
例:override x = 42; の解析:
-
42はAbstractInt値42です。 -
override宣言は具象スカラー型が必要です。
例:let y = x + 1; の解析:
-
上記より、
xはi32型です。 -
x + 1はoverride宣言と整数リテラルから構成されているためoverride式です。 -
この式はi32型であり、パイプライン生成時に評価されます。 値は
xがパイプライン生成時に上書きされるかどうかに依存します。
例:vec3(x,x,x) の解析:
-
上記より、
xはoverride宣言で型はi32です。 -
vec3(x,x,x)は識別子がすべてoverride宣言に解決されるためoverride式です。
override a : i32= 0 ; override b = a / 0 ; // シェーダ生成エラー // cをoverrideしようとしても関係なく発生
override a : i32= 0 ; override b = 1 / a ; // bはfrag1シェーダの一部。frag1をパイプラインにコンパイルする場合: // * bがoverrideされていればエラーなし // * aが非ゼロ値にoverrideされていればエラーなし // * aが0かつbがoverrideされていなければパイプライン生成エラー @fragment fn frag1 () { _ = b ; } // bはfrag2シェーダには含まれない。frag2をパイプラインにコンパイルする場合: // bがoverrideされていなくてもaが0でもエラーにならない。 @fragment fn frag2 () { }
8.2. 不定値
限定された場合に、実行時式の評価が、その部分式に対して非対応値を使ったときに生じ得ます。
この場合、評価結果は式の静的型の不定値となり、 これは静的型における実装依存の任意値を意味します。
評価が繰り返しごとなど複数の動的コンテキストで生じる場合、個々に異なる値が生成されることがあります。 例:ループ各イテレーションごとに異なる値になる場合があります。
注: 型が浮動小数点型かつ実装がNaN値をサポートする場合、実行時の不定値はNaNとなる可能性があります。
fn fun () { var extracted_values : array< i32, 2 > ; const v = vec2< i32> ( 0 , 1 ); for ( var i : i32= 0 ; i < 2 ; i ++ ) { // 実行時式によってベクトルをインデックスし、ベクトルのインデックス範囲外の場合、 // ベクトル成分型の不定値が生成される。 let extract = v [ i + 5 ]; // この時点で 'extract' は i32 型の任意の値。 // 後で使うため保存。 extracted_values [ i ] = extract ; if extract == extract { // これは常に実行される } if extract < 2 { // 実行される場合もあるが、されない場合もある。 // 元のベクトル成分は 0 と 1 だが、 // 抽出された値がそれらとは限らない。 } } if extracted_values [ 0 ] == extracted_values [ 1 ] { // 実行される場合もあるが、されない場合もある。 } } fn float_fun ( runtime_index : u32) { const v = vec2< f32> ( 0 , 1 ); // 浮動小数点値のベクトル // 前の例と同様に、'float_extract' は不定値となる。 // 浮動小数点型なので、NaN になる場合がある。 let float_extract : f32= v [ runtime_index + 5 ]; if float_extract == float_extract { // これは *実行されない場合がある*、理由: // - 'float_extract' が NaN の場合があり、 // - NaN は他のどの浮動小数点数とも等しくない(他の NaN でさえも)。 } }
8.3. リテラル値式
| 前提条件 | 結論 | 説明 |
|---|---|---|
true: bool
| trueの論理値。
| |
false: bool
| falseの論理値。
| |
| eがサフィックスなし整数リテラルの場合 | e: AbstractInt | 抽象整数リテラル値。 |
| eがサフィックスなし浮動小数点リテラルの場合 | e: AbstractFloat | 抽象浮動小数点リテラル値。 |
eがiサフィックス付き整数リテラルの場合
| e: i32 | 32ビット符号付き整数リテラル値。 |
eがuサフィックス付き整数リテラルの場合
| e: u32 | 32ビット符号なし整数リテラル値。 |
eがfサフィックス付き浮動小数点リテラルの場合
| e: f32 | 32ビット浮動小数点リテラル値。 |
eがhサフィックス付き浮動小数点リテラルの場合
| e: f16 | 16ビット浮動小数点リテラル値。 |
8.4. 括弧付き式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e : T | ( e ) : T
| eとして評価される。 式を周囲のテキストから分離するために括弧を使う。 |
8.5. 合成値分解式
この節では、構成要素を持つ合成値から構成要素を取得する式、 および、合成値へのメモリビューから構成要素への参照を取得する式について説明します。 ここでは、合成値またはそのメモリビューを基底と呼びます。
方法は2つあります:
- 名前付き要素式
-
基底 Bの式の後にピリオド
'.'(U+002D)と要素名を続ける。 - インデックス式
-
基底式の後に
'['(U+005B)、インデックス式、']'(U+005D)を続ける。
これら2つの構文は、component_or_swizzle_specifier文法規則で表されます。
-
基底が行列型、または行列へのメモリビューの場合、Nは行列型の列数です。
インデックス値が有効範囲インデックスでない場合、範囲外インデックスです。 範囲外インデックスは多くの場合プログラムの欠陥であり、多くの場合エラーとなります。 詳細は下記参照。
さらに、ベクトル型は別のベクトルの構成要素から新しいベクトル値を作るスウィズル構文もサポートします。
8.5.1. ベクトル要素アクセス式
ベクトルの構成要素へは:
-
配列添字(例:
v[2])でアクセス -
または、スウィズル名(コンテキスト依存名)を使い、便宜的な各名称で元ベクトルの構成要素を指定してアクセス
-
色ベース:
r,g,b,aはベクトル要素0, 1, 2, 3に対応。 -
次元ベース:
x,y,z,wはベクトル要素0, 1, 2, 3に対応。
-
便宜名は . 記法を使用してアクセスされる。(例:color.bgra)。
便宜文字列は混在させてはならない。たとえば、
.rybw は使用できない。
便宜文字は、ベクトルの末尾を越えた成分にアクセスしてはならない。
便宜文字列は、必要に応じて文字を重複させることも含め、任意の順序で適用できる。 提供される文字数は、1 から 4 の間でなければならない。 すなわち、便宜文字を使用すると、スカラー型または有効なベクトル型のみを生成できる。
結果の型は、提供された文字数に依存する。vec4<f32> を仮定すると、
| アクセサ | 結果型 |
|---|---|
| r | f32
|
| rg | vec2<f32>
|
| rgb | vec3<f32>
|
| rgba | vec4<f32>
|
var a : vec3< f32> = vec3< f32> ( 1. , 2. , 3. ); var b : f32= a . y ; // b = 2.0 var c : vec2< f32> = a . bb ; // c = (3.0, 3.0) var d : vec3< f32> = a . zyx ; // d = (3.0, 2.0, 1.0) var e : f32= a [ 1 ]; // e = 2.0
8.5.1.1. ベクトル単一要素選択
| 事前条件 | 結論 | 説明 |
|---|---|---|
| e: vecN<T> |
e.x: Te .r: T
|
e の第 1 成分を選択する
これは単一文字のswizzleである。 |
| e: vecN<T> |
e.y: Te .g: T
|
e の第 2 成分を選択する
これは単一文字のswizzleである。 |
| e: vecN<T> N は 3 または 4 である |
e.z: Te .b: T
|
e の第 3 成分を選択する
これは単一文字のswizzleである。 |
| e: vec4<T> |
e.w: Te .a: T
|
e の第 4 成分を選択する
これは単一文字のswizzleである。 |
| e: vecN<T> i: i32 or u32 T は具体である | e[i]: T |
ベクトルの i 番目の成分を選択する 第 1 成分はインデックス i=0 にある。 i が範囲 [0,N-1] の外にある場合:
|
| e: vecN<T> i: i32 or u32 T は抽象である i はconst-expressionである | e[i]: T |
ベクトルの i 番目の成分を選択する 第 1 成分はインデックス i=0 にある。 i が範囲 [0,N-1] の外にある場合、シェーダー作成エラーである。 注: 抽象ベクトル値 e が、const-expressionではない式によって インデックス指定される場合、そのベクトルはインデックスが適用される前に 具体化される。 |
8.5.1.2. ベクトル複数要素選択
この節の式はすべて複数文字のスウィズルです。 それぞれが他のベクトルの構成要素からベクトルを生成します。
複数文字のスウィズルは代入の左辺には使えません: 代入の左辺は参照型でなければなりませんが、複数文字スウィズル式は常にベクトル型の値を生成します。
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
e: vecN<T> または
ptr<AS,vecN<T,AM>> Iは x, y, z, wのいずれかJは x, y, z, wのいずれかAMは readまたはread_write |
e.IJ: vec2<T> | 第1要素e.I、第2要素e.Jの2要素ベクトルを生成。zはNが3または4の時のみ有効。wはNが4の時のみ有効。eがポインターの場合、間接参照後にロード規則が適用される。 |
|
e: vecN<T> または
ptr<AS,vecN<T,AM>> Iは r, g, b, aのいずれかJは r, g, b, aのいずれかAMは readまたはread_write |
e.IJ: vec2<T> | 第1要素e.I、第2要素e.Jの2要素ベクトルを生成。bはNが3または4の時のみ有効。aはNが4の時のみ有効。eがポインターの場合、間接参照後にロード規則が適用される。 |
|
e: vecN<T> または
ptr<AS,vecN<T,AM>> I, J, Kは x, y, z,
wのいずれかAMは readまたはread_write |
e.IJK: vec3<T> | 第1要素e.I、第2要素e.J、第3要素e.Kの3要素ベクトルを生成。zはNが3または4の時のみ有効。wはNが4の時のみ有効。eがポインターの場合、間接参照後にロード規則が適用される。 |
|
e: vecN<T> または
ptr<AS,vecN<T,AM>> I, J, Kは r, g, b,
aのいずれかAMは readまたはread_write |
e.IJK: vec3<T> | 第1要素e.I、第2要素e.J、第3要素e.Kの3要素ベクトルを生成。bはNが3または4の時のみ有効。aはNが4の時のみ有効。eがポインターの場合、間接参照後にロード規則が適用される。 |
|
e: vecN<T> または
ptr<AS,vecN<T,AM>> I, J, K, Lは x, y,
z, wのいずれかAMは readまたはread_write |
e.IJKL:
vec4<T> | 第1要素e.I、第2要素e.J、第3要素e.K、第4要素e.Lの4要素ベクトルを生成。zはNが3または4の時のみ有効。wはNが4の時のみ有効。eがポインターの場合、間接参照後にロード規則が適用される。 |
|
e: vecN<T> または
ptr<AS,vecN<T,AM>> I, J, K, Lは r, g,
b, aのいずれかAMは readまたはread_write |
e.IJKL:
vec4<T> | 第1要素e.I、第2要素e.J、第3要素e.K、第4要素e.Lの4要素ベクトルを生成。bはNが3または4の時のみ有効。aはNが4の時のみ有効。eがポインターの場合、間接参照後にロード規則が適用される。 |
8.5.1.3. ベクトルメモリビューからの要素参照
この節の式は、ベクトル全体のメモリビューからベクトルの単一要素のメモリビューを生成します。
WGSLの型規則により、これらの式は以下の場合に利用できます:
ベクトル要素への書き込みアクセスは、ベクトルに関連付けられたメモリ位置全体をアクセスする場合があります。
注: これは、異なるinvocationでベクトルメモリの異なる要素にアクセスし、少なくとも一方が書き込みアクセスの場合は同期が必要となることを意味します。§ 17.11 同期組み込み関数参照。
| 前提条件 | 結論 | 説明 |
|---|---|---|
| r: ref<AS,vecN<T>,AM> または ptr<AS,vecN<T>,AM> |
r.x: ref<AS,T,AM>r .r: ref<AS,T,AM> | メモリビューrが参照するベクトルの第1要素への参照を取得。 結果参照の元変数はrの元変数と同じ。 |
| r: ref<AS,vecN<T>,AM> または ptr<AS,vecN<T>,AM> |
r.y: ref<AS,T,AM>r .g: ref<AS,T,AM> | メモリビューrが参照するベクトルの第2要素への参照を取得。 結果参照の元変数はrの元変数と同じ。 |
| r: ref<AS,vecN<T>,AM> または ptr<AS,vecN<T>,AM> Nは3または4 |
r.z: ref<AS,T,AM>r .b: ref<AS,T,AM> | メモリビューrが参照するベクトルの第3要素への参照を取得。 結果参照の元変数はrの元変数と同じ。 |
| r: ref<AS,vec4<T>,AM> または ptr<AS,vec4<T>,AM> |
r.w: ref<AS,T,AM>r .a: ref<AS,T,AM> | メモリビューrが参照するベクトルの第4要素への参照を取得。 結果参照の元変数はrの元変数と同じ。 |
| r: ref<AS,vecN<T>,AM> または ptr<AS,vecN<T>,AM> i: i32 または u32 |
r[i] : ref<AS,T,AM> |
メモリビューrが参照するベクトルのi番目要素への参照を取得
iが範囲[0,N-1]外の場合:
結果参照の元変数はrの元変数と同じ。 |
8.5.2. 行列要素アクセス式
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
e: matCxR<T> i: i32 または u32 Tは具象型 | e[i]: vecR<T> |
eのi番目の列ベクトルを返す。
iが範囲[0,C-1]外の場合:
|
|
e: matCxR<T> i: i32 または u32 Tは抽象型 iはconst式 | e[i]: vecR<T> |
eのi番目の列ベクトルを返す。
iが範囲[0,C-1]外ならシェーダ生成エラー。 注: 抽象行列値eをconst式でない式でインデックスすると、インデックス適用前に具象化されます。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
r: ref<AS,matCxR<T>,AM>
または ptr<AS,matCxR<T>,AM> i: i32 または u32 | r[i] : ref<AS,vecR<T>,AM> |
メモリビューrが参照する行列のi番目の列ベクトルへの参照を取得
iが範囲[0,C-1]外の場合:
結果参照の元変数はrの元変数と同じ。 |
8.5.3. 配列要素アクセス式
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
e: array<T,N> i: i32 または u32 Tは具象型 | e[i] : T |
e配列値のi番目の要素の値を返す。
iが範囲[0,N-1]外の場合:
|
|
e: array<T,N> i: i32 または u32 Tは抽象型 iはconst式 | e[i] : T |
e配列値のi番目の要素の値を返す。
iが範囲[0,N-1]外ならシェーダ生成エラー。 注: 抽象配列値eをconst式でない式でインデックスすると、インデックス適用前に具象化されます。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
r: ref<AS,array<T,N>,AM> または ptr<AS,array<T,N>,AM> i: i32 または u32 | r[i] : ref<AS,T,AM> |
メモリビューrが参照する配列のi番目の要素への参照を取得
iが範囲[0,N-1]外の場合:
結果参照の元変数はrの元変数と同じ。 |
| r: ref<AS,array<T>,AM> または ptr<AS,array<T>,AM> i: i32 または u32 | r[i] : ref<AS,T,AM> |
実行時サイズ配列のメモリビューrが参照する配列のi番目の要素への参照を取得
実行時に配列がN要素なら、iが範囲[0,N-1]外の場合は不正メモリ参照評価となる。 iが符号付き整数で0未満の場合:
結果参照の元変数はrの元変数と同じ。 |
8.5.4. 構造体要素アクセス式
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
Sは構造体型 MはSのメンバー名(型T) e: S | e.M: T | e構造体値のメンバー名Mの値を返す。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
Sは構造体型 MはSのメンバー名(型T) r: ref<AS,S,AM> または ptr<AS,S,AM> | r.M: ref<AS,T,AM> | 構造体メモリビューから、識別子名Mの構造体メンバーへの参照を取得。 結果参照の元変数はrの元変数と同じ。 |
8.6. 論理式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e: T TはboolまたはvecN<bool> | !e: T
| 論理否定。
eがfalseなら結果はtrue、eがtrueならfalse。
Tがベクトルなら構成要素ごと。
|
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e1: bool e2: bool | e1 || e2: bool
| 短絡"or"。e1またはe2がtrueなら結果はtrue。
e1がfalseの場合のみe2を評価。
|
| e1: bool e2: bool | e1 && e2: bool
| 短絡"and"。e1とe2がともにtrueなら結果はtrue。
e1がtrueの場合のみe2を評価。
|
| e1: T e2: T TはboolまたはvecN<bool> | e1 | e2: T
| 論理"or"。Tがベクトルなら構成要素ごと。e1とe2を両方評価。 |
| e1: T e2: T TはboolまたはvecN<bool> | e1 & e2: T
| 論理"and"。Tがベクトルなら構成要素ごと。e1とe2を両方評価。 |
8.7. 算術式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e: T TはAbstractInt, AbstractFloat, i32, f32, f16, vecN<AbstractInt>, vecN<AbstractFloat>, vecN<i32>, vecN<f32>, または vecN<f16> | -e: T
| 符号反転。Tがベクトル型の場合構成要素ごとに適用。 Tが整数スカラー型でeが最小負値の場合、結果はe。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e1 : T e2 : T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> | e1 + e2 : T
|
加算。Tがベクトル型の場合構成要素ごとに適用。
Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:
|
| e1 : T e2 : T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> | e1 - e2 : T
|
減算。Tがベクトル型の場合構成要素ごとに適用。
Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:
|
| e1 : T e2 : T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> | e1 * e2 : T
|
乗算。Tがベクトル型の場合構成要素ごとに適用。
Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:
|
| e1 : T e2 : T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> | e1 / e2 : T
|
除算。Tがベクトル型の場合構成要素ごとに適用。
Tが符号付き整数スカラー型の場合:
注: 切り捨て動作の保証には符号なし除算より多くの演算が必要になる場合があります。 両被演算子が同符号と判明している場合は符号なし除算を使うこと。 Tが符号なし整数スカラー型の場合:
Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:
|
| e1 : T e2 : T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> | e1 % e2 : T
|
剰余。Tがベクトル型の場合構成要素ごとに適用。
Tが符号付き整数スカラー型の場合、e1とe2を1回ずつ評価し、結果は:
注: 非ゼロの場合、結果はe1と同符号。 注: 一貫した動作保証には符号なし剰余より多くの演算が必要になる場合があります。 Tが符号なし整数スカラー型の場合、結果は:
Tが浮動小数点型の場合、結果はe1 - e2 * trunc(e1 / e2)。 Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:
|
| 前提条件 | 結論 | 意味 |
|---|---|---|
| SはAbstractInt, AbstractFloat, f32, f16, i32, u32のいずれか VはvecN<S> es: S ev: V | ev + es: V
| ev + V(es)
|
es + ev: V
| V(es) + ev
| |
ev - es: V
| ev - V(es)
| |
es - ev: V
| V(es) - ev
| |
ev * es: V
| ev * V(es)
| |
es * ev: V
| V(es) * ev
| |
ev / es: V
| ev / V(es)
| |
es / ev: V
| V(es) / ev
| |
ev % es: V
| ev % V(es)
| |
es % ev: V
| V(es) % ev
|
| 前提条件 | 結論 | 意味 |
|---|---|---|
| e1, e2: matCxR<T> TはAbstractFloat, f32, f16 | e1 + e2: matCxR<T> | 行列加算:結果は構成要素ごとに計算され、結果の列iはe1[i] + e2[i] |
e1 - e2: matCxR<T>
| 行列減算:結果は構成要素ごとに計算され、結果の列iはe1[i] - e2[i] | |
| m: matCxR<T> s: T TはAbstractFloat, f32, f16 | m * s: matCxR<T> | 構成要素ごとのスケーリング:(m *
s)[i][j]はm[i][j] * s
|
s * m: matCxR<T> | 構成要素ごとのスケーリング:(s *
m)[i][j]はm[i][j] * s
| |
| m: matCxR<T> v: vecC<T> TはAbstractFloat, f32, f16 | m * v: vecR<T> | 線形代数の行列-列ベクトル積:
結果の構成要素iは
dot(transpose(m)[i],v)
|
|
m: matCxR<T> v: vecR<T> TはAbstractFloat, f32, f16 | v * m: vecC<T> | 線形代数の行ベクトル-行列積: transpose(transpose(m) *
transpose(v))
|
| e1: matKxR<T> e2: matCxK<T> TはAbstractFloat, f32, f16 | e1 * e2: matCxR<T> | 線形代数の行列積。 |
8.8. 比較式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e1: T e2: T SはAbstractInt, AbstractFloat, bool, i32, u32, f32, f16 TはSまたはvecN<S> TBはTがベクトルの場合vecN<bool>、それ以外はbool | e1 == e2: TB
| 等価。Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: T SはAbstractInt, AbstractFloat, bool, i32, u32, f32, f16 TはSまたはvecN<S> TBはTがベクトルの場合vecN<bool>、それ以外はbool | e1 != e2: TB
| 非等価。Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> TBはTがベクトルの場合vecN<bool>、それ以外はbool | e1 < e2: TB
| より小さい。Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> TBはTがベクトルの場合vecN<bool>、それ以外はbool | e1 <= e2: TB
| 以下。Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> TBはTがベクトルの場合vecN<bool>、それ以外はbool | e1 > e2: TB
| より大きい。Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: T SはAbstractInt, AbstractFloat, i32, u32, f32, f16 TはSまたはvecN<S> TBはTがベクトルの場合vecN<bool>、それ以外はbool | e1 >= e2: TB
| 以上。Tがベクトル型の場合構成要素ごと。 |
8.9. ビット式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e: T SはAbstractInt, i32, u32のいずれか TはSまたはvecN<S> | ~e : T
| eに対するビット単位の補数。 結果の各ビットはeの対応するビットの反転値。 Tがベクトル型の場合構成要素ごと。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e1: T e2: T SはAbstractInt, i32, u32のいずれか TはSまたはvecN<S> | e1 | e2: T
| ビット単位OR。Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: T SはAbstractInt, i32, u32のいずれか TはSまたはvecN<S> | e1 & e2: T
| ビット単位AND。Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: T SはAbstractInt, i32, u32のいずれか TはSまたはvecN<S> | e1 ^ e2: T
| ビット単位排他的OR。Tがベクトル型の場合構成要素ごと。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e1: T e2: TS Sはi32またはu32 TはSまたはvecN<S> TSはTがSのときu32、そうでなければvecN<u32> | e1 << e2: T
|
左シフト(シフト値は具体的な値):
e1を左シフトし、下位ビットにはゼロを挿入、上位ビットは破棄。 シフトするビット数はe2の値(e1のビット幅でmod)。
両方がシェーダ実行開始前に分かっている場合、結果はオーバーフローしない必要:
Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: TS TはAbstractIntまたはvecN<AbstractInt> TSはTがAbstractIntのときu32、そうでなければvecN<u32> | e1 << e2: T
|
左シフト(シフト値は抽象値):
e1を左シフトし、下位ビットにはゼロを挿入、上位ビットは破棄。 シフトするビット数はe2の値。 e1の最上位e2+1個のビットは必ず同じ値でなければならない。そうでない場合はオーバーフロー。 注: この条件は、破棄されるビットが元値の符号ビットと同じで、結果値の符号ビットとも同じである必要があることを意味します。 Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: TS Sはi32またはu32 TはSまたはvecN<S> TSはTがSのときu32、そうでなければvecN<u32> | e1 >> e2: T |
右シフト(シフト値は具体的な値)。
e1を右シフトし、下位ビットを破棄。 Sが符号なし型なら、上位ビットにはゼロを挿入。 Sが符号付き型なら:
シフトするビット数はe2(e1のビット幅でmod)。 e2がe1のビット幅以上の場合:
Tがベクトル型の場合構成要素ごと。 |
| e1: T e2: TS TはAbstractIntまたはvecN<AbstractInt> TSはTがAbstractIntのときu32、そうでなければvecN<u32> | e1 >> e2: T |
右シフト(抽象値)。
e1を右シフトし、下位ビットを破棄。 e1が負なら挿入ビットは1、結果も負。そうでなければ0。 シフトするビット数はe2の値。 Tがベクトル型の場合構成要素ごと。 |
8.10. 関数呼び出し式
関数呼び出し式は、呼び出し先関数が戻り値型を持つ関数呼び出しを実行します。 呼び出し関数が値を返さない場合は、関数呼び出し文を使います。 § 9.5 関数呼び出し文参照。
8.11. 変数識別子式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| vは識別子で、解決先が アドレス空間ASに宣言された 格納型T、 アクセスモードAMの スコープ内変数 | v: ref<AS,T,AM> | 変数名vのメモリへの参照が結果。 |
8.12. 仮引数式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| aは識別子で、解決先が スコープ内の仮引数宣言(型T) | a: T | 関数呼び出し時の呼び出し元オペランドで渡された値。 |
8.13. アドレス取得式
アドレス取得演算子は参照を対応するポインタに変換します。
| 前提条件 | 結論 | 説明 |
|---|---|---|
| r: ref<AS,T,AM> |
&r: ptr<AS,T,AM>
|
結果は、参照値rと同じメモリビューに対応するポインタ値。
rが不正メモリ参照なら、結果ポインタも不正メモリ参照。 rがベクトル要素への参照のときシェーダ生成エラー。 |
8.14. 間接参照式
間接参照演算子はポインタを対応する参照に変換します。
| 前提条件 | 結論 | 説明 |
|---|---|---|
| p: ptr<AS,T,AM> |
*p: ref<AS,T,AM>
|
結果は、ポインタ値pと同じメモリビューに対応する参照値。
pが不正メモリ参照なら、結果参照も不正メモリ参照。 |
8.15. 値宣言の識別子式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| cは識別子で、解決先が スコープ内のconst宣言(型T) | c: T | 初期化式を評価した値。 式はconst式で、シェーダ生成時に評価される。 |
| cは識別子で、解決先が スコープ内のoverride宣言(型T) | c: T |
パイプライン生成時に定数IDに値が指定された場合、その値。
パイプラインごとに異なる場合あり。
それ以外の場合は初期化式の評価値。 パイプライン上書き可能定数はモジュールスコープに現れるので、評価はシェーダ実行開始前。 注:
API呼び出しで初期値未指定かつ |
| cは識別子で、解決先が スコープ内のlet宣言(型T) | c: T | 初期化式を評価した値。
let宣言は関数本体内に現れ、初期化は制御フローが宣言に到達するたびに評価される。 |
8.16. 列挙式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| eは識別子で、解決先が事前宣言列挙値 であり、列挙型Eに属する | e : E | § 6.3.1 事前宣言列挙値参照 |
8.17. 型式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| tは識別子で、解決先が事前宣言型 | t : AllTypes | § 6.9 事前宣言型・型ジェネレーターまとめ参照 |
| aは識別子で、解決先が型エイリアス | a : AllTypes | さらに、aはエイリアス先の型を表します。 |
| sは識別子で、解決先が構造体型宣言 | s : AllTypes | さらに、sはその構造体型を表します。 |
|
tgは識別子で、解決先が型ジェネレーター
e1: T1 | tg _template_args_start e1, ..., eN _template_args_end : AllTypes |
各型ジェネレーターは必要なテンプレートパラメータの要件を独自に定めており、
テンプレートパラメータが結果型決定方法を定義します。
式e1~eNはテンプレートパラメータ。 例:型式 § 6.9 事前宣言型・型ジェネレーターまとめに型ジェネレーター一覧あり。 注: この2つのバリエーションは、eNの後にカンマがあるかどうかのみが異なります。 |
| tg _template_args_start e1, ..., eN, _template_args_end : AllTypes |
8.18. 式文法まとめ
識別子がcall_phraseの最初のトークンの場合、次のいずれかです:
宣言とスコープの規則により、これらの名前は常に区別されます。
expression ( ',' expression ) * ',' ?
'[' expression ']' component_or_swizzle_specifier ?
| multiplicative_expression multiplicative_operator unary_expression
| additive_expression additive_operator multiplicative_expression
| shift_expression _less_than shift_expression
| shift_expression _greater_than shift_expression
| shift_expression _less_than_equal shift_expression
| shift_expression _greater_than_equal shift_expression
binary_and_expression '&' unary_expression
| short_circuit_or_expression '||'
relational_expression
8.19. 演算子の優先順位と結合規則
この節全体は非規範的です。
右辺WGSL式の演算子の優先順位と結合規則は、まとめると文法から現れます。右辺式は演算子をグループ化して整理し、次の図で示されるように構成されます:
可読性を高めるために、以下のグループは他のグループとは結合しません:
-
ショートサーキット OR (自身および関係と弱く結合可能)
-
ショートサーキット AND (自身および関係と弱く結合可能)
そして以下のグループは自身とは結合しません:
これらのグループセクション両方を結合するには、関係を明示的に設定するため括弧が必要です。次の例では、これらの規則がコメント内で式を無効にする場所を示します:
let a = x & ( y ^ ( z | w )); // 無効: x & y ^ z | w let b = ( x + y ) << ( z >= w ); // 無効: x + y << z >= w let c = x < ( y > z ); // 無効: x < y > z let d = x && ( y || z ); // 無効: x && y || z
優先順位によって式の暗黙の括弧が制御され、より強い結合の演算子は弱い優先順位の演算子と一緒に現れる場合、括弧で囲まれているかのように動作します。例えば、乗算演算子が加算より強い場合、式
a + b * c から (a + (b * c)) が推論されます。同様に、結合規則によってこれらの暗黙の括弧の方向が制御されます。例えば、左から右への結合は
a + b + c 式から ((a + b) + c) を推論し、右から左への結合は * * a 式から
(* (* a)) を推論します。
次の表は、演算子の優先順位、結合規則、結合対象をまとめており、強いものから弱いものへと並べています。結合対象欄には、各演算子のより強い式が記載されています。例えば「All above」と書かれている場合、この演算子はそれより強い式すべてを含むことができます。一方、「Unary」と書かれている場合、単項より弱くこの演算子より強いものは括弧が必要です。この欄は演算子を線形に並べるために必要です。
| 名前 | 演算子 | 結合規則 | 結合対象 |
|---|---|---|---|
| 括弧付き | (...)
| ||
| 主 | a(), a[], a.b
| 左から右 | |
| 単項 | -a, !a, ~a, *a, &a
| 右から左 | 上記すべて |
| 乗算 | a*b, a/b, a%b
| 左から右 | 上記すべて |
| 加算 | a+b, a-b
| 左から右 | 上記すべて |
| シフト | a<<b, a>>b
| 括弧が必要 | 単項 |
| 関係 | a<b, a>b, a<=b, a>=b,
a==b, a!=b
| 括弧が必要 | 上記すべて |
| ビット単位 AND | a&b
| 左から右 | 単項 |
| ビット単位 XOR | a^b
| 左から右 | 単項 |
| ビット単位 OR | a|b
| 左から右 | 単項 |
| ショートサーキット AND | a&&b
| 左から右 | 関係 |
| ショートサーキット OR | a||b
| 左から右 | 関係 |
9. 文
文は、実行を制御するプログラムの断片です。 文は通常、順次実行されますが、制御フロー文によって非順次に実行される場合があります。
9.1. 複合文
複合文は、中括弧で囲まれた0個以上の文の並びです。 それらの文の中に宣言が含まれる場合、その識別子は、 次の文の開始から複合文の終わりまでスコープ内になります。
continuing_compound_statementは、複合文の特殊な形式であり、 continuing文の本体を構成し、最後にbreak-if文を任意で許容します。
9.2. 代入文
代入は、式を評価し、必要に応じてメモリに格納(つまり変数の内容を更新)します。
lhs_expression ( '=' | compound_assignment_operator ) expression
| '_' '=' expression
演算子トークンの左側のテキストを左辺、 演算子トークンの右側の式を右辺と呼びます。
9.2.1. 単純代入
代入は、
単純代入である場合、
左辺が式であり、演算子がイコール('=')トークンです。
この場合、右辺の値が左辺で参照されるメモリに書き込まれます。
| 事前条件 | 文 | 説明 |
|---|---|---|
| e: T, Tは具体的な構築可能型, r: ref<AS,T,AM>, ASは書き込み可能なアドレス空間, アクセスモード AMはwriteまたはread_write | r = e |
rを評価し、次にeを評価し、eで計算された値を
rが参照するメモリ位置に書き込みます。
注: 参照が無効なメモリ参照の場合、書き込みが実行されない場合や、 予期しないメモリ位置に書き込まれる場合があります。 |
最も単純な場合、左辺は変数名です。 その他のケースについては§ 6.4.8 参照値とポインタ値の形成を参照してください。
struct S { age : i32, weight : f32} var < private> person : S ; fn f () { var a : i32= 20 ; a = 30 ; // 'a' の内容を 30 に置き換える。 person . age = 31 ; // person 変数の age フィールドに 31 を書き込む。 var uv : vec2< f32> ; uv . y = 1.25 ; // uv の第2成分に 1.25 を格納。 let uv_x_ptr : ptr< function, f32> = & uv . x ; * uv_x_ptr = 2.5 ; // uv の第1成分に 2.5 を格納。 var sibling : S ; // person 変数の内容を sibling 変数にコピーする。 sibling = person ; }
9.2.2. ダミー代入
代入が
ダミー代入である場合、
左辺がアンダースコア('_')トークンです。
この場合、右辺は評価され、その後無視されます。
| 事前条件 | 文 | 説明 |
|---|---|---|
| e: T, Tは構築可能型、ポインタ型、テクスチャ型、またはサンプラー型 | _ = e |
eを評価します。
注: 得られた値は保存されません。
|
ダミー代入は以下のような用途で便利です:
-
戻り値がある関数を呼び出し、結果の値が不要であることを明確に表現する場合。
-
静的アクセスにより、変数を シェーダのリソースインターフェイスの一部として確立する場合。
注: バッファ変数のストア型が構築可能でない場合(例:atomic型やランタイムサイズ配列を含む場合)には、 その内容へのポインタを使ってください。
var < private> counter : i32; fn increment_and_yield_previous () -> i32{ let previous = counter ; counter = counter + 1 ; return previous ; } fn user () { // counter をインクリメントするが、結果は使わない。 _ = increment_and_yield_previous (); }
struct BufferContents { counter : atomic< u32> , data : array< vec4< f32>> } @group ( 0 ) @binding ( 0 ) var < storage> buf : BufferContents ; @group ( 0 ) @binding ( 1 ) var t : texture_2d< f32> ; @group ( 0 ) @binding ( 2 ) var s : sampler; @fragment fn shade_it () -> @location ( 0 ) vec4< f32> { // buf, t, s がシェーダインターフェイスの一部であることを宣言するが、何も利用しない。 _ = & buf ; _ = t ; _ = s ; return vec4< f32> (); }
9.2.3. 複合代入
代入は、 複合代入である場合、 左辺が式であり、 演算子がcompound_assignment_operatorsのいずれかです。
各文の型要件・意味論・挙動は、以下の表のように複合代入が展開されるものとして定義されています。ただし、
-
参照式e1は一度だけ評価され、
-
e1の参照型は 必ず read_writeの アクセスモードでなければなりません。
| 文 | 展開 |
|---|---|
| e1 += e2 | e1 = e1 + (e2) |
| e1 -= e2 | e1 = e1 - (e2) |
| e1 *= e2 | e1 = e1 * (e2) |
| e1 /= e2 | e1 = e1 / (e2) |
| e1 %= e2 | e1 = e1 % (e2) |
| e1 &= e2 | e1 = e1 & (e2) |
| e1 |= e2 | e1 = e1 | (e2) |
| e1 ^= e2 | e1 = e1 ^ (e2) |
| e1 >>= e2 | e1 = e1 >> (e2) |
| e1 <<= e2 | e1 = e1 << (e2) |
注: 構文上、複合代入が ダミー代入になることはできません。
注: 参照e1は一度評価されますが、基となるメモリには2回アクセスされます。 まず読み取りアクセスで古い値を取得し、 次に書き込みアクセスで更新値を保存します。
var < private> next_item : i32= 0 ; fn advance_item () -> i32{ next_item += 1 ; // next_item に 1 を加算。 return next_item - 1 ; } fn bump_item () { var data : array< f32, 10 > ; next_item = 0 ; // data[0] に 5.0 を加算、advance_item() は一度だけ呼ばれる。 data [ advance_item ()] += 5.0 ; // この時点で next_item は 1。 } fn precedence_example () { var value = 1 ; // 複合代入の右辺は独立した式として評価される。 value *= 2 + 3 ; // value = value * (2 + 3); と同じ。 // 'value' は 5 になる。 }
e1+=e2;
は次のように書き換えられます。
ここで識別子{ let p = &(e1); *p = *p + (e2); }
pは、プログラム内の他の識別子と異なるものを選びます。
evは次のように書き換えられます。[c] +=e2;
ここで識別子{ let p = &(ev); let c0 =c; (*p)[c0] = (*p)[c0] + (e2); }
c0とpは、プログラム内の他の識別子と異なるものを選びます。
9.3. インクリメント文とデクリメント文
インクリメント文は、変数の内容に1を加算します。 デクリメント文は、変数の内容から1を減算します。
式は、具体な整数スカラーの格納型およびread_write アクセスモードを持つ参照に評価されなければならない。
| 事前条件 | 文 | 説明 |
|---|---|---|
| r : ref<AS,T,read_write>, T は具体な整数スカラーである | r++
| r によって参照されるメモリの内容に 1 を加算する。
r += T(1) と同じ |
| r : ref<AS,T,read_write>, T は具体な整数スカラーである | r--
| r によって参照されるメモリの内容から 1 を減算する。
r -= T(1) と同じ |
9.4. 制御フロー
制御フロー文によってプログラムが非順次に実行される場合があります。
9.4.1. if文
if文は、条件式の評価に基づいて最大1つの複合文を条件付きで実行します。
if文はif節、0個以上のelse if節、任意のelse節で構成されます。
'else' 'if' expression compound_statement
'else' compound_statement
型規則の事前条件:
各ifおよびelse if節の式は必ずbool型でなければなりません。
if文の実行方法は以下の通りです:
-
if節に関連付けられた条件を評価します。 結果がtrueの場合、 制御は(条件式の直後の)最初の複合文に移ります。 -
そうでない場合、次の
else if節(存在する場合)の条件をテキスト順で評価し、 結果がtrueの場合、制御は対応する複合文に移ります。-
この挙動は、いずれかの条件が
trueになるまで、全てのelse if節に対して繰り返されます。
-
-
どれも
trueと評価されない場合は、else節(存在する場合)に関連付けられた複合文に制御が移ります。
9.4.2. switch文
switch文は、セレクタ式の評価に応じて、case節のいずれか、またはdefault節に制御を移します。
attribute * 'switch' expression switch_body
attribute * '{' switch_clause + '}'
'case' case_selectors ':' ? compound_statement
'default' ':' ? compound_statement
case_selector ( ',' case_selector ) * ',' ?
'default'
case節は、'case'トークンの後にカンマ区切りのcaseセレクタのリストと、複合文形式の本体が続くものです。
default単独節は、'default'トークンの後に、複合文形式の本体が続きます。
default節は、以下のいずれかです:
各 switch 文は、ちょうど 1 つの default 句 を持たなければならない。
'default'
トークンは、単一の case_selector リスト内に
複数回出現してはならない。
型規則の 前提条件: 単一の switch 文について、セレクター式およびすべての case セレクター式は、同じでなければならない 具象整数スカラー型でなければならない。
case_selectors 内の式は、const 式 でなければならない。
同じ switch 文内の 2 つの異なるケースセレクタ式は、同じ値を持ってはならない。
セレクタ値が case_selector リスト内の式の値と等しい場合、 制御はその case 句 の本体に移される。 セレクタ値がいずれのケースセレクタ値とも等しくない場合、制御は default 句 の本体に移される。
制御が句の本体の末尾に達すると、制御は switch 文の直後の最初の文に移る。
句の本体内の文の 1 つが 宣言 である場合、 それは 複合文 内の宣言が従う通常の スコープ および 存続期間 の規則に従う。 すなわち、本体は文の並びであり、そのうちの 1 つが宣言である場合、 その宣言のスコープは、並びにおける次の文の開始から 本体の末尾まで及ぶ。 宣言は到達した時点で実行され、 変数 または 値 の新しいインスタンスを生成し、それを初期化する。
var a : i32; let x : i32= generateValue (); switch x { case 0 : { // コロンは省略可能 a = 1 ; } default { // defaultは最後でなくてもよい a = 2 ; } case 1 , 2 , { // 複数のセレクタ値を使える a = 3 ; } case 3 , { // 末尾のカンマは省略可能 a = 4 ; } case 4 { a = 5 ; } }
const c = 2 ; var a : i32; let x : i32= generateValue (); switch x { case 0 : { a = 1 ; } case 1 , c { // caseセレクタに定数式を使える a = 3 ; } case 3 , default { // defaultキーワードを他節と組み合わせ可能 a = 4 ; } }
9.4.3. loop文
loop文は、ループ本体を繰り返し実行します。 ループ本体は複合文として指定されます。 ループ本体の各実行を反復と呼びます。
この繰り返しは、breakまたは return文によって中断される場合があります。
オプションで、ループ本体の末尾にcontinuing文を配置できます。
動的エラーは、 loopが無限回の反復を実行する場合に発生します。 これはループの早期終了、他の非局所的な効果、あるいはデバイスロスにつながることがあります。
ループ本体内の文の1つが宣言である場合、 通常のスコープとライフタイム規則が適用されます。 すなわち、ループ本体は文の並びであり、その中に宣言がある場合、その宣言のスコープは並びの次の文の開始からループ本体の終わりまで拡張します。 宣言は到達するたびに実行されるため、各反復ごとに新しい変数または値のインスタンスが作成され、再初期化されます。
注:
loop文は特殊な構文であり、一般的にはforやwhile文を使うことを推奨します。loop文は他のシェーダ言語との最大の違いのひとつです。
この設計は、コンパイル済みコードでよく見られるループイディオムを直接表現しています。 特に、ループ更新文をループ本体の末尾に配置することで、本体内で定義された値を自然に利用できます。
-
<1> 初期化はループの前に記載されています。
var a : i32= 2 ; let step : i32= 1 ; for ( var i : i32= 0 ; i < 4 ; i += step ) { if ( i % 2 == 0 ) { continue ; } a *= 2 ; }
var a : i32= 2 ; var i : i32= 0 ; loop { if i >= 4 { break ; } let step : i32= 1 ; i = i + step ; if i % 2 == 0 { continue ; } a = a * 2 ; }
var a : i32= 2 ; var i : i32= 0 ; loop { if i >= 4 { break ; } let step : i32= 1 ; if i % 2 == 0 { continue ; } a = a * 2 ; continuing { // <2> i = i + step ; } }
-
<2> continue 構文は
loopの末尾に配置されます。
9.4.4. for文
attribute * 'for' '(' for_header ')' compound_statement
for_init ? ';' expression ? ';' for_update ?
for ステートメントは、複合ステートメント に含まれる
ループ ステートメントの構文糖衣です。
一般的に、for ステートメントは以下の形式を取ります。
for (initializer;condition;update_part) {body}
条件式が存在する場合、for ステートメントは次の形式のループに展開されます:
{条件式が存在しない場合、
initializer ;
loop {
if !(condition) { break; }
body
continuing { update_part }
}
}
for ステートメントは次の形式のループに展開されます:
{
initializer ;
loop {
body
continuing { update_part }
}
}
さらに:
-
initializerが空でない場合、最初の スコープ 内で追加的に実行され、最初の イテレーション の前に実行されます。 initializer 内の宣言のスコープは、ループ本体の終了まで拡張されます。 -
型ルールの事前条件: 条件が空でない場合、必須として bool 型の式である必要があります。
-
条件が存在する場合、ループ本体を実行する直前に評価されます。 条件が false の場合、§ 9.4.6 Break ステートメント が実行され、ループの実行を終了します。 このチェックは各ループイテレーションの開始時に行われます。
-
-
update_partが空でない場合、ループ構造の最後に continuing ステートメントとなります。 -
デシュガリングの 過程で、
body内で宣言された識別子は、update_part内の全ての識別子がデシュガリング前と同じ宣言に 解決 されるように必要に応じて名前が変更されます。
for ループの initializer は、ループが実行される前に一度だけ実行されます。
宣言 が initializer に現れる場合、その
識別子 は
スコープ内 にあり、body の終了まで有効です。
body 内の宣言とは異なり、この宣言は各イテレーションで再初期化されません。
condition、body、および update_part はこの順序で実行され、ループの
イテレーション を形成します。
body は特別な形式の 複合ステートメント です。
body 内の宣言の識別子は、次のステートメントの開始からbody の終了まで
スコープ内 にあります。
この宣言は到達するたびに実行されるため、各新しいイテレーションは変数または定数の新しいインスタンスを作成し、それを再初期化します。
var a : i32= 2 ; for ( var i : i32= 0 ; i < 4 ; i ++ ) { if a == 0 { continue ; } a = a + 2 ; }
変換後:
var a : i32= 2 ; { // i 変数用に新しいスコープを導入 var i : i32= 0 ; loop { if ! ( i < 4 ) { break ; } if a == 0 { continue ; } a = a + 2 ; continuing { i ++ ; } } }
var a : i32= 2 ; for ( var i : i32= 0 ; ; i ++ ) { if a == 0 { continue ; } if i == 4 { break ; } a = a + 2 ; }
変換後:
var a : i32= 2 ; { // i 変数用に新しいスコープを導入 var i : i32= 0 ; loop { // 注意: デシュガリングで if 文は追加されません。 if a == 0 { continue ; } if i == 4 { break ; } a = a + 2 ; continuing { i ++ ; } } }
動的エラーは、 for ループが無制限の イテレーション を実行する場合に発生します。 これにより、ループの早期終了、他の非局所的影響、または デバイスの喪失 さえ引き起こされる可能性があります。
9.4.5. while文
attribute * 'while' expression compound_statement
while文は、条件でパラメータ化されるループの一種です。 各ループ反復の開始時に、 真偽値条件が評価されます。 条件が偽のとき、whileループは実行を終了します。 そうでない場合は反復の残りが実行されます。
型規則の事前条件: 条件は必ずbool型でなければなりません。
whileループはloop文またはfor文の構文糖とみなせます。 以下の文形式は同等です:
-
whilecondition{body_statements} -
loop { if !condition{break;}body_statements} -
for (;condition;) {body_statements}
動的エラーは、 whileループが無限回の反復を実行する場合に発生します。 これはループの早期終了、他の非局所的な効果、あるいはデバイスロスにつながることがあります。
9.4.6. break文
'break'
break文は、最も近い囲みのループ またはswitch文の本体直後へ制御を移し、 そのループまたはswitch文の実行を終了します。
break文は必ず
loop、
for、
while、
およびswitch文の中だけで使われなければなりません。
break文は、ループのcontinuing文から抜け出すような位置に置いてはなりません。
代わりにbreak-if文を使用してください。
var a : i32= 2 ; var i : i32= 0 ; loop { let step : i32= 1 ; if i % 2 == 0 { continue ; } a = a * 2 ; continuing { i = i + step ; if i >= 4 { break ; } // 無効。代わりに break-if を使用すること。 } }
9.4.7. break-if文
'break' 'if' expression ';'
break-if文は真偽値条件を評価します。 条件がtrueであれば、最も近い囲みのloop文の本体直後に制御が移り、そのループの実行が終了します。
型規則の事前条件: 条件は必ずbool型でなければなりません。
注: break-if文はcontinuing 文の本体の最後の文としてのみ現れることができます。
var a : i32= 2 ; var i : i32= 0 ; loop { let step : i32= 1 ; if i % 2 == 0 { continue ; } a = a * 2 ; continuing { i = i + step ; break if i >= 4 ; } }
9.4.8. continue文
'continue'
continue 文は、最も内側を囲む ループ において制御を移す:
-
そのループの本体の末尾にある continuing 文が存在する場合は、そこへ前方に移す。
-
そうでない場合は、ループ本体の最初の文へ後方に移し、次の 反復 を開始する。
continue 文は、loop、for または while 文の中でのみ使用しなければならない。
continue 文は、囲んでいる continuing 文へ制御を移すような位置に
配置してはならない。
(continuing 文へ分岐する場合、それは 前方 分岐である。)
continue 文は、対象とする continuing 文で使用される宣言を飛び越えて
制御を移すような位置に配置してはならない。
注記: continue は、continuing 文の中に
ネストされた別のループ内で制御フローを移すために使用される場合にのみ、continuing 文の中で使用できる。
すなわち、continue を使用して、現在実行中の continuing 文の先頭へ制御を
移すことはできない。
var i : i32= 0 ; loop { if i >= 4 { break ; } if i % 2 == 0 { continue ; } // <3> let step : i32= 2 ; continuing { i = i + step ; } }
-
<3> この
continueは、continuing構文で使用されるstepの宣言を 飛び越えてしまうため無効である
9.4.9. continuing文
'continuing' continuing_compound_statement
continuing文は、ループ反復の末尾で実行される複合文を指定します。 この構文は任意です。
複合文は、どのネストレベルでもreturnを含んではなりません。
9.4.10. return文
'return' expression ?
return 文は、現在の関数の実行を終了する。 関数が エントリポイント である場合、 現在のシェーダ呼び出しが 終了する。 そうでない場合、評価は現在の関数呼び出しの 呼び出し位置 の 評価の後に続く次の式または文から継続する。
関数が 戻り値 型 を持たない場合、return 文は 省略可能である。そのような関数に対して return 文が提供される場合、それは値を 供給してはならない。 そうでない場合、式が存在しなければならず、これは 戻り値 と呼ばれる。 この場合、この関数呼び出しの呼び出し位置はその戻り値に評価される。 戻り値の型は、関数の戻り値型と一致しなければならない。
9.4.11. discard文
discard ステートメントは、その呼び出しを
ヘルパー呼び出しに変換し、
フラグメント出力を破棄する。
discard ステートメントは、しなければならない、フラグメントシェーダーステージ内でのみ使用されること。
より正確には、discard ステートメントを実行すると、する:
-
現在の呼び出しをヘルパー呼び出しに変換し、かつ
-
現在のフラグメント出力が、GPURenderPipeline 内の下流で処理されることを防ぐ。
discard ステートメントより前に実行されたステートメントだけが、する観測可能な効果を持つ。
注: discard ステートメントは、任意の
フラグメントステージ内の関数によって実行されることがあり、その効果は同じである:
フラグメント出力は破棄される。
@group ( 0 ) @binding ( 0 ) var < storage, read_write> will_emit_color : u32; fn discard_if_shallow ( pos : vec4< f32> ) { if pos . z < 0.001 { // ここが実行される場合、will_emit_color変数は1にはならない。 // ヘルパー呼び出しはshared memoryに書き込まないため。 discard ; } will_emit_color = 1 ; } @fragment fn main ( @builtin ( position) coord_in : vec4< f32> ) -> @location ( 0 ) vec4< f32> { discard_if_shallow ( coord_in ); // ヘルパー関数がdiscard文を実行しなかった場合のみ、値1をセットし赤色を出す。 will_emit_color = 1 ; return vec4< f32> ( 1.0 , 0.0 , 0.0 , 1.0 ); }
9.5. 関数呼び出し文
関数呼び出し文は関数呼び出しを実行します。
呼び出される関数にmust_use属性がある場合、シェーダ生成エラーとなります。
注: 関数が値を返す場合でも、 その関数にmust_use属性がなければ、 その値は無視されます。
9.6. 文の文法まとめ
statement規則は、関数本体内のほとんどの場所で使える文に一致します。
さらに、特定の文は非常に特定の文脈でのみ使用できます:
9.7. 文の挙動解析
9.7.1. 規則
制御フローに影響する一部の文は、特定のコンテキストでのみ有効です。 例えば、continue は loop、for、または while の外では無効です。 さらに、均一性解析(§ 15.2 Uniformity参照)では、制御フローが複数の異なる方法で文を抜ける場合を判定する必要があります。
これら両方の目的は、文の実行挙動を要約するシステムによって達成されます。挙動解析は各文を、文の評価が完了した後に実行が進む可能な方法の集合へとマッピングします。 値や式に対する型解析と同様に、挙動解析もボトムアップで進行します:まず基本的な文の挙動を判定し、それから上位の構造に対して結合規則を適用して挙動を決定します。
挙動とは、次の要素を持つ集合です:
-
Return
-
Break
-
Continue
-
Next
これらは複合文を抜ける方法に対応しており、キーワードによるものか、次の文へ進む("Next")ことによるものです。
「s: B」は、s が挙動に関する規則を満たし、挙動 B を持つことを表します。
各関数について:
-
その本体は、これらの規則によって妥当な文でなければならない。
各関数に 挙動 を割り当てる。これは、 その本体の 挙動(本体を 通常の文として扱う)であり、任意の "Return" を "Next" に置き換えたものである。 上記の規則の結果として、関数の挙動は常に {} または {Next} のいずれかである。
挙動解析は、各文および関数について 空でない 挙動 を決定できなければ ならない。
| 文 | 前提条件 | 結果の挙動 |
|---|---|---|
| 空文 | {Next} | |
| {s} | s: B | B |
|
s1 s2
注: s1 はしばしばセミコロンで終わる。 | s1: B1 B1 に Next がある s2: B2 | (B1∖{Next}) ∪ B2 |
| s1: B1 B1 に Next がない s2: B2 | B1 | |
| var x:T; | {Next} | |
| let x = e; | {Next} | |
| var x = e; | {Next} | |
| x = e; | {Next} | |
| _ = e; | {Next} | |
| f(e1, ..., en); | f の挙動 B がある | B |
| return; | {Return} | |
| return e; | {Return} | |
| discard; | {Next} | |
| break; | {Break} | |
| break if e; | {Break, Next} | |
| continue; | {Continue} | |
| const_assert e; | {Next} | |
| if e s1 else s2 |
s1: B1 s2: B2 | B1 ∪ B2 |
| loop {s1 continuing {s2}} |
s1: B1 s2: B2 B1 = {Return} B2 に {Continue, Return} がない | {Return} |
|
s1: B1 s2: B2 B1 ≠ {Return} B2 に {Continue, Return} がない (B1 ∪ B2) に Break がない | (B1 ∪ B2)∖{Continue, Next} | |
|
s1: B1 s2: B2 B1 ≠ {Return} B2 に {Continue, Return} がない (B1 ∪ B2) に Break がある | (B1 ∪ B2 ∪ {Next})∖{Break, Continue} | |
| switch e {case c1: s1 ... case cn: sn} |
s1: B1 ... sn: Bn (B1 ∪ ... ∪ Bn) に Break がない | B1 ∪ ... ∪ Bn |
|
s1: B1 ... sn: Bn (B1 ∪ ... ∪ Bn) に Break がある | (B1 ∪ ... ∪ Bn ∪ {Next})∖Break |
注: ∪は集合の和演算、∖は集合の差分演算です。
注: 空文の場合は、loop の本体が空の場合や、for
ループに初期化や更新文がない場合に該当します。
この解析の目的のため:
-
forループはデシュガー処理される(§ 9.4.4 For Statement参照) -
whileループはデシュガー処理される(§ 9.4.5 While Statement参照) -
loop {s}はloop {s continuing {}}として扱う -
else分岐のないif文は空の else 分岐(else {})があるものとして扱う;これにより 挙動 に Next が加わる -
else if分岐を持つif文は、入れ子の単純なif/else文として扱う -
switch_clause が
defaultで始まる場合は、switch_clause がcase _:で始まる場合と同様に動作する
各built-in functionは{Next}のbehaviorを持つ。 また、上記の表に記載されていない各演算子の適用も、同じオペランドを持つ関数呼び出しとして、関数の{Next}のbehaviorを持つかのような同じbehaviorを持つ。
関数のmustは、上記の規則を満たさなければならない。
注記: 上記の規則から、ループの挙動は {Next}、{Return}、または {Next,Return} となることが示唆される。
注記: 式のbehaviorの解析は不要である。なぜなら、式は常に{Next}であるか、既に解析された関数がエラーを発生させているためである。
9.7.2. 補足
この節は情報提供のみであり、規範的ではありません。
挙動解析によって、プログラムは以下のような理由で拒否されることがあります (上記の要件を再掲):
-
関数の本体(通常の文として扱う)が{Next, Return}に含まれない挙動を持つ場合。
-
戻り値型を持つ関数の本体が{Return}でない挙動を持つ場合。
-
continuingブロックの挙動にContinueやReturnが含まれる場合。
-
明らかに無限ループとなるものが空集合の挙動セットとなり、無効となる場合。
この解析は、呼び出しグラフをボトムアップで解析することで線形時間で実行できます(関数呼び出しの挙動は関数のコードに依存するため)。
9.7.3. 例
以下は、この解析の実例です:
fn simple () -> i32{ var a : i32; return 0 ; // 挙動: {Return} a = 1 ; // 有効、静的に到達不可能なコード。 // 文の挙動: {Next} // 全体の挙動(逐次文による): {Return} return 2 ; // 有効、静的に到達不可能なコード。挙動: {Return} } // 関数の挙動: {Return}
fn nested () -> i32{ var a : i32; { // 複合文の開始。 a = 2 ; // 挙動: {Next} return 1 ; // 挙動: {Return} } // 複合文全体の挙動は{Return} a = 1 ; // 有効、静的に到達不可能なコード。 // 文の挙動: {Next} // 全体の挙動(逐次文による): {Return} return 2 ; // 有効、静的に到達不可能なコード。挙動: {Return} }
fn if_example () { var a : i32= 0 ; loop { if a == 5 { break ; // 挙動: {Break} } // if複合文全体の挙動: {Break, Next}, // ifには暗黙的な空のelseがある a = a + 1 ; // 有効、前の文の挙動に"Next"があるため } }
fn if_example () { var a : i32= 0 ; loop { if a == 5 { break ; // 挙動: {Break} } else { continue ; // 挙動: {Continue} } // if複合文全体の挙動: {Break, Continue} a = a + 1 ; // 有効、静的に到達不可能なコード。 // 文の挙動: {Next} // 全体の挙動: {Break, Continue} } }
fn if_example () { var a : i32= 0 ; loop { // if e1 s1 else if e2 s2 else s3 // は次と同一: // if e1 else { if e2 s2 else s3 } if a == 5 { break ; // 挙動: {Break} } else if a == 42 { continue ; // 挙動: {Continue} } else { return ; // 挙動: {Return} } // if複合文全体の挙動: // {Break, Continue, Return} } // ループ複合文全体の挙動 {Next, Return} } // 関数全体の挙動 {Next}
fn switch_example () { var a : i32= 0 ; switch a { default : { break ; // 挙動: {Break} } } // 挙動: {Next}、switchはBreakをNextに置き換える a = 5 ; // 有効、前の文にNextがあるため }
fn invalid_infinite_loop () { loop { discard ; // 挙動 { Next } } // 無効、ループ全体の挙動は{ }。 }
fn conditional_continue () { var a : i32; loop { if a == 5 { break ; } // 挙動: {Break, Next} if a % 2 == 1 { // 有効、前の文にNextがあるため continue ; // 挙動: {Continue} } // 挙動: {Continue, Next} a = a * 2 ; // 有効、前の文にNextがあるため continuing { // 有効、continuing文の挙動は{Next} // これに{Break, Continue, Return}は含まれない a = a + 1 ; } } // ループ全体の挙動は{Next}、 // "Continue"と"Next"は吸収され、 // "Break"は"Next"に置き換えられる }
fn redundant_continue_with_continuing () { var a : i32; loop { if a == 5 { break ; } continue ; // 有効。冗長で、次の文へ分岐するだけ。 continuing { a = a + 1 ; } } }
fn continue_end_of_loop_body () { for ( var i : i32= 0 ; i < 5 ; i ++ ) { continue ; // 有効。冗長で、 // ループ本体の末尾に分岐するだけ。 } // 挙動: {Next}、 // ループは"Continue"を吸収し、 // "for"ループは必ず"Next"を加える }
forループはloopと条件付きbreakにデシュガーされます。前述の例の通り、条件付きbreakは挙動 {Break,
Next}を持ち、これによりループの挙動に"Next"が加えられます。
fn missing_return () -> i32{ var a : i32= 0 ; if a == 42 { return a ; // 挙動: {Return} } // 挙動: {Next, Return} } // エラー: Nextは戻り値型を持つ関数の本体には無効 //
fn continue_out_of_loop () { var a : i32= 0 ; if a > 0 { continue ; // 挙動: {Continue} } // 挙動: {Next, Continue} } // エラー: 関数本体内ではContinueは無効
continueをbreakに置き換えても、同じ理由で無効です。
10. アサーション
アサーションは、 ブール条件が満たされていることを検証するためのチェックです。
WGSLでは、アサーションの種類は一つ、 定数アサーションのみ定義されています。
'const_assert' expression
型規則の前提条件: 式は必ずbool型でなければなりません。
10.1. 定数アサーション文
const アサーション文は、式が false に評価される場合に シェーダ生成エラー を生成する アサーション である。
式は const 式 でなければならない。
この文は、シェーダ内で 静的アクセス
の条件を満たすことができるが、
それ以外ではコンパイル済みシェーダに影響を与えない。
const アサーションは、
モジュールスコープ に、または
関数スコープ の
文 として出現できる。
const x = 1 ; const y = 2 ; const_assert x < y ; // モジュールスコープで有効。 const_assert ( y != 0 ); // 括弧は省略可能。 fn foo () { const z = x + y - 2 ; const_assert z > 0 ; // 関数内で有効。 let a = 3 ; const_assert a != 0 ; // 無効、式は定数式でなければならない。 }
11. 関数
関数は、呼び出されたときに計算処理を実行します。
関数は次のいずれかの方法で呼び出されます:
-
関数呼び出し式の評価による。§ 8.10 関数呼び出し式参照。
-
関数呼び出し文の実行による。§ 9.5 関数呼び出し文参照。
-
エントリーポイント関数は、WebGPUの実装によって シェーダーステージの処理を パイプライン内で実行するために呼び出されます。§ 13 エントリーポイント参照。
WGSLの関数は、定義順序に制限がなく、使用より後に定義しても構いません。 そのため、関数プロトタイプや前方宣言は不要であり、その方法もありません。
関数には2種類あります:
-
組み込み関数はWGSLの実装によって提供され、 常にWGSLモジュールで利用可能です。 § 17 組み込み関数参照。
-
ユーザー定義関数はWGSLモジュール内で宣言されます。
11.1. ユーザー定義関数の宣言
関数宣言は、ユーザー定義関数を作成します。指定内容は以下の通りです:
-
オプションの属性のセット。
-
関数名。
-
仮引数リスト:0個以上の仮引数宣言の順序付き列。 それぞれに属性を付与でき、カンマ区切りで括弧で囲みます。
-
オプションの戻り値型(属性付与可)。
-
関数本体。 これは関数が呼び出されたときに実行される文の集合です。
関数宣言は、モジュールスコープ でのみ出現しなければならない。 関数名は、プログラム全体で スコープ内 にある。
注記: 各 ユーザ定義関数 は、1 つの オーバーロード のみを持つ。
仮引数 宣言 は、関数を呼び出す際に 提供しなければならない 値に対する 識別子 名および型を指定する。 仮引数は属性を持つことができる。 § 11.2 関数呼び出し を参照のこと。 識別子の スコープ は、 関数本体 である。 ある関数に対する 2 つの仮引数は、同じ名前を持ってはならない。
注記: 一部の組み込み関数は、引数が 抽象数値 型 であることを許可する場合がある。 ただし、この機能は現在のところユーザ宣言関数に対しては サポートされていない。
戻り値型 は、指定される場合、 構築可能 で なければならない。
WGSL は、関数宣言に適用できる以下の属性を定義する:
WGSLでは、関数の仮引数・戻り値型に付与できる属性は以下の通りです:
'fn' ident '(' param_list ? ')' ( '->' attribute * template_elaborated_ident ) ?
// add_two関数の宣言。 // 仮引数は i と b の2つ。 // 戻り値型は i32。 // 本体はreturn文を持つ。 fn add_two ( i : i32, b : f32) -> i32{ return i + 2 ; // 仮引数は本体内で利用可能。 } // コンピュートシェーダーのエントリーポイント関数 'main'。 // 戻り値型は指定なし。 // add_two関数を呼び出し、 // 結果を'six'という値に格納。 @compute @workgroup_size ( 1 ) fn main () { let six : i32= add_two ( 4 , 5.0 ); }
11.2. 関数呼び出し
関数呼び出しは、 関数を実行する文または式です。
関数呼び出しを含む関数は、呼び出し元関数または呼び出し元と呼ばれます。 実際に呼び出される関数は呼び出し先関数または呼び出し先です。
関数呼び出しは:
-
呼び出し先関数の名前を指定し、
-
括弧で囲み、カンマ区切りの引数値式のリストを与えます。
関数呼び出しは、呼び出される関数 にある 仮引数 の数と同じ数の 実引数値を供給しなければならない。 各実引数値は、位置に従って、対応する仮引数と同じ型に評価しなければならない。
まとめると、関数呼び出し時は:
呼び出し先関数は次のようにreturnされます:
詳細な手順は:
-
関数呼び出しの引数値が評価されます。 評価順は左から右です。
-
呼び出し先がユーザー定義の場合、 呼び出し先関数の関数スコープ変数ごとにメモリが割り当てられます。
-
初期化は § 7.3 var宣言で記載された通りに行われます。
-
-
呼び出し先関数の仮引数には、位置で一致する関数呼び出しの引数値が割り当てられます。 例えば、呼び出し先関数の最初の仮引数は、呼び出し元の最初の引数値となります。
-
呼び出し先関数へ制御が移ります。 ユーザー定義関数の場合、本体の最初の文から実行されます。
-
呼び出し先関数はreturnされるまで実行されます。
-
制御が呼び出し元関数に戻り、呼び出し先の実行が解除されます。 戻り値を持つ場合、その値が関数呼び出し式の値となります。
関数呼び出しの位置は、呼び出し位置と呼ばれます。これは、トークンのうち call_phrase構文規則の解析インスタンスで最初のものの位置です。 呼び出し位置は動的コンテキストの一種です。 そのため、同じテキスト上の位置が複数の呼び出し位置となることもあります。
注: フラグメントシェーダー内の関数呼び出しが、クアッド内の全ての呼び出しが discardされた場合、 returnしない可能性があります。 この場合、制御は呼び出し元関数に戻りません。
11.3. const関数
const属性付きで宣言された関数は、 シェーダー生成時に評価できます。 これらの関数は定数関数と呼ばれます。 これらへの呼び出しは定数式の一部として利用できます。
関数内に定数式でない 式やconst宣言でない宣言が含まれている場合、 シェーダー生成エラーとなります。
注: const属性は ユーザー定義関数には付けられません。
const first_one = firstLeadingBit ( 1234 + 4567 ); // 12に評価される // first_oneの型はi32、 // firstLeadingBitはAbstractIntに対応しないため @id ( 1 ) override x : i32; override y = firstLeadingBit ( x ); // 定数式は // override式でも利用可能 // firstLeadingBit(x)はこの文脈では定数式ではない fn foo () { var a : array< i32, firstLeadingBit ( 257 ) > ; // 定数関数は // パラメータがすべて定数式なら // 定数式内で利用可能 }
11.4. 関数に対する制約
-
-
構築可能型
-
ポインタ型
-
テクスチャ型
-
サンプラ型
-
-
各関数呼び出しの実引数は、対応する 関数引数の型に評価しなければならない。
注: 再帰はどの宣言種にも循環が許可されていないため禁止されています。
fn bar ( p : ptr< function, f32> ) { } fn baz ( p : ptr< private, i32> ) { } fn bar2 ( p : ptr< function, f32> ) { let a = &*&* ( p ); bar ( p ); // 有効 bar ( a ); // 有効 } fn baz2 ( p : ptr< storage, f32> ) { } struct S { x : i32} @group ( 0 ) @binding ( 0 ) var < storage> ro_storage : f32; @group ( 0 ) @binding ( 1 ) var < storage, read_write> rw_storage : f32; var usable_priv : i32; var unusable_priv : array< i32, 4 > ; fn foo () { var usable_func : f32; var unusable_func : S ; var i32_func : i32; let a_priv = & usable_priv ; let b_priv = a_priv ; let c_priv = &*& usable_priv ; let d_priv = & ( unusable_priv . x ); let e_priv = d_priv ; let a_func = & usable_func ; let b_func = & unusable_func ; let c_func = & ( * b_func )[ 0 ]; let d_func = c_func ; let e_func = &* a_func ; baz ( & usable_priv ); // 有効、変数のアドレス取得 baz ( a_priv ); // 有効、実質的に変数のアドレス取得 baz ( b_priv ); // 有効、実質的に変数のアドレス取得 baz ( c_priv ); // 有効、実質的に変数のアドレス取得 baz ( d_priv ); // 有効、メモリビューが変化 baz ( e_priv ); // 有効、メモリビューが変化 baz ( & i32_func ); // 無効、アドレス空間不一致 bar ( & usable_func ); // 有効、変数のアドレス取得 bar ( c_func ); // 有効、メモリビューが変化 bar ( d_func ); // 有効、メモリビューが変化 bar ( e_func ); // 有効、実質的に変数のアドレス取得 baz2 ( & ro_storage ); // 有効、変数のアドレス取得 baz2 ( & rw_storage ); // 無効、アクセスモード不一致 }
11.4.1. エイリアス解析
11.4.1.1. ルート識別子
メモリ位置は、関数の実行中にメモリビューを使ってアクセスできます。 関数内では、各メモリビューに特定のルート識別子が存在し、 その関数内で最初にそのメモリへのアクセスを提供する変数または仮引数の名前となります。
関数内で参照型や ポインター型の局所的な式は、 あるルート識別子のための新しい名前を導入することがありますが、 各式には静的に決定可能なルート識別子があります。
式Eがポインター型または参照型の場合、 ルート識別子は 以下のように見つかる元の変数か ポインター型の仮引数です:
-
Eが変数に解決される識別子の場合、そのルート識別子はその変数です。
-
Eがポインター型の仮引数に解決される識別子の場合、そのルート識別子はその仮引数です。
-
Eが
(E2)、&E2、*E2、 またはE2[Ei]の形の場合、そのルート識別子はE2のルート識別子です。 -
EがE2.swizという形のベクターアクセス式で、 swizがスウィズル名の場合、そのルート識別子はE2のルート識別子です。
-
EがE2.member_nameという形の構造体アクセス式の場合、 ルート識別子はE2のルート識別子です。
11.4.1.2. 別名化(エイリアシング)
ルート識別子の発生元変数は、関数の呼び出し箇所に依存する動的な概念である一方、 WGSL モジュールは、各ルート識別子について、可能なすべての発生元変数の集合を決定するために 静的に解析できる。
2 つのルート識別子は、同じ 発生元 変数を持つとき、エイリアスである。 WGSL 関数の実行は、エイリアスされたルート識別子を通じてメモリに潜在的に アクセスしてはならない。ここで、一方のアクセスは書き込みであり、 他方は読み取りまたは書き込みである。 これは、呼び出しグラフの葉から上方へ(すなわち、トポロジカル順序で) プログラムを解析することによって決定される。 各関数について、解析は次の集合を記録する:
-
モジュールスコープ変数のうち、 書き込まれるもの。 これには、この関数から呼び出される関数内で書き込まれるすべてのモジュールスコープ変数が含まれる。
-
モジュールスコープ変数のうち、 読み取られるもの。 これには、この関数から呼び出される関数内で読み取られるすべてのモジュールスコープ変数が含まれる。
-
この関数または呼び出される関数内で書き込まれるメモリビューのルート識別子として使用される ポインター仮引数。
-
この関数または呼び出される関数内で読み取られるメモリビューのルート識別子として使用される ポインター仮引数。
関数の各呼び出し箇所では、 次のいずれかが発生する場合、シェーダー作成エラーである:
-
ポインター型の 2 つの引数が同じルート識別子を持ち、対応する引数のいずれかが 書き込まれる引数集合に含まれる場合。
-
ルート識別子がモジュールスコープ変数であるポインター型の引数で、次の場合:
-
対応するポインター仮引数が、書き込まれるポインター仮引数の集合に含まれ、かつ
-
そのモジュールスコープ変数が、呼び出される関数の読み取り集合に含まれる。
-
-
ルート識別子がモジュールスコープ変数であるポインター型の引数で、次の場合:
-
対応するポインター仮引数が、書き込まれるポインター仮引数の集合に含まれ、かつ
-
そのモジュールスコープ変数が、呼び出される関数の書き込み集合に含まれる。
-
-
ルート識別子がモジュールスコープ変数であるポインター型の引数で、次の場合:
-
対応するポインター仮引数が、読み取られるポインター仮引数の集合に含まれ、かつ
-
そのモジュールスコープ変数が、呼び出される関数の書き込み集合に含まれる。
-
var < private> x : i32= 0 ; fn f1 ( p1 : ptr< function, i32> , p2 : ptr< function, i32> ) { * p1 = * p2 ; } fn f2 ( p1 : ptr< function, i32> , p2 : ptr< function, i32> ) { f1 ( p1 , p2 ); } fn f3 () { var a : i32= 0 ; f2 ( & a , & a ); // 無効。2つのポインタパラメータに同じルート識別子を渡してはならない // (サブ関数で書き込みがある場合も含む)。 } fn f4 ( p1 : ptr< function, i32> , p2 : ptr< function, i32> ) -> i32{ return * p1 + * p2 ; } fn f5 () { var a : i32= 0 ; let b = f4 ( & a , & a ); // 有効。f4のp1とp2は両方とも読み出しのみ。 } fn f6 ( p : ptr< private, i32> ) { x = * p ; } fn f7 ( p : ptr< private, i32> ) -> i32{ return x + * p ; } fn f8 () { let a = f6 ( & x ); // 無効。xはグローバル変数として書き込み、パラメータとして読み出される // let b = f7 ( & x ); // 有効。xはパラメータでも変数でも読み出しのみ。 // }
12. 属性
属性はオブジェクトを修飾します。 WGSLは属性を適用するための統一された構文を提供します。 属性はAPIとのインターフェース指定など、様々な目的で使用されます。
一般的に、言語的観点からは、型チェックや意味解析の際に属性は無視できます。 また、属性名はコンテキスト依存名であり、 属性のパラメータの一部もコンテキスト依存名です。
'@' ident_pattern_token
argument_expression_list ?
| id_attr
属性の説明で明示的に許可されていない限り、属性は同じオブジェクトまたは型に複数回指定してはなりません。
12.1. align
'@' 'align' '(' expression ',' ?
')'
| 説明 |
構造体メンバーのメモリ上の配置を制約します。
この属性は、囲んでいる構造体型の値がメモリ上でどのように配置されるかに影響します。 構造体自体およびその構成メンバーのバイトアドレスを制約します。 align(n) が S のメンバーに型 T で適用され、
S がアドレス空間 AS の変数の store type になり得る場合、
ここで AS が uniform でないならば、
n は満たさなければならない:
n = k × RequiredAlignOf(T,AS) ただし、k は正の整数。 アラインメントとサイズの規則は相互再帰的です。 しかし、上記の制約は、ネストされた型の必要なアラインメントに依存するため、明確に定義されています。 型には有限のネスト深度があるためです。 |
| パラメータ | const 式
であり、かつ i32 または u32 に
解決 されるものでなければならない。 正でなければならない。 2 の累乗でなければならない。 |
12.2. binding
'@' 'binding' '(' expression ',' ?
')'
| 説明 | バインドグループ内のリソースのバインディング番号を指定する。 § 13.3.2 リソースインターフェイスを参照。 |
| パラメーター | なければならないのは、i32 または u32 へ解決されるconst-expressionであること。 非負でなければならない。 |
12.3. blend_src
'@' 'blend_src' '(' expression ',' ?
')'
| 説明 |
機能 dual_source_blending
が有効化されているとき、fragment
出力の一部を指定する。
§ 13.3.1.3 入出力ロケーションを参照。
なければならないのは、location 属性を持つ構造体型の メンバーにのみ適用されること。 なければならないのは、数値スカラー または数値 ベクトル型のオブジェクトの宣言にのみ適用されること。 含まれてはならないのは、shader stage input 内である。 含まれてはならないのは、shader stage output 内である。 ただし fragment シェーダーステージを除く。 |
| パラメーター | なければならないのは、値が 0 または 1 の
i32 または u32 へ解決されるconst-expressionであること。
|
12.4. builtin
'@' 'builtin' '(' builtin_value_name ',' ? ')'
| 説明 |
関連付けられたオブジェクトが、指定されたトークンによって表される組み込み値であることを指定する。
§ 13.3.1.1 組み込み入力と出力を参照。
なければならないのは、エントリーポイント 関数パラメーター、エントリーポイント戻り型、または構造体のメンバーにのみ適用されること。 |
| パラメーター | なければならないのは、組み込み値に対する組み込み値 name-tokenであること。 |
12.5. const
'@' 'const'
| 説明 |
関数をconst-functionとして使用できることを指定する。
この属性はユーザー定義関数に適用してはならない。
なければならないのは、関数宣言にのみ適用されること。 注: この属性は、 どの組み込み関数がconst-expressionで使用できるかを記述するための 表記上の慣例として使用される。 |
| パラメーター | なし |
12.6. diagnostic
'@' 'diagnostic' diagnostic_control
'(' severity_control_name ',' diagnostic_rule_name ',' ? ')'
| 説明 |
範囲診断フィルターを指定します。§ 2.3
診断参照。
同じ構文要素に複数のdiagnostic属性を指定可能ですが、 必ず異なるトリガールールを指定してください。 |
| パラメータ |
1番目のパラメータはseverity_control_nameです。
2番目のパラメータはdiagnostic_rule_nameトークンであり、 トリガールールを指定します。 |
12.7. group
'@' 'group' '(' expression ',' ?
')'
| 説明 | リソースのバインディンググループを指定する。 § 13.3.2 リソースインターフェイスを参照。 |
| パラメーター | なければならないのは、i32 または u32 へ解決されるconst-expressionであること。 非負でなければならない。 |
12.8. id
'@' 'id' '(' expression ',' ?
')'
| 説明 |
pipeline-overridable 定数の代替名として、
数値識別子を指定する。
スカラー型のoverride-declarationにのみ適用されなければならない。 |
| パラメーター | i32 または u32 へ解決されるconst-expressionでなければならない。 非負でなければならない。 |
12.9. interpolate
'@' 'interpolate' '(' interpolate_type_name ',' ? ')'
| '@' 'interpolate' '(' interpolate_type_name ',' interpolate_sampling_name ',' ? ')'
| 説明 | ユーザー定義 IO がどのように補間されなければならないかを指定する。 § 13.3.1.4 補間を参照。 |
| パラメーター |
最初のパラメーターは、補間型に対する
補間型 name-tokenでなければならない。
2 番目のパラメーターが存在する場合、それは 補間サンプリングに対する補間サンプリング name-tokenでなければならない。 |
12.10. invariant
'@' 'invariant'
| 説明 |
vertex
shader の position 組み込み出力値に適用された場合、
結果の計算は、異なるプログラム間および同じエントリーポイントの異なる呼び出し間で不変である。
すなわち、異なるエントリーポイントにある 2 つの position 出力について
データと制御フローが一致する場合、その結果値は同じであることが保証される。
position 組み込み入力値には効果がない。
なければならないのは、position 組み込み値にのみ適用されること。 注: この属性は、HLSL の
|
| パラメーター | なし |
12.11. location
'@' 'location' '(' expression ',' ?
')'
| 説明 |
エントリーポイントのユーザー定義 IO の一部を指定する。
§ 13.3.1.3 入出力ロケーションを参照。
なければならないのは、エントリーポイント 関数パラメーター、エントリーポイント 戻り型、または構造体型のメンバーにのみ適用されること。 なければならないのは、数値スカラー または数値 ベクトル型のオブジェクトの宣言にのみ適用されること。 含まれてはならないのは、compute shader stage inputs 内である。 |
| パラメーター | なければならないのは、i32 または u32 へ解決されるconst-expressionであること。 非負でなければならない。 |
12.12. must_use
'@' 'must_use'
| 説明 |
この関数への呼び出しが式として使用されなければならないことを指定する。
すなわち、この関数への呼び出しは関数呼び出し文全体であってはならない。
なければならないのは、戻り型を持つ関数の宣言にのみ適用されること。 注: 多くの関数は値を返し、
副作用を持たない。
そのような関数を関数呼び出し文の唯一のものとして呼び出すことは、
多くの場合プログラミング上の欠陥である。
これらの性質を持つ組み込み関数は 注:
|
| パラメーター | なし |
12.13. size
'@' 'size' '(' expression ',' ?
')'
| 説明 |
構造体メンバーのために予約されるバイト数を指定する。
この数値は、少なくともメンバーの型のバイトサイズでなければならない:
§ 14.4 メモリレイアウトを参照。 なければならないのは、構造体型のメンバーにのみ適用されること。 メンバー型は作成時固定 フットプリントを持たなければならない。 |
| パラメーター | なければならないのは、i32 または u32 へ解決されるconst-expressionであること。 正でなければならない。 |
12.14. subgroup_size
'@' 'subgroup_size' '(' expression ',' ? ')'
| 説明 |
compute shader 呼び出しの subgroup サイズを指定する。
なければならないのは、compute shader エントリーポイント関数にのみ適用されること。 |
| 要件 | なければならないのは、subgroup_size_control 拡張が 有効化されている場合にのみ使用されること。 |
| パラメーター |
なければならないのは、i32 または u32 へ解決されるconst-expressionまたはoverride-expressionであること。 値が 2 の累乗でない場合:
エントリーポイントの
値が 値が
|
12.15. workgroup_size
'@' 'workgroup_size' '(' expression ',' ? ')'
| '@' 'workgroup_size' '(' expression ',' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ','
expression ',' ?
')'
| 説明 |
compute shader 用のworkgroup gridの x、y、および z 次元を指定する。
最初のパラメーターは x 次元を指定する。 2 番目のパラメーターが与えられた場合は y 次元を指定し、そうでなければ 1 とみなされる。 3 番目のパラメーターが与えられた場合は z 次元を指定し、そうでなければ 1 とみなされる。 なければならないのは、compute shader エントリーポイント関数にのみ適用されること。 他のどのオブジェクトにも適用されてはならない。 |
| パラメーター |
1 個、2 個、または 3 個のパラメーターを取る。
各パラメーターはconst-expressionまたはoverride-expressionでなければならない。 すべてのパラメーターは同じ型でなければならず、i32 または u32 のいずれかである。 指定されたパラメーターのいずれかが 非正の値に評価されるconst-expressionである場合、shader-creation error が発生する。 指定されたパラメーターのいずれかが 非正の値に評価されるか、WebGPU API によって指定される上限を超える場合、またはパラメーター値の積が WebGPU API によって指定される上限を超える場合、pipeline-creation error が発生する(WebGPU § 3.6.2 Limitsを参照)。 |
12.16. シェーダーステージ属性
以下のシェーダーステージ 属性は、 特定のシェーダーステージのエントリー ポイントとして関数を指定する。 これらの属性は関数宣言にのみ適用されなければならず、 与えられた関数に存在できるのは多くとも 1 つである。 これらはパラメーターを取らない。
12.16.1. vertex
'@' 'vertex'
vertex 属性は、関数をrender
pipeline のvertex shader
stageのエントリー
ポイントとして宣言する。
12.16.2. fragment
'@' 'fragment'
fragment 属性は、関数をrender
pipeline のfragment shader
stageのエントリー
ポイントとして宣言する。
12.16.3. compute
'@' 'compute'
compute 属性は、関数をcompute pipeline のcompute shader
stageのエントリー
ポイントとして宣言する。
13. エントリポイント
エントリポイントは、特定のシェーダーステージで処理を行うユーザー定義関数です。
13.1. シェーダーステージ
WebGPUはGPUに対して描画やディスパッチコマンドの形で作業を発行します。 これらのコマンドは、シェーダーステージの入力、出力、および 接続されたリソースのコンテキストでパイプラインを実行します。
パイプラインは、GPU上で実行される作業を、いくつかのステージのシーケンスとして記述します。その中にはプログラム可能なステージも含まれます。 WebGPUでは、描画やディスパッチコマンドを実行する前にパイプラインを作成します。 パイプラインには2種類あります: GPUComputePipeline と GPURenderPipeline。
ディスパッチコマンドは、 GPUComputePipeline を使用して、 コンピュートシェーダーステージ を論理的なグリッド上の多数のポイントで並列性を制御しながら実行し、 バッファーやイメージリソースを読み込み、必要に応じて更新します。
描画コマンドは、 GPURenderPipelineを使って、 他の固定機能ステージの間に2つのプログラム可能なステージを含むマルチステージプロセスを実行します:
-
頂点シェーダー ステージは、単一の頂点について入力属性を その頂点の出力属性へ対応付ける。
-
固定機能ステージは、頂点を(たとえば三角形などの)図形プリミティブへ対応付け、 それらはその後ラスタライズされて、ラスタライズフラグメントを生成する。 各ラスタライズフラグメントは、描画されるプリミティブと、 フレームバッファ内の特定のピクセルとの 重なりを表す。
-
フラグメント シェーダーステージは各フラグメントを処理し、 フラグメント出力を生成することがある。
-
通常、各ラスタライズ フラグメントに対して、1 つのフラグメントシェーダー呼び出しが作成される。 ラスタライズフラグメントが複数の サンプルを覆う場合は、複数のフラグメント呼び出しが作成されることがある。 WebGPU § 23.2.10 サンプル単位シェーディングを参照。
-
ラスタライズフラグメントがプリミティブの境界付近にある場合、追加のヘルパー 呼び出しも 作成されることがある。§ 15.4 フラグメント シェーダーとヘルパー呼び出しを参照。
-
-
固定機能ステージはフラグメント出力を消費し、色アタッチメントや深度およびステンシルバッファなどの 外部状態を更新することがある。
WebGPU仕様ではパイプラインについてさらに詳しく記述されています。
WGSLは、パイプラインのプログラム可能な部分に対応する3つのシェーダーステージを定義しています:
-
コンピュート
-
バーテックス
-
フラグメント
各シェーダーステージは、それぞれ独自の機能と制約を持ちます(詳細は他の箇所に記載)。
13.2. エントリポイント宣言
エントリーポイントを作成するには、 シェーダーステージ属性を持つユーザー定義 関数を宣言する。
WebGPU API でパイプラインを構成するとき、
エントリーポイントの関数名は、
WebGPU GPUProgrammableStage
オブジェクトの entryPoint 属性に対応付けられる。
エントリーポイントの仮 パラメーターは、そのステージのshader stage inputsを表す。 構造体型を使用して、ユーザー定義入力同士をまとめ、任意で組み込み 入力とまとめることができる。 各パラメーターは、shader stage input であるなければならないか、 または、各構造体メンバーが shader stage input である構造体型で宣言されなければならない。
指定されている場合、エントリーポイントの戻り 型およびその属性は、そのステージのshader stage outputsを表す。 構造体型を使用して、ユーザー定義出力同士をまとめ、任意で組み込み 出力とまとめることができる。 存在する場合、戻り型およびその属性は shader stage output でなければならないか、 または各構造体メンバーが shader stage output である構造体型でなければならない。
注: コンピュートエントリポイントは戻り値の型を持ちません。
@vertex fn vert_main () -> @builtin ( position) vec4< f32> { return vec4< f32> ( 0.0 , 0.0 , 0.0 , 1.0 ); } @fragment fn frag_main ( @builtin ( position) coord_in : vec4< f32> ) -> @location ( 0 ) vec4< f32> { return vec4< f32> ( coord_in . x , coord_in . y , 0.0 , 1.0 ); } @compute @workgroup_size ( 1 ) fn comp_main () { }
シェーダーステージ内の関数群は、次の集合の和集合です:
-
そのステージのエントリポイント関数
-
シェーダーステージ内の関数本体から呼び出される関数のターゲット(呼び出しが実際に実行されるかどうかは問わない)
この和集合は安定するまで繰り返し適用されます。 有限回のステップで安定します。
13.2.1. エントリポイントの関数属性
WGSLでは、エントリポイント宣言に適用できる以下の属性が定義されています:
@compute @workgroup_size ( 8 , 4 , 1 ) fn sorter () { } @compute @workgroup_size ( 8u ) fn reverser () { } // パイプラインで上書き可能な定数の使用例 @id ( 42 ) override block_width = 12u ; @compute @workgroup_size ( block_width ) fn shuffler () { } // エラー: workgroup_size は compute シェーダーで指定する必要があります @compute fn bad_shader () { }
13.3. シェーダーインターフェース
シェーダーインターフェースは、シェーダーステージ外部のデータへアクセスするため、 読み書きやシェーダーの設定に用いる パイプライン上書き可能 定数を含むオブジェクト群です。 このインターフェースには以下が含まれます:
-
アタッチされたリソース。これには 次が含まれる:
宣言 D は、次の場合にシェーダーによって静的にアクセスされる:
-
D に解決される 識別子が、シェーダーステージ内の関数のいずれかの宣言に出現する。
-
D に解決される 識別子が、静的にアクセスされる宣言の型を定義するために使用される。
-
D に解決される 識別子が、静的にアクセスされる宣言の初期化子で使用される。
-
D に解決される 識別子が、静的にアクセスされる宣言によって使用される属性によって使用される。
-
属性、仮引数、戻り型、および関数本体を含む、関数宣言のすべての部分。
-
上記を定義するために必要な任意の型。これには型エイリアスをたどることも含まれる。
-
型の定義を助ける特定の場合として、 workgroupアドレス空間内の変数の配列型の要素数であるoverride-expression内で使用される任意のoverride 宣言。 その変数自体が静的にアクセスされる場合。
-
上記のいずれかにおける override-expression の評価を支援するために使用される任意の override 宣言。
-
上記のいずれかに付けられた任意の属性。
これで、シェーダーのインターフェイスを、次から構成されるものとして正確に定義できる:
-
エントリーポイントの戻り値。 これはシェーダーステージ出力を表す。
-
シェーダーによって静的に アクセスされるuniform バッファ、 storage バッファ、テクスチャ リソース、およびサンプラーリソース変数。
-
シェーダーによって静的に アクセスされるoverride 宣言。
-
シェーダーによって静的に アクセスされる即時データ 変数。
13.3.1. ステージ間の入力・出力インターフェース
シェーダーステージ入力 は、パイプラインの上流からそのステージに渡されるデータです。 各データは 組み込み入力値 か、ユーザー定義入力です。
シェーダーステージ出力 は、パイプラインの下流処理へ渡すためのデータです。 各データは 組み込み出力値 か、ユーザー定義出力です。
IO属性は、 オブジェクトを シェーダーステージ入力や シェーダーステージ出力として定義し、 さらに入力や出力のプロパティを記述します。 IO属性は以下です:
13.3.1.1. 組み込み入力・出力
組み込み入力 値は、システム生成の制御情報へのアクセスを提供する。 エントリーポイントは、同じ組み込み 値名を持つ組み込み入力を 2 つ持ってはならない。
名前 X、型 TX を持つステージ S の組み込み入力は、 シェーダーステージ S のエントリーポイントへの 仮パラメーターを介して、 次の 2 つの方法のいずれかでアクセスされる:
-
パラメーターは属性
builtin(X)を持ち、型 TX である。 -
パラメーターは構造体型を持ち、その構造体メンバーの 1 つが属性
builtin(X)を持ち、型 TX である。
逆に、エントリーポイントのパラメーターまたはパラメーターのメンバーがbuiltin 属性を持つ場合、 対応する builtin は、エントリーポイントのシェーダーステージに対する入力でなければならない。
組み込み出力 値は、シェーダーによって、 パイプライン内の後続の処理ステップへ制御情報を伝えるために使用される。 エントリーポイントは、同じ組み込み 値名を持つ組み込み出力を 2 つ持ってはならない。
名前 Y、型 TY を持つステージ S の組み込み出力は、 シェーダーステージ S のエントリーポイントに対する 戻り値を介して、 次の 2 つの方法のいずれかで設定される:
-
エントリーポイントの戻り型が 属性
builtin(Y)を持ち、型 TY である。 -
エントリーポイントの戻り 型が構造体型を持ち、その構造体メンバーの 1 つが属性
builtin(Y)を持ち、型 TY である。
逆に、エントリーポイントの戻り型または戻り型のメンバーがbuiltin 属性を持つ場合、 対応する builtin は、エントリーポイントのシェーダーステージに対する出力でなければならない。
注: position 組み込み値は、 vertex shader の出力であると同時に、fragment shader への入力でもある。
組み込み入力値と組み込み出力値を総称して、組み込み値と呼ぶ。
次の表は、利用可能な組み込み値をまとめたものである。 それぞれは、組み込み値に対する組み込み値名トークンである。 それぞれは後続の節で詳細に説明される。
| 名前 | ステージ | 方向 | 型 | 拡張 |
|---|---|---|---|---|
| vertex_index | vertex | input | u32 | |
| instance_index | vertex | input | u32 | |
| clip_distances | vertex | output | array<f32, N>(N ≤ 8)
| clip_distances |
| position | vertex | output | vec4<f32> | |
| fragment | input | vec4<f32> | ||
| front_facing | fragment | input | bool | |
| frag_depth | fragment | output | f32 | |
| primitive_index | fragment | input | u32 | primitive_index |
| sample_index | fragment | input | u32 | |
| sample_mask | fragment | input | u32 | |
| fragment | output | u32 | ||
| local_invocation_id | compute | input | vec3<u32> | |
| local_invocation_index | compute | input | u32 | |
| global_invocation_id | compute | input | vec3<u32> | |
| global_invocation_index | compute | input | u32 | linear_indexing |
| workgroup_id | compute | input | vec3<u32> | |
| workgroup_index | compute | input | u32 | linear_indexing |
| num_workgroups | compute | input | vec3<u32> | |
| subgroup_invocation_id | compute | input | u32 | subgroups |
| fragment | ||||
| subgroup_size | compute | input | u32 | subgroups |
| fragment | ||||
| subgroup_id | compute | input | u32 | subgroups および subgroup_id |
| num_subgroups | compute | input | u32 | subgroups および subgroup_id |
struct VertexOutput { @builtin ( position) my_pos : vec4< f32> , @builtin ( clip_distances ) my_clip_distances : array< f32, 8 > , } @vertex fn vs_main ( @builtin ( vertex_index) my_index : u32, @builtin ( instance_index) my_inst_index : u32, ) -> VertexOutput {} struct FragmentOutput { @builtin ( frag_depth) depth : f32, @builtin ( sample_mask) mask_out : u32} @fragment fn fs_main ( @builtin ( front_facing) is_front : bool, @builtin ( position) coord : vec4< f32> , @builtin ( sample_index) my_sample_index : u32, @builtin ( sample_mask) mask_in : u32, ) -> FragmentOutput {} @compute @workgroup_size ( 64 ) fn cs_main ( @builtin ( local_invocation_id) local_id : vec3< u32> , @builtin ( local_invocation_index) local_index : u32, @builtin ( global_invocation_id) global_id : vec3< u32> , ) {}
13.3.1.1.1. clip_distances
| 名前 | clip_distances |
| ステージ | vertex |
| 型 | array<f32, N> |
| 方向 | 出力 |
| 説明 |
配列の各値はユーザー定義クリップ面への距離を表します。clip
distanceが0のとき、その頂点は面上にあり、正の値ならクリップ半空間内、負の値なら半空間外です。clip_distancesの配列サイズは8以下でなければなりません。
詳細は WebGPU § 23.2.4
プリミティブのクリッピング を参照。
|
13.3.1.1.2. frag_depth
| 名前 | frag_depth |
| ステージ | fragment |
| 型 | f32 |
| 方向 | 出力 |
| 説明 |
ビューポートの深度範囲内で更新されたフラグメントの深度値。
詳細は WebGPU § 3.3 座標系 を参照。 |
13.3.1.1.3. front_facing
| 名前 | front_facing |
| ステージ | fragment |
| 型 | bool |
| 方向 | 入力 |
| 説明 | 現在のフラグメントがfront-facingプリミティブ上ならtrue、そうでなければfalseです。 |
13.3.1.1.4. global_invocation_id
| 名前 | global_invocation_id |
| ステージ | compute |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのglobal invocation ID、つまりコンピュートシェーダーグリッド内での位置です。global_invocation_idの値は workgroup_id × workgroup_size + local_invocation_idと等しいです。 |
13.3.1.1.5. global_invocation_index
| 名前 | global_invocation_index |
| ステージ | compute |
| 型 | u32; |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのグローバル呼び出しインデックス、すなわち
compute
シェーダーグリッド内での線形位置。global_invocation_index
の値は次に等しい:
global_invocation_id.x +
注: ディスパッチされる
ワークグループの数により、この値が u32
型の範囲を超える場合、ディスパッチは失敗する:
|
13.3.1.1.6. instance_index
| 名前 | instance_index |
| ステージ | vertex |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在のAPIレベルの描画コマンド内での頂点インスタンス番号。
最初のインスタンスの番号は、描画コマンドの |
13.3.1.1.7. local_invocation_id
| 名前 | local_invocation_id |
| ステージ | compute |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのlocal invocation ID、つまりワークグループグリッド内での位置です。 |
13.3.1.1.8. local_invocation_index
| 名前 | local_invocation_index |
| ステージ | compute |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのlocal invocation index、ワークグループグリッド内での呼び出し位置を線形化した値です。 |
13.3.1.1.9. num_workgroups
| 名前 | num_workgroups |
| ステージ | compute |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 |
ディスパッチサイズ、すなわちvec3<u32>(group_count_x, group_count_y, group_count_z)であり、APIによってコンピュートシェーダーがディスパッチされたときの値です。
|
13.3.1.1.10.
position
| 名前 | position |
| ステージ | vertex |
| 型 | vec4<f32> |
| 方向 | 出力 |
| 説明 |
現在の頂点のクリップ位置(
クリップ空間座標における)。
出力値 (x,y,z,w) は WebGPU の 正規化デバイス座標において (x/w, y/w, z/w) にマッピングされます。 WebGPU § 3.3 座標系 および WebGPU § 23.2.4 プリミティブクリッピング を参照してください。 w 座標がゼロの場合、動的エラーが発生します。 |
| 名前 | position |
| ステージ | フラグメント |
| 型 | vec4<f32> |
| 方向 | 入力 |
| 説明 |
現在のフラグメントラスタライズ点の入力位置。
rp を、そのフラグメントのRasterizationPoint とする。 図式的には次のとおり: fp.xy = rp.destination.position より詳しくは:
|
13.3.1.1.11. primitive_index
| 名前 | primitive_index |
| ステージ | fragment |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在のインスタンスに対して描画操作開始から処理されたプリミティブ数に基づいたプリミティブごとのインデックスです。 0から始まり、各ポイント、ライン、トライアングルプリミティブが処理されるごとに1ずつ増加します。インスタンスごとに0にリセットされます。 プリミティブ再スタート値によるストリッププリミティブの再起動はprimitive_indexに影響しません。このインデックスはプリミティブの全フラグメントで一様です。 |
13.3.1.1.12. sample_index
| 名前 | sample_index |
| ステージ | フラグメント |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在のフラグメントラスタライズ点のサンプルインデックス。
値は 0 以上で、最大でも
sampleCount-1 である。ここで sampleCount は、GPU レンダーパイプラインに
指定されたサンプル
count
である。
この属性が適用される場合、フラグメントシェーダーの効果が
sample_index の値に基づいて変化するなら、
フラグメントシェーダーは
サンプルごとに 1 回呼び出される。
|
13.3.1.1.13. sample_mask
| 名前 | sample_mask |
| ステージ | フラグメント |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在のフラグメントのサンプルカバレッジビットマスク。
ビットは半開区間 [0, ビットは、サンプルがレンダリング中のプリミティブによって覆われている
場合に限り 1 に設定されます。
インデックスが ビットマスクには 2 つの可能な値があります。
注: 注: これは WebGPU § 23.2.10 サンプル単位シェーディングおよび WebGPU § 23.2.11 サンプル マスキングを参照してください。 |
| 名前 | sample_mask |
| ステージ | fragment |
| 型 | u32 |
| 方向 | 出力 |
| 説明 |
現在のフラグメントのサンプルカバレッジマスク制御。この変数に最後に書き込まれた値がシェーダー出力マスクとなります。値のゼロビットは対応するカラーバッファのサンプルを捨てます。
詳細は WebGPU § 23.2.11 サンプルマスキング を参照。 |
13.3.1.1.14. vertex_index
| 名前 | vertex_index |
| ステージ | vertex |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在のAPIレベルの描画コマンド内での頂点のインデックス(描画インスタンスに依存しない)。
非インデックス描画の場合、最初の頂点のインデックスは描画コマンドの インデックス付き描画の場合、インデックスは頂点に対するインデックスバッファのエントリ+描画コマンドの |
13.3.1.1.15. workgroup_id
| 名前 | workgroup_id |
| ステージ | compute |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのworkgroup
ID、すなわちコンピュートシェーダーグリッド全体の中でのワークグループの位置です。
同じワークグループ内の全呼び出しは同じworkgroup IDを持ちます。 ワークグループIDは(0,0,0)から(group_count_x - 1, group_count_y - 1, group_count_z - 1)まで広がります。 |
13.3.1.1.16. workgroup_index
| 名前 | workgroup_index |
| ステージ | compute |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのワークグループインデックス、すなわち全体のcompute シェーダーグリッド内での
ワークグループの線形位置。
同じワークグループ内のすべての呼び出しは、同じワークグループインデックスを持つ。
注: ディスパッチされる
ワークグループの数により、この値が u32
型の範囲を超える場合、ディスパッチは失敗する:
|
13.3.1.1.17. subgroup_invocation_id
| 名前 | subgroup_invocation_id |
| ステージ | compute または fragment |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのサブグループ呼び出し ID。
ID は範囲 [0, subgroup_size - 1] 内である。 compute シェーダーでは、ID はゼロから始まり密である。 すなわち、compute シェーダーが実行を開始すると、各サブグループ内では:
注: fragment シェーダー内の サブグループ呼び出しインデックスは密でない場合がある。実装は、 低い番号の ID の一部をヘルパー呼び出しに割り当てる場合がある。 |
13.3.1.1.18. subgroup_size
| 名前 | subgroup_size |
| ステージ | compute または fragment |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しの subgroup のsubgroup サイズ。
subgroup_size 属性を持つ compute shader では、この値は 指定された属性値に等しい。 |
13.3.1.1.19. subgroup_id
| 名前 | subgroup_id |
| ステージ | compute |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
ワークグループ内における、現在の呼び出しのサブグループの
サブグループ ID。
ID は範囲 [0, num_subgroups - 1] 内である。 |
13.3.1.1.20. num_subgroups
| 名前 | num_subgroups |
| ステージ | compute |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのワークグループ内の サブグループの数。 |
13.3.1.2. ユーザー定義入力・出力
ユーザー定義データは、パイプラインの開始時に入力として渡したり、 パイプラインのステージ間で渡したり、パイプラインの末尾から出力したりできる。
各ユーザー定義 入力データおよび ユーザー定義 出力データはなければならない:
-
IO ロケーションが割り当てられていること。§ 13.3.1.3 入出力 ロケーションを参照。
compute shader は、ユーザー定義 入力または出力を持ってはならない。
13.3.1.3. 入出力ロケーション
各入出力ロケーションは、サイズが最大 16 バイトの値を格納できる。 型のバイトサイズは、§ 14.4.1 アラインメントとサイズの SizeOf 列を使用して定義される。 たとえば、浮動小数点値の 4 成分ベクトルは単一のロケーションを占有する。
IO ロケーションは、location 属性を介して指定される。
各ユーザー定義入力および出力は、 明示的に指定された IO ロケーションを持たなければならない。 エントリーポイント IO 内の各構造体メンバーは、組み込み値 (§ 13.3.1.1 組み込み入力と出力を参照)であるか、またはロケーションが割り当てられていなければならない。
注:ロケーション番号は入力と出力で別々です: エントリポイントのシェーダーステージ入力用ロケーション番号は、出力用ロケーション番号と競合しません。
注:エントリポイントの出力内でロケーションが重複しないように追加ルールは必要ありません。 出力が構造体の場合、上記の最初のルールによって重複が防止されます。 それ以外の場合、出力はスカラーまたはベクトルであり、単一のロケーションしか割り当てられません。
注:エントリポイントで利用可能なロケーション数はWebGPU APIによって定義されます。
ユーザー定義IOは同じ構造体内で組み込み値と混在できます。例えば、
// 組み込み値とユーザー定義入力の混在 struct MyInputs { @location ( 0 ) x : vec4< f32> , @builtin ( front_facing) y : bool, @location ( 1 ) @interpolate ( flat) z : u32} struct MyOutputs { @builtin ( frag_depth) x : f32, @location ( 0 ) y : vec4< f32> } @fragment fn fragShader ( in1 : MyInputs ) -> MyOutputs { // ... }
struct A { @location ( 0 ) x : f32, // 無効:xとyは同じロケーションを共有できない @location ( 0 ) y : f32} struct B { @location ( 0 ) x : f32} struct C { // 無効:ユーザー定義IOを持つ構造体はネスト不可 b : B } struct D { x : vec4< f32> } @fragment // 無効:構造体型にロケーションは適用不可 fn fragShader1 ( @location ( 0 ) in1 : D ) { // ... } @fragment // 無効:in1とin2は同じロケーションを共有できない fn fragShader2 ( @location ( 0 ) in1 : f32, @location ( 0 ) in2 : f32) { // ... } @fragment // 無効:構造体へのロケーションの適用不可 fn fragShader3 ( @location ( 0 ) in1 : vec4< f32> ) -> @location ( 0 ) D { // ... }
13.3.1.4. 補間
作者は、interpolate 属性の使用を通じて、 ユーザー定義 IO データがどのように補間されるかを制御できる。 WGSL は、補間の 2 つの側面、すなわち補間の型と、 補間のサンプリングを制御できるようにしている。
補間型は、 次の補間型名トークンのいずれかでなければならない:
- perspective
-
値は perspective correct な方法で補間される。
- linear
-
値は linear で、non-perspective correct な方法で補間される。
- flat
-
値は補間されない。
補間 サンプリングは、次の 補間サンプリング名トークンのいずれかでなければならない:
- center
-
補間はピクセルの中心で実行される。
- centroid
-
補間は、現在のプリミティブ内で fragment によって覆われる すべてのサンプルの内部にある点で実行される。 この値は、プリミティブ内のすべてのサンプルで同じである。
- sample
-
補間はサンプルごとに実行される。 この属性が適用されると、fragment shader は サンプルごとに 1 回呼び出される。
- first
-
値はプリミティブの最初の頂点によって提供される。
- either
-
値はプリミティブの最初の頂点または最後の頂点によって提供される。 値が最初の頂点から来るか最後の頂点から来るかは実装依存である。
スカラーまたはベクトル浮動小数点型のユーザー定義 IO について:
-
補間属性が指定されていない場合、
@interpolate(perspective, center)とみなされる。 -
補間属性が補間型とともに指定されている場合:
スカラーまたはベクトル整数型のユーザー定義vertex 出力およびfragment 入力は、常に補間型
flat で指定されなければならない。
Interstage interface validation は、 render pipeline 内で、 各ユーザー定義fragment 入力の補間プロパティが、 同じlocation 割り当てを持つ vertex 出力の 補間プロパティと一致することを検査する。 一致しない場合、pipeline-creation error が発生することになる。
13.3.2. リソースインターフェース
リソースは、 シェーダーステージの外部にあるデータへのアクセスを提供するオブジェクトであり、 override-declarationでも、即時データ変数でも、shader stage input または outputでもない。 リソースはシェーダーのすべての呼び出しによって共有される。
リソースには 4 種類ある:
シェーダーのリソース インターフェイスは、シェーダーステージ内の関数によって静的にアクセスされるモジュールスコープの リソース変数の集合である。
各リソース変数は、group 属性と binding 属性の両方を指定して宣言されなければならない。 これらはシェーダーのステージとともに、シェーダーのパイプライン上の リソースのバインディングアドレスを識別する。 WebGPU § 8.3 GPUPipelineLayoutを参照。
即時データ変数は、 group 属性またはbinding 属性を使用しない。
シェーダー内の 2 つの異なるリソース変数は、 ペアとして考えたときに、同じgroup 値とbinding 値を持ってはならない。
13.3.3. リソースレイアウトの互換性
WebGPUは、シェーダーのリソースインターフェースが使用しているパイプラインのレイアウトと一致することを要求します。
WGSLのリソースインターフェース内の変数が、互換性のないWebGPU binding member または binding type にバインドされている場合、これはパイプライン作成エラーとなります。互換性は以下の表で定義されています。
WebGPU API 現行標準仕様にてインターフェースの検証要件を参照してください。
13.3.4. バッファバインディングによる実行時サイズ配列の要素数決定
storage buffer
変数に実行時サイズの配列が含まれている場合、その配列の要素数は対応するresourceのサイズから決定されます。
Tをストア型とし、storage buffer変数に対し、 Tが実行時サイズ配列型またはその型を含むものとする。
bufferBindingを get as buffer binding(
resource) とする。EBSを 実効バッファバインディングサイズとし、 bufferBindingがパイプラインのバインディングアドレスにバインドされた該当storage buffer変数用のものとする。
そして NRuntime、 すなわち実行時サイズ配列の要素数は SizeOf(T) ≤ EBS を満たす最大の整数とする。
詳細として、型RATの実行時サイズ配列に対するNRuntimeは:
truncate((EBBS − array_offset) ÷ array_stride)、ここで
EBBSは、その変数に関連づけられた実効バッファバインディングサイズです。
array_offsetは、ストア型内で実行時サイズ配列のバイトオフセットです。
ストア型がRAT(配列型自体)の場合は0です。
それ以外の場合は、ストア型が構造体であり、その最後のメンバーが実行時サイズ配列です。 この場合、array_offsetはそのメンバーの構造体内バイトオフセットです。
array_strideは配列型のストライド、すなわちStrideOf(RAT)です。
シェーダーはNRuntimeを、arrayLength組み込み関数を使って計算できます。
NRuntimeは対応するバッファバインディングのサイズにより決定され、 これはdraw またはdispatch commandごとに異なる場合があります。
WebGPUの検証規則により、1 ≤ NRuntimeが保証されます。
-
weights変数はstorage bufferです。 -
そのストア型は実行時サイズ配列型
array<f32>です。 -
配列オフセットは0です。
-
配列ストライドはStrideOf(array<f32>) = 4です。
次の表は、対応する実効バッファバインディングサイズに基づくweights変数のNRuntimeの例を示します。
| 実効バッファバインディングサイズ | weights変数のNRuntime
| 計算方法 |
|---|---|---|
| 1024 | 256 | truncate( 1024 ÷ 4 ) |
| 1025 | 256 | truncate( 1025 ÷ 4 ) |
| 1026 | 256 | truncate( 1026 ÷ 4 ) |
| 1027 | 256 | truncate( 1027 ÷ 4 ) |
| 1028 | 257 | truncate( 1028 ÷ 4 ) |
-
lights変数はstorage bufferです。 -
そのストア型は
LightStorageです。 -
LightStorageのpointメンバーは、型array<PointLight>の実行時サイズ配列です。
struct PointLight { // align(16) size(32) position: vec3f, // offset(0) align(16) size(12) // -- implicit member alignment padding -- // offset(12) size(4) color : vec3f, // offset(16) align(16) size(12) // -- implicit struct size padding -- // offset(28) size(4) } struct LightStorage { // align(16) pointCount : u32, // offset(0) align(4) size(4) // -- implicit member alignment padding -- // offset(4) size(12) point : array< PointLight > , // offset(16) align(16) elementsize(32) } @group ( 0 ) @binding ( 1 ) var < storage> lights : LightStorage ;
以下の表は、lights変数のpointメンバーに対するNRuntimeの例を示します。
| 実効バッファバインディングサイズ | lights変数のpointメンバーのNRuntime
| 計算方法 |
|---|---|---|
| 1024 | 31 | truncate( ( 1024 - 16 ) ÷ 32) ) |
| 1025 | 31 | truncate( ( 1025 - 16 ) ÷ 32) ) |
| 1039 | 31 | truncate( ( 1039 - 16 ) ÷ 32) ) |
| 1040 | 32 | truncate( ( 1040 - 16 ) ÷ 32) ) |
14. メモリ
WGSLでは、storable型の値はメモリに格納でき、後で取得することができます。 このセクションでは、メモリの構造と、メモリにアクセスする操作の意味論について説明します。 メモリに格納できる値の型や、メモリアクセスに使用される型については§ 6.4 メモリビューを参照してください。
14.1. メモリロケーション
メモリは一連の個別なメモリロケーションから構成されます。 各メモリロケーションは8ビットのサイズです。 メモリに影響を与える操作は、1つ以上のメモリロケーションの集合とやりとりします。 合成型に対するメモリ操作はパディングされたメモリロケーションをアクセスしません。 そのため、操作によってアクセスされるメモリロケーションの集合は連続していない場合があります。
2つのメモリロケーションの集合は、そのメモリロケーションの集合の交差が空でない場合、オーバーラップします。
14.2. メモリアクセスモード
メモリアクセスは、 メモリロケーションに作用する操作です。
-
読み取りアクセスは、メモリロケーションの内容を観察します。
-
書き込みアクセスは、メモリロケーションの内容を設定します。
1つの操作で、読み取り・書き込み、または両方を行うことができます。
特定のメモリロケーションは、メモリのアクセスモードとして表現される、特定の種類のアクセスのみをサポートする場合があります。
| アクセスモード | サポートされるアクセス |
|---|---|
| read | 読み取りアクセスのみサポート、書き込み不可。 |
| write | 書き込みアクセスのみサポート、読み取り不可。 |
| read_write | 読み取り・書き込み両方のアクセスをサポート。 |
WGSLは事前宣言された列挙子としてread、write、read_writeを持ちます。
14.3. アドレス空間
メモリロケーションはアドレス空間で分割されています。 各アドレス空間は、 可変性・可視性・格納できる値・変数の使用方法など独自の特性を持ちます。 詳細は§ 7 変数と値の宣言を参照してください。
特定のメモリビューのアクセスモードは、しばしば文脈によって決まります:
storageアドレス空間は readおよび read_writeアクセスモードの両方をサポートします。 他のアドレス空間は1つのアクセスモードのみをサポートします。 各アドレス空間のデフォルトアクセスモードは以下の表で説明されています。
| アドレス空間 | 呼び出し間の共有 | 既定のアクセスモード | 注 |
|---|---|---|---|
| function | 同じ呼び出しのみ | read_write | |
| private | 同じ呼び出しのみ | read_write | |
| workgroup | 同じ compute シェーダーのワークグループ内の呼び出し | read_write | 最外配列の要素数は、 パイプラインで上書き可能な定数であってよい。 |
| uniform | 同じシェーダーステージ内の呼び出し | read | uniform バッファ変数用 |
| storage | 同じシェーダーステージ内の呼び出し | read | storage バッファ変数用 |
| immediate | 同じシェーダーステージ内の呼び出し | read | 即時
データ変数用。 各エントリーポイントは、 多くとも 1 つの immediate 変数に静的にアクセスできる。 |
| handle | 同じシェーダーステージ内の呼び出し | read | サンプラー
およびテクスチャ
変数用。 |
WGSL は、handle アドレス空間を除き、各アドレス空間に対して列挙子を事前宣言する。
workgroup アドレス空間内の変数は、 compute shader stage内でのみ静的に アクセスされなければならない。
storage
アドレス空間(storage buffers)内の変数は、アクセスモードがreadである場合に限り、vertex shader stageによって静的に
アクセスできる。
ストア型が
write または read_write アクセスモードを持つstorage
textureである変数は、
vertex shader
stageによって静的に
アクセスできない。
WebGPU createBindGroupLayout()を参照。
注: 各アドレス空間は異なる性能 特性を持つ場合がある。
14.4. メモリレイアウト
WGSL における型のレイアウトは、アドレス空間に依存しない。 ただし、厳密に言えば、そのレイアウトはホスト共有可能な バッファによってのみ観測できる。 uniform バッファおよびstorage バッファ変数は、 メモリ内のバイト列として構成された大量データを共有するために使用される。 バッファは、CPU と GPU の間、パイプライン内の異なるシェーダーステージの間、 または異なるパイプラインの間で共有される。
バッファデータは再フォーマットや変換なしに共有されるため、バッファの producer と consumer がメモリレイアウトに合意していない場合、それは 動的エラーである。 メモリレイアウトとは、バッファ内のバイトが、型付きの WGSL 値としてどのように構成されるかの記述である。 これらのバイトは、共通の基準位置を基準とする値のメモリ 位置である。
バッファー変数のストア型は、 下で述べるように、完全に詳細化されたメモリレイアウトを持つ host-shareableでなければならない。
各バッファー変数は、uniform または storage アドレス空間のいずれかで宣言されなければならない。
型のメモリレイアウトは、次のものを持つ式を評価するときにのみ重要である:
8 ビットバイトは、ホスト共有可能メモリの最も基本的な単位である。 この節で定義される用語は、8 ビットバイトの個数を表す。
以下の表記を使用する。ここで、 T はホスト共有可能または固定フットプリント型、 S はホスト共有可能または固定フットプリントの構造体型、 A はホスト共有可能または固定フットプリントの配列またはランタイムサイズ配列である:
-
AlignOf(T) は T のアライメントである。
-
AlignOfMember(S, i) は S の i 番目のメンバーのアライメントである。
-
SizeOf(T) は T のバイトサイズである。
-
SizeOfMember(S, i) は S の i 番目のメンバーのサイズである。
-
OffsetOfMember(S, i) は S の先頭からの i 番目のメンバーのオフセットである。
-
StrideOf(A) は A の要素 ストライドであり、 1 つの配列要素の先頭から次の要素の先頭までのバイト数として定義される。 これは、配列の要素型のサイズを、その要素型のアライメントまで切り上げたものに等しい:
StrideOf(array<E, N>) = roundUp(AlignOf(E), SizeOf(E))
StrideOf(array<E>) = roundUp(AlignOf(E), SizeOf(E)) -
AccessibleBytes(T) は、型 T のインスタンス内で データを含むバイトオフセットの集合である。
-
T がスカラーまたはベクトルである場合、AccessibleBytes(T) は、
0 <= k <SizeOf(T) となる整数kの集合である。 -
T が C 列および R 行を持つ行列である場合、AccessibleBytes(T) は、次のように計算される集合である:
-
0..C-1内の各iについて:-
AccessibleBytes(vecR) 内の各
kについて:-
その集合は
k + i * Strideを含む。
-
-
-
T が構造体 S である場合、AccessibleBytes(T) は、次のように計算される集合である:
-
バイトオフセット
Offset= OffsetOfMember(S,i) にある各メンバーM_iについて:-
AccessibleBytes(
M_i) 内の各kについて:-
その集合は
k + Offsetを含む。
-
-
-
-
-
AccessibleSlots(T) は、 区間
[4*i, 4*i+4)と AccessibleBytes(T) の共通部分が空でないような整数iの集合である。
14.4.1. アライメントとサイズ
各ホスト共有可能または固定フットプリントデータ型 T は、アライメントとサイズを持つ。
型のアライメントは、 その型の値をメモリ内のどこに配置できるかに関する制約であり、整数として表される: 型のアライメントは、その型の値の開始メモリ位置のバイトアドレスを 均等に割り切らなければならない。 アライメントにより、値へのアクセスにより効率的なハードウェア命令を使用できるようになり、 または特定のアドレス空間におけるより制限的なハードウェア要件を満たす。 (アドレス空間レイアウト制約を参照)。
注: 各アライメント値は、構成上、常に 2 の累乗である。
型または構造体メンバーのバイトサイズは、 その型または構造体メンバーの値を格納する目的で ホスト共有可能メモリ内に予約される連続したバイト数である。 サイズには、型の末尾にあるアドレス指定できないパディングが含まれる場合がある。 したがって、値のロードおよびストアは、値のサイズより少ないメモリ位置に アクセスする場合がある。
ホスト共有可能型および固定フットプリント型のアライメントとサイズは、次の表で 再帰的に定義される:
| host-shareable または固定フットプリント型 T | AlignOf(T) | SizeOf(T) |
|---|---|---|
| bool
注を参照。 | 4 | 4 |
| i32、u32、または f32 | 4 | 4 |
| f16 | 2 | 2 |
| atomic<T> | 4 | 4 |
| vec2<T>、 T は bool、i32、u32、または f32 | 8 | 8 |
| vec2<f16> | 4 | 4 |
| vec3<T>、T は bool、i32、u32、 または f32 | 16 | 12 |
| vec3<f16> | 8 | 6 |
| vec4<T>、T は bool、i32、u32、 または f32 | 16 | 16 |
| vec4<f16> | 8 | 8 |
|
matCxR
(列優先) (一般形) | AlignOf(vecR) | SizeOf(array<vecR, C>) |
| mat2x2<f32> | 8 | 16 |
| mat2x2<f16> | 4 | 8 |
| mat3x2<f32> | 8 | 24 |
| mat3x2<f16> | 4 | 12 |
| mat4x2<f32> | 8 | 32 |
| mat4x2<f16> | 4 | 16 |
| mat2x3<f32> | 16 | 32 |
| mat2x3<f16> | 8 | 16 |
| mat3x3<f32> | 16 | 48 |
| mat3x3<f16> | 8 | 24 |
| mat4x3<f32> | 16 | 64 |
| mat4x3<f16> | 8 | 32 |
| mat2x4<f32> | 16 | 32 |
| mat2x4<f16> | 8 | 16 |
| mat3x4<f32> | 16 | 48 |
| mat3x4<f16> | 8 | 24 |
| mat4x4<f32> | 16 | 64 |
| mat4x4<f16> | 8 | 32 |
| struct S、その メンバー M1...MN | max(AlignOfMember(S,1), ... , AlignOfMember(S,N)) | roundUp(AlignOf(S),
justPastLastMember) ここで justPastLastMember = OffsetOfMember(S,N) + SizeOfMember(S,N) |
| array<E,
N> | AlignOf(E) | N × roundUp(AlignOf(E), SizeOf(E)) |
| array<E> | AlignOf(E) | NRuntime × roundUp(AlignOf(E),SizeOf(E)) ここで NRuntime は T の実行時に決定される要素数である |
bool 値が 4 バイトアライメントで 4 バイトを占有すると指定することで、
実装は、データ競合を生じさせずにメモリ内の隣接するブール値をサポートできる。
14.4.2. 構造体メンバーのレイアウト
構造体の内部レイアウトは、 そのメンバーのサイズとアラインメントから計算される。 デフォルトでは、メンバーはメンバーのアラインメント要件を満たしつつ、重ならないように、順に、詰めて配置される。
このデフォルトの内部レイアウトは、レイアウト属性を使うことでオーバーライドできる。それらは次のとおりである:
構造体型 S の i 番目のメンバーはサイズとアラインメントを持ち、それぞれ SizeOfMember(S, i) および AlignOfMember(S, i) と表記される。 メンバーのサイズとアラインメントは、 § 14.4.4 値の内部レイアウトで述べるように、 構造体の先頭からの各メンバーのバイトオフセットを計算するために使用される。
SizeOfMember(S, i) は、S の i 番目のメンバーが属性 size(k) を持つ場合、k である。 そうでなければ、それは SizeOf(T) であり、ここで T はそのメンバーの型である。
AlignOfMember(S, i) は、S の i 番目のメンバーが属性 align(k) を持つ場合、k である。 そうでなければ、それは AlignOf(T) であり、ここで T はそのメンバーの型である。
構造体メンバーに size 属性が適用される場合、その 値はメンバーの型のサイズ以上でなければならない:
SizeOfMember(S, i) ≥ SizeOf(T)
ここで T は S の i 番目のメンバーの型である。
最初の構造体メンバーは常に、構造体の先頭からのバイトオフセットが 0 である:
OffsetOfMember(S, 1) = 0
後続の各メンバーは、メンバー型のアラインメントを満たし、 かつ前のメンバーとの重なりを避ける、最小のオフセットに配置される。 各メンバーインデックス i > 1 について:
OffsetOfMember(S, i) = roundUp(AlignOfMember(S, i ), OffsetOfMember(S, i-1) + SizeOfMember(S, i-1))
struct A { // align(8) size(24) u : f32, // offset(0) align(4) size(4) v : f32, // offset(4) align(4) size(4) w : vec2< f32> , // offset(8) align(8) size(8) x : f32// offset(16) align(4) size(4) // -- implicit struct size padding -- // offset(20) size(4) } struct B { // align(16) size(160) a : vec2< f32> , // offset(0) align(8) size(8) // -- implicit member alignment padding -- // offset(8) size(8) b : vec3< f32> , // offset(16) align(16) size(12) c : f32, // offset(28) align(4) size(4) d : f32, // offset(32) align(4) size(4) // -- implicit member alignment padding -- // offset(36) size(4) e : A , // offset(40) align(8) size(24) f : vec3< f32> , // offset(64) align(16) size(12) // -- implicit member alignment padding -- // offset(76) size(4) g : array< A , 3 > , // element stride 24 offset(80) align(8) size(72) h : i32// offset(152) align(4) size(4) // -- implicit struct size padding -- // offset(156) size(4) } @group ( 0 ) @binding ( 0 ) var < storage, read_write> storage_buffer : B ;
struct A { // align(8) size(32) u : f32, // offset(0) align(4) size(4) v : f32, // offset(4) align(4) size(4) w : vec2< f32> , // offset(8) align(8) size(8) @size ( 16 ) x : f32// offset(16) align(4) size(16) } struct B { // align(16) size(208) a : vec2< f32> , // offset(0) align(8) size(8) // -- implicit member alignment padding -- // offset(8) size(8) b : vec3< f32> , // offset(16) align(16) size(12) c : f32, // offset(28) align(4) size(4) d : f32, // offset(32) align(4) size(4) // -- implicit member alignment padding -- // offset(36) size(12) @align ( 16 ) e : A , // offset(48) align(16) size(32) f : vec3< f32> , // offset(80) align(16) size(12) // -- implicit member alignment padding -- // offset(92) size(4) g : array< A , 3 > , // element stride 32 offset(96) align(8) size(96) h : i32// offset(192) align(4) size(4) // -- implicit struct size padding -- // offset(196) size(12) } @group ( 0 ) @binding ( 0 ) var < uniform> uniform_buffer : B ;
14.4.3. 配列レイアウト例
// 配列: // - アライメントは4 = AlignOf(f32) // - 要素ストライドは4 = roundUp(AlignOf(f32),SizeOf(f32)) = roundUp(4,4) // - サイズは32 = stride * number_of_elements = 4 * 8 var small_stride : array< f32, 8 > ; // 配列: // - アライメントは16 = AlignOf(vec3<f32>) = 16 // - 要素ストライドは16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>)) // = roundUp(16,12) // - サイズは128 = stride * number_of_elements = 16 * 8 var bigger_stride : array< vec3< f32> , 8 > ;
// 配列: // - アライメントは4 = AlignOf(f32) // - 要素ストライドは4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4 // Bがdrawまたはdispatchコマンドのバインディングにおける実効バッファバインディングサイズの場合、要素数は: // N_runtime = floor(B / element stride) = floor(B / 4) @group ( 0 ) @binding ( 0 ) var < storage> weights : array< f32> ; // 配列: // - アライメントは16 = AlignOf(vec3<f32>) = 16 // - 要素ストライドは16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>)) // = roundUp(16,12) // Bがdrawまたはdispatchコマンドのバインディングにおける実効バッファバインディングサイズの場合、要素数は: // N_runtime = floor(B / element stride) = floor(B / 16) var < storage> directions : array< vec3< f32>> ;
14.4.4. 値の内部レイアウト
この節では、値全体の配置が仮定されている場合に、host-shareable 値の内部がバッファーのバイト位置にどのように配置されるかを説明する。 これらのレイアウトは、値の型、および構造体メンバー上のalign 属性とsize 属性に依存する。
値が配置されるバッファーバイトオフセットは、型のアラインメント要件を満たさなければならない: 型 T の値が バッファーオフセット k に配置される場合、ある 非負整数 c について、k = c × AlignOf(T) である。
データは、アドレス空間にかかわらず同一に現れることになる。
注: bool 型は host-shareable ではない。 WGSL は、bool 値が 4 バイトのサイズと アラインメントを持つことを指定するが、 bool 値の内部レイアウトは指定しない。
u32 または i32 型の値 V が host-shared バッファーのバイトオフセット k に配置される場合:
-
バイト k は V のビット 0 から 7 を含む
-
バイト k+1 は V のビット 8 から 15 を含む
-
バイト k+2 は V のビット 16 から 23 を含む
-
バイト k+3 は V のビット 24 から 31 を含む
注: i32 は 2 の補数表現を使用するため、符号ビットは ビット位置 31 にあることを思い出すこと。
64 ビット整数レイアウト: WebGPU API の一部の機能は、64 ビットの 符号なし整数値をバッファに書き込む。そのような値 V が ホスト共有バッファのバイトオフセット k に現れるとき:
-
バイト k は V のビット 0 から 7 を含む
-
バイト k+1 は V のビット 8 から 15 を含む
-
バイト k+2 は V のビット 16 から 23 を含む
-
バイト k+3 は V のビット 24 から 31 を含む
-
バイト k+4 は V のビット 32 から 39 を含む
-
バイト k+5 は V のビット 40 から 47 を含む
-
バイト k+6 は V のビット 48 から 55 を含む
-
バイト k+7 は V のビット 56 から 63 を含む
型 f32 の値 V は、 IEEE-754 binary32 形式で表現される。 これは 1 つの符号ビット、8 個の指数ビット、および 23 個の仮数部ビットを持つ。 V がホスト共有バッファのバイトオフセット k に配置されるとき:
-
バイト k は仮数部のビット 0 から 7 を含む。
-
バイト k+1 は仮数部のビット 8 から 15 を含む。
-
バイト k+2 のビット 0 から 6 は仮数部のビット 16 から 22 を含む。
-
バイト k+2 のビット 7 は指数のビット 0 を含む。
-
バイト k+3 のビット 0 から 6 は指数のビット 1 から 7 を含む。
-
バイト k+3 のビット 7 は符号ビットを含む。
型 f16 の値 V は、 IEEE-754 binary16 形式で表現される。 これは 1 つの符号ビット、5 個の指数ビット、および 10 個の仮数部ビットを持つ。 V がホスト共有バッファのバイトオフセット k に配置されるとき:
-
バイト k は仮数部のビット 0 から 7 を含む。
-
バイト k+1 のビット 0 から 1 は仮数部のビット 8 から 9 を含む。
-
バイト k+1 のビット 2 から 6 は指数のビット 0 から 4 を含む。
-
バイト k+1 のビット 7 は符号ビットを含む。
注記: 上記の規則は、 ホスト共有バッファ内の数値が リトルエンディアン形式で格納されることを意味する。
アトミック型
atomic<T> の値 V がホスト共有バッファに配置されるとき、
それは基礎となる型 T の値と同じ内部レイアウトを持つ。
ベクトル型 vecN<T> の値 V が ホスト共有バッファのバイトオフセット k に配置されるとき:
-
V.x はバイトオフセット k に配置される
-
V.y はバイトオフセット k + SizeOf(T) に配置される
-
N ≥ 3 の場合、V.z はバイトオフセット k + 2 × SizeOf(T) に配置される
-
N ≥ 4 の場合、V.w はバイトオフセット k + 3 × SizeOf(T) に配置される
行列型 matCxR<T> の値 V が ホスト共有バッファのバイトオフセット k に配置されるとき:
-
V の列ベクトル i は、バイトオフセット k + i × AlignOf(vecR<T>) に配置される
配列型 A の値が ホスト共有メモリバッファのバイトオフセット k に配置されるとき、 次のようになる:
-
配列の要素 i は、バイトオフセット k + i × StrideOf(A) に配置される
構造体型 S の値がホスト共有メモリバッファのバイトオフセット k に配置されるとき、 次のようになる:
-
構造体値の i'th メンバーは、バイトオフセット k + OffsetOfMember(S,i) に配置される。 § 14.4.2 構造体メンバーレイアウトを参照。
14.4.5. アドレス空間レイアウト制約
storage および uniform アドレス空間は、 この節で説明される異なるバッファレイアウト制約を持つ。
アドレス空間は、uniform を除きすべて、 storage アドレス空間と同じ 制約を持つ。
変数によって直接的または間接的に参照されるすべての構造体型および配列型は、 その変数のアドレス空間の制約に従わなければならない。 アドレス空間の制約に違反すると、シェーダー作成エラーが発生する。
本節では、RequiredAlignOf(S, C) を、 ホスト共有可能型または固定フットプリント型 S の値がアドレス空間 C で 使用される場合の、値のバイトオフセットアライメント要件として定義する。
| ホスト共有可能型または固定フットプリント型 S、 ただし S が C に出現可能であると仮定する | RequiredAlignOf(S, C)、 uniform_buffer_standard_layout がサポートされている、または C が uniform ではない場合 | RequiredAlignOf(S, C)、 uniform_buffer_standard_layout がサポートされておらず、かつ C が uniform である場合 |
|---|---|---|
| bool、i32、u32、f32、 または f16 | AlignOf(S) | AlignOf(S) |
| atomic<T> | AlignOf(S) | AlignOf(S) |
| vecN<T> | AlignOf(S) | AlignOf(S) |
| matCxR<T> | AlignOf(S) | AlignOf(S) |
| array<T, N> | AlignOf(S) | roundUp(16, AlignOf(S)) |
| array<T> | AlignOf(S) C が uniform の場合は許可されない | 許可されない |
| struct S | AlignOf(S) | roundUp(16,
AlignOf(S)) |
型 T の構造体メンバーは、アドレス空間 C について、 構造体の先頭からのバイトオフセットが RequiredAlignOf(T, C) の倍数で なければならない:
OffsetOfMember(S, i) = k × RequiredAlignOf(T, C)
ここで k は非負整数であり、構造体 S の i 番目のメンバーは 型 T を持つ
要素型 T の配列は、アドレス空間 C について、 RequiredAlignOf(T, C) の倍数である 要素ストライドを持た なければならない:
StrideOf(array<T, N>) = k × RequiredAlignOf(T, C)
StrideOf(array<T>) = k × RequiredAlignOf(T, C)
ここで k は正の整数である
uniform_buffer_standard_layout が サポートされていない場合、 uniform アドレス空間は次のことを要求する:
-
配列要素は 16 バイト境界にアライメントされる。 すなわち、ある正の整数 k' について StrideOf(array<T,N>) = 16 × k' である。
-
構造体メンバー自体が構造体型
Sを持つ場合、そのメンバーの先頭から 後続の任意のメンバーの先頭までのバイト数は、 少なくとも roundUp(16, SizeOf(S)) で なければならない。
注: 次の例は構造体メンバーでalignやsize属性を使用し、uniformバッファのレイアウト要件を満たす方法を示しています。 特に、こうした手法を用いてstd140レイアウトのGLSLバッファをWGSLに機械的に変換することが可能です。
struct S { x : f32} struct Invalid { a : S , b : f32// 無効: a と b の間のオフセットが 4 バイトだが、少なくとも 16 必要 } @group ( 0 ) @binding ( 0 ) var < uniform> invalid : Invalid ; struct Valid { a : S , @align ( 16 ) b : f32// 有効: a と b の間のオフセットは 16 バイト } @group ( 0 ) @binding ( 1 ) var < uniform> valid : Valid ;
struct small_stride { a : array< f32, 8 > // ストライド 4 } // 無効、ストライドは16の倍数でなければならない @group ( 0 ) @binding ( 0 ) var < uniform> invalid : small_stride ; struct wrapped_f32 { @size ( 16 ) elem : f32} struct big_stride { a : array< wrapped_f32 , 8 > // ストライド 16 } @group ( 0 ) @binding ( 1 ) var < uniform> valid : big_stride ; // 有効
14.5. メモリモデル
WGSLは一般にVulkanメモリモデルに従います。 この節の残りではWGSLプログラムがVulkanメモリモデルにどのようにマップされるかを説明します。
注: Vulkanメモリモデルは 形式的なAlloyモデルのテキスト版です。
14.5.1. メモリ操作
WGSLでは、読み取りアクセスは Vulkanメモリモデルのメモリ読み取り操作に相当します。 WGSLでは、書き込みアクセスは Vulkanメモリモデルのメモリ書き込み操作に相当します。
読み取りアクセスは、 下記のいずれかを呼び出しが実行したときに発生します:
-
Load Ruleの評価
-
次を除くテクスチャ組み込み関数のいずれか:
-
atomicStore以外のatomic組み込み関数
-
workgroupUniformLoad組み込み関数
書き込みアクセスは、 下記のいずれかを呼び出しが実行したときに発生します:
-
textureStore組み込み関数
-
atomicLoad以外のatomic組み込み関数
-
atomicCompareExchangeWeakは、戻り値の
exchangedメンバーがtrueの時だけ書き込みを行います
-
Atomic read-modify-write組み込み関数は 読み取りアクセスと書き込みアクセス両方となる単一のメモリ操作を行います。
読み取り・書き込みアクセスは他の場合に発生しません。 これらはVulkanメモリモデルでメモリ操作と呼ばれます。
メモリ操作は、その操作で使用される特定のメモリ ビューに関連付けられた位置の集合だけにアクセスする。たとえば、 複数のメンバーを含む struct から u32 にアクセスする メモリ読み取りは、その u32 メンバーに関連付けられたメモリ位置だけを読み取る。
注: ベクターのコンポーネントに対する書き込みアクセスは そのベクターに関連するすべてのメモリロケーションをアクセスする場合があります。
struct S { a : f32, b : u32, c : f32} @group ( 0 ) @binding ( 0 ) var < storage> v : S ; fn foo () { let x = v . b ; // v.aやv.cのメモリロケーションはアクセスしない。 }
14.5.2. メモリモデル参照
各モジュールスコープのリソース変数は、 一意なgroup と binding の組に対するメモリモデル参照を 形成する。 その他の各変数(すなわち、function、 private、 および workgroup アドレス空間内の変数)は、 その変数の存続期間にわたって一意なメモリモデル参照を形成する。
14.5.3. スコープ付き操作
呼び出しがスコープ付き操作を実行する場合、それは1つまたは2つの呼び出し集合に影響します。 これらの集合はメモリスコープと実行スコープです。メモリスコープは、操作によるメモリ内容の更新を観測できる呼び出し集合を指定します。 同期組み込み関数の場合、影響を受ける全てのメモリ操作は、関数より前にプログラム順で行われたものが、 関数より後にプログラム順で行われた操作に可視となります。 実行スコープは、 操作に参加できる呼び出し集合を指定します(§ 15.6 集合操作参照)。
アトミック組み込み関数は、アトミック操作にマッピングされ、そのメモリスコープは次の通りです:
同期組み込み関数は、実行およびメモリスコープがWorkgroupの制御バリアにマッピングされます。
暗黙的・明示的な微分は、暗黙的にquad実行スコープを持ちます。
注:
生成されたシェーダーでVulkanメモリモデルが有効化されていない場合は、QueueFamilyの代わりにDeviceスコープを使用します。
14.5.4. メモリ意味論
全てのアトミック組み込み関数はRelaxed
メモリ意味論を使用し、ストレージクラス意味論はありません。
注: WGSLのアドレス空間はSPIR-Vのストレージクラスに相当します。
workgroupBarrierはAcquireReleaseメモリ意味論とWorkgroupMemory意味論を使用します。
storageBarrierはAcquireReleaseメモリ意味論とUniformMemory意味論を使用します。
textureBarrierはAcquireReleaseメモリ意味論とImageMemory意味論を使用します。
注:
workgroupBarrierとstorageBarrierを組み合わせると、AcquireRelease
順序意味論と両方のWorkgroupMemory・UniformMemoryメモリ意味論を使用します。
注: いかなるアトミック・同期組み込み関数もMakeAvailableや
MakeVisible意味論は使用しません。
14.5.5. privateとnon-private
storage
や
workgroupアドレス空間における非アトミックな読み取りアクセスはすべて
non-privateと見なされ、NonPrivatePointer | MakePointerVisibleメモリオペランドをWorkgroupスコープで持つ読み取り操作に対応します。
storage
や
workgroupアドレス空間における非アトミックな書き込みアクセスはすべて
non-privateと見なされ、NonPrivatePointer | MakePointerAvailableメモリオペランドをWorkgroupスコープで持つ書き込み操作に対応します。
handle
アドレス空間における非アトミックな読み取りアクセスは
non-privateと見なされ、
NonPrivateTexel | MakeTexelVisibleメモリオペランドをWorkgroupスコープで持つ読み取り操作に対応します。
handle
アドレス空間における非アトミックな書き込みアクセスは
non-privateと見なされ、
NonPrivateTexel | MakeTexelAvailableメモリオペランドをWorkgroupスコープで持つ書き込み操作に対応します。
15. 実行
§ 1.1 概要では、シェーダーがどのように呼び出され、invocationに分割されるかを説明しています。 このセクションでは、invocationが個別および集合的にどのように実行されるかに関する追加の制約について説明します。
15.1. Invocation内のプログラム順序
WGSLモジュール内の各ステートメントは、実行中に0回以上実行される可能性があります。 特定のinvocationにおいて、あるステートメントの各実行は一意の 動的ステートメントインスタンス を表します。
ステートメントが式を含む場合、ステートメントの意味論は以下を決定します。
-
式がステートメント実行の一部として評価されるかどうか。
-
ステートメント内の独立した式同士の評価の相対的な順序。
式のネストは、評価を完了するために満たす必要があるデータ依存関係を定義します。
すなわち、ネストされた式は、囲っている式を評価する前に評価されなければなりません。
式のオペランドの評価順序はWGSLでは左から右です。
例えば、foo() + bar()では、foo()がbar()より先に評価されます。
詳しくは§ 8 式を参照してください。
WGSLモジュール内のステートメントは、制御フロー順に実行されます。 詳しくは§ 9 ステートメントおよび§ 11.2 関数呼び出しを参照してください。
15.2. 一様性
集合的操作 (例えば、バリア、微分、または暗黙的に計算された微分に依存するテクスチャ操作など)は、GPU上で同時に動作する複数のinvocation間の協調が必要です。 この操作は、すべてのinvocationが同時に、つまり一様な制御フローで実行された場合に、正しくかつ移植性を持って動作します。
逆に、invocationの厳密な部分集合のみが操作を実行した場合、すなわち非一様な制御フローで実行された場合、 正しくないまたは移植性のない動作が発生します。 非一様な制御依存は、制御フローステートメントの挙動が非一様な値に依存することで生じます。
例えば、異なるinvocationが if、 break-if、 while、 forの条件で異なる値を計算した場合や、 switchのセレクターで異なる値になった場合、 または短絡評価の二項演算子(
&&や||)の左オペランドで異なる値になった場合などに非一様な制御依存が生じます。
これらの非一様な値は、多くの場合、静的に一様であると証明されていない特定のソースに遡ることができます。 これらのソースには、以下が含まれますが、これに限定されません:
正しく移植可能な振る舞いを保証するため、WGSL 実装は必ず 静的な一様性解析を実行し、各集団操作が一様な 制御フローで実行されることを証明しようとする。 後続の小節でこの解析について説明する。
一様性失敗は、 必ず 発生する。 これは、一様性 解析が、特定の集団操作が一様な 制御フローで実行されることを証明できない場合である。
-
一様性失敗が 導関数を計算する組み込み 関数について発生した場合、 derivative_uniformity 診断が発生する。
-
一様性失敗が同期 組み込みについて発生した場合、 エラー診断が発生し、 その結果、シェーダー作成エラーとなる。
-
一様性失敗がサブグループまたは クアッド組み込みについて発生した場合、subgroup_uniformity 診断が発生する
-
診断の発生位置は、その 組み込みの呼び出し箇所の位置、 または subgroupShuffleUp、 subgroupShuffleDown、または subgroupShuffleXor の場合は一様であることが要求されるパラメーターの位置である
-
15.2.1. 用語と概念
以下の定義は単に参考情報であり、次の小節の解析が何を計算しているのかについての直観を与えようとするものである。 これらの概念、およびプログラムがいつ妥当であるか、または一様性規則に違反するかを実際に定義するのは、 その解析である。
与えられた呼び出しのグループについて:
-
与えられたスコープ内のすべての呼び出しが、プログラム内のある時点でロックステップで実行されているかのように 実行される場合、その時点は与えられた一様性スコープについて一様制御フローを持つと言われる。
-
ワークグループ一様性スコープ:計算シェーダーステージでは、一様性スコープは 同じワークグループ内のすべての呼び出しである。
-
描画 一様性スコープ:他のシェーダーステージでは、 一様性スコープは同じ 描画コマンド内の、そのエントリーポイントに対するすべての呼び出しである。
-
サブグループ一様性スコープ:もし subgroup_uniformity 機能が サポートされる場合、 サブグループおよび クアッド組み込み関数についての一様性スコープは、代わりに同じサブグループ内のすべての 呼び出しである。
-
-
式が一様制御フロー内で実行され、すべての呼び出しが 同じ値を計算する場合、それは一様値であると言われる。
-
ローカル変数が生存しているすべての時点で、呼び出しがそのローカル変数について同じ値を保持している場合、 それは一様変数であると言われる。
15.2.2. 一様性解析の概要
残りのサブセクションでは、集合演算が一様制御フロー内でのみ実行されることを検証する静的解析について定めます。 subgroup_uniformity機能がサポートされている場合、複数の一様性スコープが存在します。 この解析はスコープごとに一度ずつ実行されます。
注: 解析はスコープごとに1回実行されるものとして記述されていますが、実装によってはすべてのスコープをまとめた単一の解析を行ってもかまいません。 ワークグループおよびドロー の一様性スコープは、異なるシェーダーステージで動作し、それぞれがシェーダーステージ中で最大の一様性スコープを表すため、事実上等価です。
この解析は動的エラーが発生しないことを前提としています。 動的エラーが発生するシェーダーステージは、たとえ一様性解析の結果がどうであれ、すでに移植性がありません。
各関数は2つのことを満たすように解析されます:
-
他の関数を呼び出す際、一様性要件が満たされていること
-
呼び出される際にも一様性要件が満たされていること
この解析の一部として、各関数について、その呼び出し元の解析を助けるためのメタデータを計算します。 つまり、まず呼び出しグラフを構築し、標準ライブラリ以外の関数を呼ばない関数(葉)からエントリーポイントに向かって順に解析します。 こうすることで、関数を解析する時点で、その呼び出し先全てのメタデータがすでに計算されていることが保証されます。 言語仕様上、再帰は禁止されているため、サイクルに陥る心配はありません。
注記:これは言い換えれば、関数を「(間接的に)呼び出し先である」部分順序でトポロジカルソートし、その順序で解析するということです。
さらに、各関数呼び出しについて、解析はその呼び出しが一様な制御フローであることを証明できなかった場合に発生する発生規則の集合を計算・伝播します。 これを呼び出しの潜在的発生セットと呼びます。 このセットの要素は以下のいずれかです:
-
微分計算に依存する関数の場合はderivative_uniformity
-
§ 17.12 サブグループ組み込み関数や§ 17.13 クアッド演算の関数の場合はsubgroup_uniformity
-
フィルターできない一様性要件のための無名の発生規則
-
これは、同期関数に依存する計算シェーダー関数で使われます。
-
15.2.3. 関数の均一性要件の分析
各関数は2つの段階で分析されます。
最初の段階では、関数の構文をたどりながら、以下の小節に記載された規則に従って有向グラフを構築します。 第2段階ではそのグラフを探索し、この関数の呼び出しに関する制約を計算し、 必要に応じて均一性失敗を引き起こすことがあります。
-
プログラムの特定の地点が均一な制御フローで実行されなければならない。
-
式が均一な値でなければならない。
-
変数が均一な変数でなければならない。
-
メモリに保存され、ポインタ経由でロードされる可能性がある値は、均一な値でなければならない。
エッジは、ソースノードに対応するステートメントからターゲットノードに対応するステートメントへの含意として理解できます。
例えば、workgroupBarrier組み込み関数は均一な制御フロー内でのみ呼び出されなければならないという均一性要件があります。
これを表現するために、RequiredToBeUniform.errorから
workgroupBarrierの呼び出し箇所に対応するノードへエッジを追加します。
これは、RequiredToBeUniform.errorは命題Trueに対応し、
RequiredToBeUniform.error -> X は Xが真であることを意味します。
逆に、均一性を保証できないもの(例えばスレッドIDを保持する変数など)については、対応するノードからMayBeNonUniformノードへエッジを追加します。 これを理解する方法として、MayBeNonUniformは命題Falseに対応し、X -> MayBeNonUniform は Xが偽であることを意味します。
この解釈の結果、RequiredToBeUniform.errorから到達可能なすべてのノードは、 プログラムが有効であるために均一である必要があるものに対応し、MayBeNonUniformから到達可能なすべてのノードは、 均一性を保証できないものに対応します。 従って、RequiredToBeUniform.errorからMayBeNonUniformへの経路が存在する場合、 均一性違反が発生し、均一性失敗が発生します。
RequiredToBeUniform.warningおよびRequiredToBeUniform.infoノードも同様に使われますが、 これらは警告や情報の診断を出すべき場合を判定するのに使われます:
-
RequiredToBeUniform.warningからMayBeNonUniformへの経路が存在する場合、警告 診断が発生します。
-
RequiredToBeUniform.infoからMayBeNonUniformへの経路が存在する場合、情報 診断が発生します。
§ 2.3 診断で説明されているように、より重大度の高い診断が生成されている場合、低い重大度の診断は破棄されることがあります。
各関数について、2つのタグが計算されます:
-
呼び出し箇所タグ は関数の呼び出し箇所に関する制御フローの均一性要件を記述します。
-
関数タグ は関数の均一性への影響を記述します。
各形式パラメータごとに、1つまたは2つのタグが計算されます:
-
パラメータタグ はパラメータ値の均一性要件を記述します。
-
パラメータ戻り値タグは、パラメータの均一性が関数の戻り値の均一性にどのように影響するかを記述します。
-
ポインタパラメータタグは、パラメータ型が関数アドレス空間へのポインタの場合。 このタグは、関数呼び出しの実行中にパラメータが指すメモリ内の値が非均一になる可能性があるかどうかを記述します。
| 呼び出し箇所タグ | 説明 |
|---|---|
| CallSiteRequiredToBeUniform.S, ここで S は次のいずれかの重大度: error, warning, info。 |
関数は均一な制御フローからのみ呼び出さなければなりません。
そうでない場合、重大度Sの診断が発生します。
potential-trigger-setと関連付けられています。 |
| CallSiteNoRestriction | 関数は非均一な制御フローから呼び出すことができます。 |
| 関数タグ | 説明 |
|---|---|
| ReturnValueMayBeNonUniform | 関数の戻り値は非均一である可能性があります。 |
| NoRestriction | 関数は非均一性を導入しません。 |
| パラメータタグ | 説明 |
|---|---|
| ParameterRequiredToBeUniform.S, ここで S は次のいずれかの重大度: error, warning, info。 |
パラメータは均一な値でなければなりません。
パラメータ型がポインタの場合、メモリビュー自体(その内容は必ずしも含まない)は均一でなければなりません。
そうでない場合、重大度Sの診断が発生します。
potential-trigger-setと関連付けられています。 |
| ParameterContentsRequiredToBeUniform.S, ここで S は次のいずれかの重大度: error, warning, info。 |
ポインタパラメータが指すメモリに格納された値は均一な値でなければなりません。
そうでない場合、重大度Sの診断が発生します。
potential-trigger-setと関連付けられています。 |
| ParameterNoRestriction | パラメータ値には均一性要件はありません。 |
| パラメータ戻り値タグ | 説明 |
|---|---|
| ParameterReturnContentsRequiredToBeUniform | このパラメータは必ずユニフォーム値でなければならず、そうでなければ戻り値がユニフォーム値になりません。 パラメータがポインタである場合は、そのポインタが指すメモリに格納されている値もユニフォームでなければなりません。 |
| ParameterReturnNoRestriction | パラメータ値には均一性要件はありません。 |
| ポインタパラメータタグ | 説明 |
|---|---|
| PointerParameterMayBeNonUniform | ポインタパラメータが指すメモリの値は、関数呼び出し後に非均一になる可能性があります。 |
| PointerParameterNoRestriction | ポインタパラメータが指すメモリの値の均一性は関数呼び出しによって影響を受けません。 |
以下のアルゴリズムは、与えられた関数についてこれらのタグを計算する方法を説明します:
-
次のノードを作成します:
-
RequiredToBeUniform.error, RequiredToBeUniform.warning, および RequiredToBeUniform.info。 これらをまとめてRequiredToBeUniform.Sノードと呼びます。
-
それぞれのノードは、potential-trigger-setと関連付けられており、初期状態では空です。
-
-
MayBeNonUniform
-
CF_startは、関数実行開始時の制御フローの均一性要件を表します。
-
param_i(iは関数の形式パラメータの範囲)
-
関数に戻り値型がある場合は、Value_returnノードを作成します。
-
-
§ 15.2.4 ポインタのデシュガーで説明されているようにポインタをデシュガーします。
-
関数アドレス空間へのポインタ型の形式パラメータごとに、次のノードを作成します:
-
param_i_contents: メモリビューの内容の均一性を表します。
-
Value_return_i_contents: メモリビューの内容の均一性に対する関数の影響を表します。
-
-
-
関数の構文をたどり、関数本体の開始制御フローとしてCF_startを使い、次節(§ 15.2.5 関数スコープ変数値分析、§ 15.2.6 ステートメントの均一性規則、§ 15.2.7 関数呼び出しの均一性規則、§ 15.2.8 式の均一性規則)の規則に従ってノードとエッジをグラフに追加します。
-
この段階で追加されるノードは内部ノードと呼びます。
-
-
以下の初期化を行います:
-
関数タグはNoRestrictionに初期化されます。
-
呼び出し箇所タグはCallSiteNoRestrictionに初期化されます。
-
各param_iについてのパラメータタグはParameterNoRestrictionに初期化されます。
-
各param_iについてのパラメータ戻り値タグはParameterReturnNoRestrictionに初期化されます。
-
各param_iについて、存在する場合はポインタパラメータタグをPointerParameterNoRestrictionに初期化します。
-
-
重大度Sについて、{error, warning, info}の順に、以下を実行します:
-
R.SをRequiredToBeUniform.Sから到達可能な未訪問ノードの集合とする。
-
R.S内の内部ノードを訪問済みとしてマークする。
-
PTSをRequiredToBeUniform.Sに関連付けられたpotential-trigger-setとする。
-
R.SにMayBeNonUniformノードが含まれている場合、均一性失敗を発生させる:
-
各t∈PTSについて、重大度Sおよび発生規則tで診断を発生させる。
-
-
そうでない場合:
-
もしR.SにCF_startが含まれ、呼び出し箇所タグが初期化後に更新されていなければ、 呼び出し箇所タグをCallSiteRequiredToBeUniform.Sに設定し、 そのpotential-trigger-setをPTSに設定します。
-
R.Sに含まれる各param_iについて、 対応するパラメータタグが初期化後に更新されていなければ、 そのタグをParameterRequiredToBeUniform.Sに設定し、 そのpotential-trigger-setをPTSに設定します。
-
R.Sに含まれる各param_i_contentsについて、 対応するパラメータタグが初期化後に更新されていなければ、 そのタグをParameterContentsRequiredToBeUniform.Sに設定し、 そのpotential-trigger-setをPTSに設定します。
-
-
-
すべての内部ノードの訪問済み状態を解除します。
-
Value_returnが存在する場合、 VRをValue_returnから到達可能なノードの集合とします。
-
VRにMayBeNonUniformが含まれていれば、 関数タグをReturnValueMayBeNonUniformに設定します。
-
VRに含まれる各param_iについて、 対応するパラメータ戻り値タグをParameterReturnContentsRequiredToBeUniformに設定します。
-
-
各Value_return_i_contentsノードについて、 VRiをValue_return_i_contentsから到達可能なノードの集合とします。
-
VRiにMayBeNonUniformが含まれていれば、 対応するポインタパラメータタグをPointerParameterMayBeNonUniformに設定します。
-
注: この時点でグラフ全体は破棄可能です。 上記のタグだけが、この関数の呼び出し元を分析するために記憶しておくべき情報です。 しかし、グラフにはより有益な診断を提供するための情報が含まれています。 例えば、ある関数内の値が均一であることを証明できない場合、 それが他の関数で均一性失敗を引き起こす原因となります。 有益な診断では、その非均一な値と、診断の発生箇所となる関数呼び出しも記述されます。
15.2.4. ポインタのデシュガー処理
関数アドレス空間内のポインタ型の各パラメータは、 パラメータをデリファレンスした値と同等の初期値を持つローカル変数宣言としてデシュガーされます。 つまり、関数アドレス空間のポインタはローカル変数宣言のエイリアスとして扱われます。 初期値の代入は、i番目のパラメータに対するparam_i_contentsノードへのエッジを生成します(すなわち、V(e)はparam_i_contentsです)。
各let宣言 Lで、 effective-value-typeがポインタ型の場合、次のようにデシュガーされます:
-
初期化式の各部分式SEをポストオーダーの深さ優先探索で訪問する:
-
(更新された可能性のある)Lの初期化式を記録する。
このデシュガー処理により、ポインタのroot識別子を各使用箇所で直接露出させ、後続の解析を簡素化します。
注: 均一性解析の目的では、型チェックはこのデシュガー前後の両方で行われるものとします。
fn foo ( p : ptr< function, array< f32, 4 >> , i : i32) -> f32{ let p1 = p ; var x = i ; let p2 = & (( * p1 )[ x ]); x = 0 ; * p2 = 5 ; return ( * p1 )[ x ]; } // 均一性解析用に変換した foo の等価バージョン fn foo_for_analysis ( p : ptr< function, array< f32, 4 >> , i : i32) -> f32{ var p_var = * p ; // p 用の変数を導入 let p1 = & p_var ; // p1用に変数を使用 var x = i ; let x_tmp1 = x ; // xの値をキャプチャ let p2 = & ( p_var [ x_tmp1 ]); // p1の初期化式を置換 x = 0 ; * ( & ( p_var [ x_tmp1 ])) = 5 ; // p2の初期化式を置換 return ( * ( & p_var ))[ x ]; // p1の初期化式を置換 }
15.2.5. 関数スコープ変数の値解析
特定の文における関数スコープの変数の値は、 その変数に到達する代入と、場合によっては初期値で解析できます。
代入は、次のいずれかの条件を満たす場合完全代入です:
-
変数のeffective-value-typeがスカラー型である、または
-
変数のeffective-value-typeが複合型であり、 複合型の各要素に値が代入されている場合。
それ以外の代入は部分代入です。
参照型の式で、以下のいずれかの場合完全参照です:
ポインタ型の式で、以下のいずれかの場合完全ポインタです:
注: この解析の目的では、ポインタ型の形式パラメータが完全ポインタとなる場合は不要です。
完全参照および同じく完全ポインタは、 該当する元変数xのすべてのメモリ位置のメモリビューです。
完全参照でない参照は部分参照です。 部分参照は次のいずれかです:
メンバーが1つの構造体型と、その型を格納する変数を考えます:
struct S { member : i32; } fn foo () { var v : S ; }
この場合、vは完全参照、v.memberは部分参照です。
両者のメモリビューは同じ位置をカバーしますが、vの格納型はS、v.sの格納型はi32です。
要素数1の配列でも同様の状況が発生します:
fn foo () { var arr : array< i32, 1 > ; }
この場合、arrは完全参照、arr[0]は部分参照です。
両者のメモリビューは同じ位置をカバーしますが、arrの格納型はarray<i32,1>、arr[0]の格納型はi32です。
解析を簡素化するため、いかなる種別の部分参照による代入は、 関連する元変数のすべてのメモリ位置を変更しないものとして扱います。 このため解析は保守的となり、実際より多くのプログラムで均一性失敗が発生しうることになります。
後続の節の均一性規則で、RHSValueとして使われる関数スコープ変数の値は、 RHSValue式評価前の変数値を意味します。 LHSValueとして使われる場合は、式が現れる文の実行後の変数値を意味します。
変数への複数の代入は、制御フロー文や部分代入により、その変数の使用箇所に到達する可能性があります。 解析では、制御フロー文から到達する複数の代入を、 各制御フロー出口に到達する代入集合の和集合として結合します。
次の表は、関数スコープ変数への複数の代入の結合規則を示します。
均一性グラフでは、各結合は結果ノードから値の由来ノードへのエッジです。
任意の変数xについて記述します。以下の記号を使います:
-
Vin(S)は文S実行前の
xの値です。 -
Vout(S)は文S実行後の
xの値です。 -
Vout(prev)は現在の文実行前の
xの値です。 -
Vin(next)は次の文実行前の
xの値です。 -
V(e)は後続の節で使われる式の値ノードです。
-
V(0)は
xのeffective-value-typeのゼロ値です。
| 文 | 結果 | 結果からのエッジ |
|---|---|---|
| var x; | Vin(next) | V(0) |
|
var x = e; | Vin(next) |
V(e)
注記: これは 完全代入です。変数xへの。 |
|
x = e; | ||
|
r = e; ここでrは変数xへの 完全参照 | ||
|
r = e; ここでrは変数xへの 部分参照 | Vout(S) |
V(e)、Vout(prev)
注記: これはxへの 部分代入です。 注記: 部分代入には 以前の値が含まれる。 その代入は、格納されているコンポーネントの部分集合だけを書き込むか、 または書き込まれる値の型が、格納型 起点変数のものと異なる。 |
|
s1 s2 ここでNextはs1の振る舞いの中にある。 注記: s1はしばしばセミコロンで終わる。 | Vin(s2) | Vout(s1) |
|
if e s1 else s2 ここでNextはs1とs2両方の振る舞いの中にある | Vin(next) | Vout(s1)、Vout(s2) |
|
if e s1 else s2 ここでNextはs1の振る舞いの中にあり、s2の中にはない | Vin(next) | Vout(s1) |
|
if e s1 else s2 ここでNextはs2の振る舞いの中にあり、s1の中にはない | Vin(next) | Vout(s2) |
| loop { s1 continuing { s2 } } | Vin(s1) | Vout(prev)、 Vout(s2)(s1の振る舞いが{Next,Continue}と交差している場合) |
| loop { s1 continuing { s2 } } | Vin(s2) | Vout(s1)(Nextがs1の振る舞い中にあるとき)、 Vout(si) (s1内で振る舞いが{Continue}となってs2へ制御が移る各siについて) |
| loop { s1 continuing { s2 } } | Vin(next) | Vout(s2)(Breakがs1の振る舞いの中にある場合)、 Vout(si) (s1内で振る舞いが{Break}となってnextへ制御が移る各siについて) |
| switch e { case _: s1 case _: s2 ... case _: s3 } | Vin(si) | Vout(prev) |
| switch e { case _: s1 case _: s2 ... case _: s3 } | Vin(next) | Vout(si)、
(振る舞いにNextまたはBreakを含む各siについて)、 Vout(sj) (内部で振る舞いが{Break}となってnextへ制御が移る各sjについて) |
その他のすべての文(関数呼び出しを除く)については、Vin(next)はVout(prev)と同値です。
注: デシュガー方法は文の動作分析と同じです。
15.2.6. 文の均一性規則
文の解析規則は、引数として文自体と、その文の冒頭に対応する制御フローのノード(以下「CF」と記述)を受け取り、以下の両方を返します:
-
その文の出口に対応する制御フローノード
-
グラフに追加する新しいノードとエッジの集合
下の表において、(CF1, S) => CF2 は、「制御フロー CF1 で始めて S に対して解析を実行し、
必要な変更をグラフに適用し、その結果の制御フローを
CF2 と名付ける」ことを意味する。
同様に、(CF1, E) => V は、「制御フロー CF1 で始めて式 E に対して解析を実行し、
必要な変更をグラフに適用し、その結果の値ノードを V と名付ける」ことを意味する
(式の解析については次節を参照)。
この式の評価は、代入の左辺の一部ではない任意の式に用いられ、
RHSValue と呼ばれる。
代入の
左辺の一部である式についても同様の規則の集合、
LHSValue
があり、これを LHSValue: (CF, E) => L と表記する。値の一様性に対応するノードを
計算する代わりに、参照先の変数の一様性に対応するノードを計算する。
注: LHSValues には、インクリメント文および デクリメント 文内の式が含まれる。
注: RHSValues には、代入文の右辺の一部である式、 または代入文、インクリメント文、デクリメント文の一部ではない式が含まれる。
複数のエッジを作成する必要がある場合、X -> {Y, Z} を
X -> Y, X -> Z の短縮表記として用いる。
ループの解析では、次のパターンを用いる:
-
ノード CF' は、各反復の開始時における制御フローの一様性をモデル化する。
-
ノード CF1 は、ループ本体 s1 の終了時における制御フローの一様性をモデル化する。
-
ノード CF2 は、continuing ブロック文 s2 の終了時における制御フローの一様性をモデル化する。
-
エッジ CF' -> CF1 および CF' -> CF2 は、 ループの終了時における制御フローの一様性が、次の反復の開始時における一様性に影響する 事実をモデル化する。 これらは、ループ本体文 s1 が break または return のみを行う場合、 すなわち s1 の振る舞いが {Break, Return} の部分集合である場合には存在しない。
-
CF' -> CF エッジは、少なくとも一部の反復の開始時における一様性が、 制御フローがループ文全体に到達した時点の一様性に依存する 事実をモデル化する。
-
ループ全体の振る舞いが {Next} である場合、制御フローの分岐はループが終了する時点までに 解消されると仮定する。 したがって、ループの結果制御フローノードは CF に設定される。 これは、ループを離れる際の一様性が、最初にループへ到達した際の一様性と一致する 事実をモデル化するためである。
-
注: 文の振る舞いの解析により、 ループの振る舞いは {Next}、{Return}、または {Next,Return} のいずれかであることが示される。
| 文 | 新しいノード | 再帰的解析 | 結果の制御フローノード | 新しいエッジ |
|---|---|---|---|---|
| 空文 | CF | |||
| {s} | (CF, s) => CF' | CF' | ||
|
s1 s2, s1 の振る舞いに Next が含まれる 注: s1 はしばしば セミコロンで終わる。 | (CF, s1) => CF1 (CF1, s2) => CF2 | CF2 | ||
|
s1 s2, s1 の振る舞いに Next が含まれない 注: s1 はしばしば セミコロンで終わる。 |
(CF, s1) => CF1 注: s2 は静的に 到達不能であり、再帰的に解析されない。 s2 は一様性解析に寄与しない。 | CF1 | ||
| if e s1 else s2 振る舞いが {Next} | (CF, e) => V (V, s1) => CF1 (V, s2) => CF2 | CF | ||
| if e s1 else s2 別の振る舞い | CFend | CFend | CFend -> {CF1, CF2} | |
| loop {s1} s1 の振る舞いに Return が含まれない | CF' | (CF', s1) => CF1 | CF | CF' -> {CF1, CF}, s1 の振る舞いが {Next,Continue} と交わる場合 |
| CF' -> CF, s1 の振る舞いが {Next,Continue} と交わらない場合 | ||||
| loop {s1} s1 の振る舞いに Return が含まれる | CF' | (CF', s1) => CF1 | CF1 | CF' -> {CF1, CF} s1 の振る舞いが {Next,Continue} と交わる場合 |
| CF' -> CF s1 の振る舞いが {Next,Continue} と交わらない場合 | ||||
| loop {s1 continuing {s2}} s1 の振る舞いが {Break} | (CF, s1) => CF1 | CF |
注: ループは 1 回の 反復しか実行しないため、追加のエッジは不要である。 | |
| loop {s1 continuing {s2}} s1 の振る舞いが {Return} または {Break,Return} | (CF, s1) => CF1 | CF1 | ||
| loop {s1 continuing {s2}} s1 の振る舞いが {Next,Continue} と交わる | CF' | (CF', s1) => CF1 (CF1, s2) => CF2 | CF s1 の振る舞いに Return が含まれない場合 | CF' -> {CF2, CF} |
| CF' s1 の振る舞いに Return が含まれる場合 | ||||
| switch e case _: s_1 .. case _: s_n 振る舞いが {Next} | (CF, e) => V (V, s_1) => CF_1 ... (V, s_n) => CF_n | CF | ||
| switch e case _: s_1 .. case _: s_n 別の 振る舞い | CFend | CFend | CFend -> {CF_1, ..., CF_n} | |
| var x: T; | CF | |||
| break; | ||||
| continue; | ||||
| break if e; | CFend | (CF, e) => V | CFend |
CFend -> V
注: CFend から
V へのエッジは、条件値が非一様である場合、この |
| return; | CF | 各function アドレス空間ポインター引数 i について、 Value_return_i_contents -> Vin(prev)(§ 15.2.5 関数スコープ 変数値解析を参照) | ||
| return e; | (CF, e) => V | CF |
Value_return ->
V
各function アドレス空間ポインター引数 i について、 Value_return_i_contents -> Vin(prev)(§ 15.2.5 関数スコープ 変数値解析を参照) | |
| e1 = e2; | LHSValue:
(CF, e1) => LV (CF, e2) => RV | CF |
LV -> RV
注: LV は値解析からの結果値である。 | |
| _ = e | (CF, e) => V | CF | ||
| let x = e; | (CF, e) => V | CF | ||
| var x = e; | (CF, e) => V | CF | ||
f()引数のない関数呼び出し文 | 関数呼び出し解析を呼び出す: (CF, f()) => Result | CF | ||
f(e1,...,eN)引数を伴う関数呼び出し文 | 関数呼び出し解析を呼び出す: (CF, f(e1,...,eN)) => Result | CF |
この解析の目的上:
-
forループは脱糖される(§ 9.4.4 For Statement を参照) -
whileループは脱糖される(§ 9.4.5 While Statement を参照) -
loop {s}はloop {s continuing {}}として扱われる -
else分岐のないif文は、空の else 分岐を持つもの、 すなわちelse {}で終わるものとして扱われる -
else if分岐を持つif文は、ネストされた単純なif/else文であるかのように扱われる -
defaultで始まる switch_clause は、case _:で始まる switch_clause とまったく同じように振る舞う
性能を最大化するため、実装はしばしば 非一様な制御 フローの量を最小化しようとする。 しかし、呼び出しが一様であると言える時点は、いくつかの要因によって変わる。 WGSL の静的解析は保守的に、 if、switch、および loop 文の終了時に、 その文の振る舞いが {Next} であるならば、一様な制御フローへ戻ると仮定する。 これは、前掲の表において、結果の制御フローノードが入力制御フローノードと同じである こととしてモデル化されている。
15.2.7. 関数呼び出しの均一性規則
最も複雑な規則は関数呼び出しに対するものである:
-
CF を、関数呼び出し式の開始時点の制御フローとする。
-
各引数について、対応する式規則を CF で適用する。対応する 値ノードを arg_i と名付ける
-
Result という名前の新しいノードを作成する
-
Result から CF へのエッジを追加する
-
-
関数の呼び出しサイトタグが CallSiteRequiredToBeUniform.S であるならば:
-
RequiredToBeUniform.S から CF へのエッジを追加する
-
呼び出しサイトタグの potential-trigger-set のメンバーを、 RequiredToBeUniform.S に関連付けられた potential-trigger-set に追加する。
-
-
関数タグが ReturnValueMayBeNonUniform であるならば、 Result から MayBeNonUniform へのエッジを追加する
-
各引数 i について:
-
対応するパラメータータグが ParameterRequiredToBeUniform.S であるならば:
-
RequiredToBeUniform.S から arg_i へのエッジを追加する。
-
パラメーター タグのpotential-trigger-set のメンバーを、 RequiredToBeUniform.S に関連付けられた potential-trigger-set に追加する。
-
-
パラメーター返却タグが ParameterReturnContentsRequiredToBeUniform であるならば、Result から arg_i へのエッジを追加する
-
対応するパラメーターが ポインターパラメータータグ PointerParameterMayBeNonUniform を持つならば、 Vout(call) から MayBeNonUniform へのエッジを追加する
-
パラメーターが function アドレス空間内のポインターである場合、 以前に記録された到達可能なパラメーターについて、Vout(call) から対応する各 arg_i へのエッジを追加する
-
パラメータータグが ParameterContentsRequiredToBeUniform.S であるならば、 RequiredToBeUniform.S から Vout(call) へのエッジを追加する
-
-
注: Vout(call)の定義については§ 15.2.5 関数スコープ変数値分析を参照。
ほとんどの組み込み関数は以下のタグを持ちます:
-
各パラメータについて:
例外リストは以下の通りです:
-
§ 17.11 同期組み込み関数内の関数の呼び出し:
-
呼び出し元タグは次の通りです:
-
CallSiteRequiredToBeUniform.error、potential-trigger-setは、triggering ruleの無名要素で構成されます。ただし、subgroup_uniformityがサポートされていないか、uniformity scopeがsubgroupでない場合。
-
注: trigger ruleには名前がついておらず、フィルタできません。
-
-
それ以外の場合はCallSiteNoRestrictionです。
-
-
また、subgroup_uniformityがサポートされていないか、uniformity scopeがsubgroupでない場合、workgroupUniformLoad呼び出しのパラメータ
pは、parameter tagがParameterRequiredToBeUniform.errorで、potential-trigger-setがtriggering rule(無名要素)で構成される。
-
§ 17.6 導関数組み込み関数、 § 17.7.8 textureSample、 § 17.7.9 textureSampleBias、 § 17.7.10 textureSampleCompareのいずれかの関数呼び出し:
-
呼び出し元タグは次の通りです:
-
subgroup_uniformityがサポートされていないか、uniformity scopeがsubgroupでない場合
-
DFを、その呼び出しサイト位置とtriggering rule derivative_uniformityに対する最近傍の診断フィルタとする。
-
もしDFが存在するなら、そのnew severityパラメータをSとする。
-
もしSがoffなら、呼び出し元タグはCallSiteNoRestrictionです。
-
それ以外の場合、呼び出し元タグはCallSiteRequiredToBeUniform.Sで、potential-trigger-setは
derivative_uniformity要素となる。
-
-
もしそのようなDFがなければ、呼び出し元タグはCallSiteRequiredToBeUniform.errorで、potential-trigger-setは
derivative_uniformity要素となる。
-
-
それ以外はCallSiteNoRestrictionです。
-
-
§ 17.7.4 textureLoadの呼び出し:
-
関数タグは次の通りです:
-
引数
tがread-write storage textureに対応していればReturnValueMayBeNonUniform -
それ以外はNoRestriction
-
-
§ 17.12 サブグループ組み込み関数または § 17.13 クアッド演算内の関数呼び出し:
-
関数タグは次の通りです:
-
DFを、その呼び出しサイト位置とtriggering rule subgroup_uniformityに対する最近傍の診断フィルタとする。
-
呼び出し元タグは次の通りです:
-
subgroup_uniformityがサポートされていないか、uniformity scopeがsubgroupの場合:
-
もしDFが存在するなら、そのnew severityパラメータをSとする。
-
もしSがoffなら、呼び出し元タグはCallSiteNoRestrictionです。
-
それ以外はCallSiteRequiredToBeUniform.Sで、potential-trigger-setは
subgroup_uniformity要素となる。
-
-
そのようなDFがなければ、呼び出し元タグはCallSiteRequiredToBeUniform.errorで、potential-trigger-setは
subgroup_uniformity要素となる。
-
-
それ以外はCallSiteNoRestrictionです。
-
-
また、subgroupShuffleUpまたはsubgroupShuffleDown呼び出しの場合、パラメータ
deltaのparameter tagは次の通りです:-
subgroup_uniformityがサポートされていないか、uniformity scopeがsubgroupの場合:
-
もしDFが存在するなら、そのnew severityパラメータをSとする。
-
もしSがoffなら、parameter tagはNoRestriction。
-
それ以外はParameterRequiredToBeUniform.Sで、potential-trigger-setは
subgroup_uniformity要素となる。
-
-
そのようなDFがなければ、parameter tagはParameterRequiredToBeUniform.errorで、potential-trigger-setは
subgroup_uniformity要素となる。
-
-
それ以外はNoRestrictionです。
-
-
また、subgroupShuffleXor呼び出しの場合、パラメータ
maskのparameter tagは次の通りです:-
subgroup_uniformityがサポートされていないか、uniformity scopeがsubgroupの場合:
-
もしDFが存在するなら、そのnew severityパラメータをSとする。
-
もしSがoffなら、parameter tagはNoRestriction。
-
それ以外はParameterRequiredToBeUniform.Sで、potential-trigger-setは
subgroup_uniformity要素となる。
-
-
そのようなDFがなければ、parameter tagはParameterRequiredToBeUniform.errorで、potential-trigger-setは
subgroup_uniformity要素となる。
-
-
それ以外はNoRestrictionです。
-
-
注: WGSLの実装では、関数呼び出し前の制御フローが特定のスコープで一様である場合、関数呼び出し後も一様であることが保証されます。
15.2.8. 式の均一性規則
式を解析する規則は、式そのものと、その開始時点の 制御フローに対応するノード(以下では "CF" と記す)の両方を引数に取り、次のものを返す:
-
その値に対応するノード
-
グラフに追加する新しいノードおよびエッジの集合
| 式 | 新しいノード | 再帰的解析 | 結果の値ノード | 新しいエッジ |
|---|---|---|---|---|
| e1 || e2 | (CF, e1) => V1 (V1, e2) => V2 | V2 | ||
| e1 && e2 | ||||
| リテラル | CF | |||
| 関数スコープ変数 "x" に解決される 識別子であって、 その識別子がメモリビュー 式 MVE のルート識別子として現れ、かつ型検査中に load 規則が MVE に対して呼び出されるもの | Result | X は、この式を含む文への入力における "x" の値に対応するノードである | Result |
Result -> {CF, X}
注: X は
"x" に対する Vout(prev) と等価である |
| 関数スコープ変数 "x" に解決される 識別子であって、 "x" が脱糖されたポインター引数 i であり、かつ その識別子がメモリビュー 式 MVE のルート識別子として現れ、かつ型検査中に load 規則が MVE に対して呼び出されないもの | param_i | |||
| 関数スコープ変数 "x" に解決される 識別子であって、 その識別子がメモリビュー 式 MVE のルート識別子として現れ、かつ型検査中に load 規則が MVE に対して呼び出されないもの | CF | |||
| const 宣言、override 宣言、 let 宣言、または非ポインター型の 非組み込み仮引数 "x" に解決される識別子 | Result | X は "x" に対応するノードである | Result | Result -> {CF, X} |
| storage、workgroup、 またはprivate アドレス空間にあり、 非読み取り専用のアクセスモードを持つ ポインター型の 仮引数に 解決される識別子であって、 その識別子がメモリビュー 式 MVE のルート識別子 として現れ、かつ型検査中にload 規則が MVE に対して呼び出されるもの | MayBeNonUniform | |||
| storage、workgroup、 またはprivate アドレス空間にあり、 非読み取り専用のアクセスモードを持つ ポインター型の 仮引数に 解決される識別子であって、 その識別子がメモリビュー 式 MVE のルート識別子 として現れ、かつ型検査中にload 規則が MVE に対して呼び出されないもの | CF | |||
| function 以外の アドレス空間内にあり、 読み取り専用のアクセスモードを持つ ポインター型の 仮引数に 解決される識別子 | CF | |||
| 一様な組み込み値 "x" に解決される 識別子 | CF | |||
| 非一様な組み込み値 "x" に解決される 識別子 | MayBeNonUniform | |||
| 読み取り専用のモジュールスコープ変数 "x" に解決される 識別子 | CF | |||
| 非読み取り専用のモジュールスコープ 変数 "x" に解決される識別子であって、 その識別子がメモリビュー 式 MVE のルート識別子として現れ、かつ 型検査中に load 規則が MVE に対して呼び出されるもの | MayBeNonUniform | |||
| 非読み取り専用のモジュールスコープ 変数 "x" に解決される識別子であって、 その識別子がメモリビュー 式 MVE のルート識別子として現れ、かつ 型検査中に load 規則が MVE に対して呼び出されないもの | CF | |||
| ( e ) | (CF, e) => V | V | ||
| op e, ここで op は単項演算子 | ||||
| e.field | ||||
| e1 op e2, ここで op は短絡しない二項 演算子 | Result | (CF, e1) => V1 (CF, e2) => V2 | Result | Result -> {V1, V2} |
| e2[e1] | ||||
f()引数のない関数呼び出し式 | 関数呼び出し解析を呼び出す: (CF, f()) => Result | Result | ||
f(e1,...,eN)引数を伴う関数呼び出し式 | 関数呼び出し解析を呼び出す: (CF, f(e1,...,eN)) => Result | Result |
次の組み込み入力変数は一様とみなされる:
subgroup 一様性スコープでは、次の組み込み 入力変数も一様とみなされる:
その他すべて(組み込み 値を参照)は非一様とみなされる。
注: 作者は、一様な組み込み値を 他の非一様な入力とまとめることを避けるべきである。解析は 複合型のコンポーネントを 個別には解析しないためである。
| 式 | 新しいノード | 再帰的解析 | 結果の変数ノード | 新しいエッジ |
|---|---|---|---|---|
| 関数スコープ変数 "x" に解決される 識別子 | Result | X は、この式を含む文の出力における "x" の値に対応するノードである。 | Result |
Result -> {CF, X}
注: X は
"x" に対する Vin(next) と等価である |
| const 宣言、override 宣言、 let 宣言、または仮引数 "x" に 解決される識別子 | X は "x" に対応するノードである | X | ||
| モジュールスコープ変数 "x" に解決される 識別子 | MayBeNonUniform | |||
| e.field | LHSValue: (CF, e) => L1 | L1 | ||
| *e | ||||
| &e | ||||
| e2[e1] | (CF, e1) => V1 LHSValue: (CF, e2) => L2 | L2 | L2 -> V1 |
15.2.9. 全ての制御フローポイントの均一性を注釈する
この小節全体は規範的ではありません。
もし実装者が、シェーダー全体の制御フローの各ポイントについて、それが均一かどうか(つまり均一性を要求する関数をそこから呼び出しても有効かどうか)を開発者に診断モードとして表示したい場合は、以下を推奨します:
-
前節で記述された(必須かつ規範的な)分析を実施し、各関数についてグラフを保持する。
-
それら全てのグラフのエッジを反転する。
-
各関数について、エントリーポイントから始め、必ず呼び出し元を全て訪問してからその関数を訪問する:
-
少なくとも一つの呼び出し元で非均一であった引数には、MayBeNonUniformからエッジを追加する。
-
少なくとも一つの呼び出し元で非均一な制御フローで呼び出された場合は、MayBeNonUniformからCF_startへエッジを追加する。
-
MayBeNonUniformから到達可能なノードを調べる。訪問された各ノードは、均一性解析によって均一性が証明できなかった式や制御フローポイントである。
-
この到達可能性解析で訪問されなかったノードは、解析によって均一性が証明できる(つまり、そこで導関数等の関数呼び出しが安全である)ことになります。
注: コール時にどのエッジをグラフに追加すべきかを把握するため、ボトムアップ解析も依然として必要です。
15.2.10. 例
次の例で使用されるグラフは、ノードに対して以下の表記法を用います:
-
矩形は値ノードを表します。
-
角が丸い矩形は制御フローノードを表します。
15.2.10.1.
無効な textureSample 関数呼び出し
この例はtextureSample組込み関数呼び出しの無効な使用例を示します。
この関数呼び出しは、条件が非均一値(組込み値position)に依存するif文の中で行われています。
無効な依存チェーンは赤色で強調されています。
@group ( 0 ) @binding ( 0 ) var t : texture_2d< f32> ; @group ( 0 ) @binding ( 1 ) var s : sampler; @fragment fn main ( @builtin ( position) pos : vec4< f32> ) { if ( pos . x < 0.5 ) { // 無効な textureSample 関数呼び出し。 _ = textureSample ( t , s , pos . xy ); } }
この例はまた、if文の後の制御フローの均一性がif文の前と同じであることも示しています(CF_returnがCF_startに接続されている)。
つまり、エントリーポイントの開始時に制御フローが均一であることが保証されているため、if文の後も再び制御フローが均一になります。
textureSample関数呼び出しがif文の外に移動されていれば、このプログラムは有効だったでしょう。
また、if文の条件が均一値(例えば各呼び出しが同じ値をuniform bufferから読み取る等)であれば、このプログラムも有効です。
15.2.10.2. 関数スコープ変数の均一性
この例は、関数スコープ変数の値に依存するbarrier関数呼び出しの有効・無効両方のケースを示します。
workgroupBarrierは、xの値が可変なモジュールスコープ変数aから導出されるため無効です。
storageBarrierは、xの値が不変なモジュールスコープ変数bから導出されるため有効です。
この例は値分析が関数スコープ変数のライフタイム内の異なる均一性期間を分離できることを強調しています。
また、最初のif文の終了後、制御フローが再び均一になることも明示されています。
これは、グラフのその部分が2つ目のif文とは独立しているため分かります。
@group ( 0 ) @binding ( 0 ) var < storage, read_write> a : i32; @group ( 0 ) @binding ( 1 ) var < uniform> b : i32; @compute @workgroup_size ( 16 , 1 , 1 ) fn main () { var x : i32; x = a ; if x > 0 { // 無効な barrier 関数呼び出し。 workgroupBarrier (); } x = b ; if x < 0 { // 有効な barrier 関数呼び出し。 storageBarrier (); } }
注: サブグラフは理解しやすくするために例として含まれています。
15.2.10.3. 複合値分析の制限
均一性分析の制約の一つは、コンポーネントを合成値の個々で独立して追跡しないことです。 つまり、非均一なコンポーネント値がある場合、 分析は合成値全体を非均一として扱います。 この例はこの問題と、シェーダー作者がこの制約を回避するために利用できる潜在的な方法を示しています。
struct Inputs { // workgroup_idは均一な組込み値。 @builtin ( workgroup_id) wgid : vec3< u32> , // local_invocation_indexは非均一な組込み値。 @builtin ( local_invocation_index) lid : u32} @compute @workgroup_size ( 16 , 1 , 1 ) fn main ( inputs : Inputs ) { // この比較は常に均一ですが、分析では判定できません。 if inputs . wgid . x == 1 { workgroupBarrier (); } }
この分析の制限を回避する最も簡単な方法は、複合値を分割し、均一であることが分かっている値と非均一であることが分かっている値を別々にすることです。 下記の代替WGSLでは、2つの組込み値を別々のパラメータに分割することで均一性分析を通過できます。 これは、グラフ内にRequiredToBeUniform.SからMayBeNonUniformへの経路がないことから分かります。
@compute @workgroup_size ( 16 , 1 , 1 ) fn main ( @builtin ( workgroup_id) wgid : vec3< u32> , @builtin ( local_invocation_index) lid : u32) { // 均一性分析はこの比較が常に均一であることを正しく判定できます。 if wgid . x == 1 { // 有効な barrier 関数呼び出し。 workgroupBarrier (); } }
15.2.10.4. ループ内の均一性
この例では、ループ内で無効なworkgroupBarrier関数呼び出しが行われています。
非均一な組込み値local_invocation_indexが最終的な原因であり、これはbarrierの後に登場していますが、その事実に関わらず無効です。
これは、後のイテレーションでワークグループ内の一部の呼び出しがループを早期に抜ける一方、他の呼び出しがbarrierを実行しようとするために起こります。
解析では、ループ本体の開始時の制御(CF_loop_body)がループ本体終了時の制御(CF_after_if)に依存するエッジとして、イテレーション間の依存関係がモデル化されています。
@compute @workgroup_size ( 16 , 1 , 1 ) fn main ( @builtin ( local_invocation_index) lid : u32) { for ( var i = 0u ; i < 10 ; i ++ ) { workgroupBarrier (); if ( lid + i ) > 7 { break ; } } }
15.2.10.5. ユーザー定義関数呼び出し
この例は最初の例を修正したもので、ユーザー定義の関数呼び出しを使用します。
解析では、scaleの両方のパラメータにparameter return tagとして
ParameterReturnContentsRequiredToBeUniformが設定されます。
これにより、main内でscale関数呼び出しの戻り値とposition組込み値の間にパスができます。
このパスは、RequiredToBeUniform.SからMayBeNonUniformへの全体の無効なパスの部分パスです。
fn scale ( in1 : f32, in2 : f32) -> f32{ let v = in1 / in2 ; return v ; } @group ( 0 ) @binding ( 0 ) var t : texture_2d< f32> ; @group ( 0 ) @binding ( 1 ) var s : sampler; @fragment fn main ( @builtin ( position) pos : vec4< f32> ) { let tmp = scale ( pos . x , 0.5 ); if tmp > 1.0 { _ = textureSample ( t , s , pos . xy ); } }
注: サブグラフは理解しやすくするために例として含まれています。
15.3. コンピュートシェーダーとワークグループ
ワークグループは、 計算シェーダーステージのエントリーポイントを並行して実行し、 workgroup アドレス空間内のシェーダー変数へのアクセスを共有する呼び出しの集合である。
計算シェーダーのワークグループグリッドは、 次を満たす整数座標 (i,j,k) を持つ点の集合である:
-
0 ≤ i < workgroup_size_x
-
0 ≤ j < workgroup_size_y
-
0 ≤ k < workgroup_size_z
ここで (workgroup_size_x, workgroup_size_y, workgroup_size_z) は、 エントリーポイントの workgroup_size 属性に指定された値である。
ワークグループグリッド内の各点につき、ワークグループ内にはちょうど 1 つの呼び出しが存在する。
呼び出しのローカル 呼び出し IDは、その呼び出しに対応するワークグループグリッド点の 座標三つ組 (i,j,k) である。
呼び出しがローカル呼び出し IDを持つとき、その ローカル呼び出し インデックスは次のとおりである:
i + (j × workgroup_size_x) + (k × workgroup_size_x × workgroup_size_y)
ワークグループが W 個の呼び出しを持つ場合、 そのワークグループ内の各呼び出し I は一意なローカル呼び出しインデックス L(I) を持ち、0 ≤ L(I) < W を満たし、 その範囲全体が覆われることに注意。
計算シェーダーは、WebGPU 実装が キューからディスパッチコマンドを取り出し、GPU 上で指定された作業を開始すると実行を開始する。 ディスパッチコマンドはディスパッチサイズを指定する。 これは、以下で説明されるように、実行されるワークグループ数を示す 整数三つ組 (group_count_x, group_count_y, group_count_z) である。
特定のディスパッチに対する計算シェーダー グリッドは、 次を満たす整数座標 (CSi,CSj,CSk) を持つ点の集合である:
-
0 ≤ CSi < workgroup_size_x × group_count_x
-
0 ≤ CSj < workgroup_size_y × group_count_y
-
0 ≤ CSk < workgroup_size_z × group_count_z
ここで workgroup_size_x、 workgroup_size_y、および workgroup_size_z は、計算シェーダーエントリーポイントについて上記のとおりである。
計算シェーダーディスパッチによって実行される作業は、計算シェーダーグリッド内の各点につき、 エントリーポイントの呼び出しをちょうど 1 つ実行することである。
呼び出しのグローバル 呼び出し IDは、その呼び出しに対応する計算シェーダーグリッド点の 座標三つ組である。
呼び出しはワークグループに編成される。そのため、各呼び出しの グローバル呼び出し ID (CSi, CSj, CSk) は、 ワークグループ IDによって識別される単一のワークグループに対応する:
( ⌊ CSi ÷ workgroup_size_x ⌋, ⌊ CSj ÷ workgroup_size_y ⌋, ⌊ CSk ÷ workgroup_size_z ⌋)
また、そのワークグループ内の単一の呼び出しに対応し、それはローカル呼び出し IDによって識別される:
( CSi mod workgroup_size_x , CSj mod workgroup_size_y , CSk mod workgroup_size_z ).
注記: ワークグループ ID は (0,0,0) から (group_count_x - 1, group_count_y - 1, group_count_z - 1) までにわたる。
linear_indexing 機能がサポートされる場合、 ワークグループがワークグループ ID (WGi, WGj, WGk) を持つとき、その ワークグループインデックスは次のとおりである:
WGi + ( WGj × group_count_x ) + ( WGk × group_count_x × group_count_y )
linear_indexing 機能がサポートされる場合、 呼び出しがグローバル呼び出し ID (CSi, CSj, CSk) を持つとき、その グローバル呼び出し インデックスは次のとおりである:
CSi + ( CSj × workgroup_size_x × group_count_x ) + ( CSk × workgroup_size_x × group_count_x × workgroup_size_y × group_count_y )
WebGPU は次について保証しない:
-
異なるワークグループからの呼び出しが並行して実行されるかどうか。 すなわち、一度に複数のワークグループが実行されると仮定することはできない。
-
あるワークグループからの呼び出しが実行を開始した後、他のワークグループが 実行からブロックされるかどうか。 すなわち、一度に 1 つのワークグループだけが実行されると仮定することはできない。 ワークグループの実行中、実装は 他のワークグループ、またはキューに入っているがブロックされていない他の作業を並行して実行することも選択できる。
-
ある特定のワークグループからの呼び出しが、 別のワークグループの呼び出しより前に実行を開始するかどうか。 すなわち、ワークグループが特定の順序で起動されると仮定することはできない。
15.4. フラグメントシェーダーとヘルパー呼び出し
フラグメントシェーダーステージの呼び出しは、XおよびY次元で隣接する位置を持つ2x2グリッドに分割されます。 これらのグリッドはクアッドと呼ばれます。 クアッドは一部の集団演算で協調することができます(§ 15.6.2 微分参照)。 呼び出しのクアッド呼び出しIDは、クアッド内で一意のIDであり、以下のとおりです:
-
ID 0は左上の呼び出し。
-
ID 1は右上の呼び出し。
-
ID 2は左下の呼び出し。
-
ID 3は右下の呼び出し。
注: クアッドID用の組込み値アクセサは存在しません。
通常、フラグメント処理 は、ラスタライゼーションによって生成された各 RasterizationPoint ごとにフラグメントシェーダの呼び出しを1つ生成します。quad を完全に埋めるのに十分な RasterizationPoints がないことがあり、例えばグラフィックスプリミティブの端などがその例です。quad に対応する RasterizationPoints に対応する呼び出しが1つ、2つ、または3つしかない場合、fragment processing will は quad の未埋めの各位置ごとに helper invocation を作成します。
ヘルパーインボケーションは観測可能な効果が限定されています。 微分 の計算を補助したり、 サブグループ操作 に参加する場合があります。 このため、ヘルパーインボケーションには以下の制約が課されます:
-
書き込みアクセスは行われ§ 14.5.1 メモリ操作も参照) ない。これはstorage または handle アドレス空間に対してである。
-
アトミック組み込み関数は必ず 不定の結果を返す。
-
エントリーポイントの戻り値は、 それ以上処理されない。 これは GPURenderPipeline 内の下流においてである。
クアッド内のすべての呼び出しがヘルパー呼び出しとなった場合(例:discard文の実行による)、 クアッドの実行は終了されることがありますが、そのような終了は非均一な制御フローを生成するものとはみなされません。
15.5. サブグループ
サブグループとは、 コンピュートまたはフラグメントシェーダーステージのエントリーポイントを並行して実行する インボケーションの集合であり、データを効率的に共有し、集合的に結果を計算できるものである。 コンピュートシェーダーまたはフラグメントシェーダー内の各インボケーションは、ちょうど 1 つのサブグループに属する。 コンピュートシェーダーでは、各サブグループは特定のワークグループの部分集合である。 フラグメントシェーダーでは、サブグループは複数の描画コマンドからのインボケーションを含む場合がある。 各クアッドは単一の サブグループに含まれる。
サブグループサイズとは、 サブグループ内のインボケーションの最大数である。 シェーダー内では、この値は subgroup_size ビルトイン値を介してアクセスできる。 サブグループサイズは、ディスパッチコマンド内、ひいてはワークグループ内では ユニフォーム値であるが、 描画コマンド内ではユニフォーム値でない場合がある。 すべてのサブグループサイズは [4, 128] の範囲内の 2 のべき乗であり、特定のデバイス向けに コンパイルされたシェーダーの値は、 WebGPU § 4.3 GPUAdapter について [subgroupMinSize, subgroupMaxSize] の範囲内となる。 実際のサイズは、シェーダー、デバイスのプロパティ、およびデバイスコンパイラに依存する。 各デバイスは、可能なサブグループサイズの範囲の部分集合(単一の値である場合もある)をサポートする。 デバイスコンパイラは、さまざまなヒューリスティックを用いてサポートされるサイズの中からサイズを選択する。 各サブグループは、報告されたサブグループサイズより少ないインボケーションを含む場合がある (例えば、サブグループサイズより少ないインボケーションが起動された場合など)。
呼び出しごとのサブグループ呼び出しIDは、同じサブグループ内で一意のIDです。
このIDは、subgroup_invocation_id
の組み込み値で取得でき、範囲は [0, subgroup_size - 1] です。
subgroup_id 機能がサポートされている場合、計算シェーダー内での サブグループID は、 ワークグループ内でサブグループの一意のIDとなります。 このIDは subgroup_id の組み込み値で取得でき、 範囲は [0, num_subgroups - 1] です。
サブグループの値(すなわち subgroup_invocation_id および subgroup_id)と
local_invocation_index との間には、
定義された関係はありません。
移植性のないコードを避けるため、シェーダー記述者はこれらの値の間に特定の対応関係があると仮定すべきではありません。
同じサブグループ内の呼び出しが異なる制御フローパスを実行するとき、サブグループ実行が分岐した(diverge)と言います。 これは非均一な制御フローの特別なケースです。 分岐はサブグループ操作の意味に影響します。 サブグループ操作を同時に実行するサブグループ内の呼び出しは、その操作に対してアクティブです。 サブグループ内のその他の呼び出しは、その操作に対して非アクティブです。 サブグループサイズがサブグループ内の呼び出し数を超える場合、余分な仮想呼び出しは非アクティブとみなされます。 ヘルパー呼び出しは操作に対してアクティブにも非アクティブにもなり得ます。 つまり、デバイスによってはヘルパー呼び出しがサブグループ操作に参加する場合もあれば、しない場合もあります。
注: 非均一な制御フローで動作する場合、基盤デバイス間で非移植性が大きく、デバイスコンパイラはこのようなコードを積極的に最適化することが多いです。 その結果、サブグループにはシェーダー作者が想定したものと異なるアクティブ呼び出し集合が含まれる場合があります。
15.6. 集団演算
15.6.1. バリア
バリアとは、プログラム内のメモリ操作を順序付ける同期ビルトイン関数である。 制御バリアは、 同じワークグループ内のすべてのインボケーションによって、 あたかも並行して実行されるかのように実行される。 そのため、制御バリアはコンピュートシェーダーにおいて、 ユニフォーム制御フロー内でのみ 実行されなければならない。
15.6.2. 微分
偏微分は、ある軸方向の値の変化率です。 同じクアッド内のフラグメントシェーダー呼び出しが協調して近似的な偏微分を計算します。
微分を計算する組込み関数は以下です:
フラグメント座標の偏微分は、以下の組込み関数の動作の一部として暗黙的に計算されます:
これらの場合、微分結果はサンプリングされるテクセルのミップレベルを決定したり、textureSampleCompareの場合はサンプリング値を参照値と比較する際に使われます。
呼び出し指定値の偏微分は、§ 17.6 微分組込み関数で説明される組込み関数によって計算されます:
-
dpdx、dpdxCoarse、dpdxFineはx軸方向の偏微分を計算します。
-
dpdy、dpdyCoarse、dpdyFineはy軸方向の偏微分を計算します。
-
fwidth、fwidthCoarse、fwidthFineは、関連するxおよびyの偏微分を使ってマンハッタン距離を計算します。
隣接する呼び出しが協調して微分を計算するため、これらの関数はフラグメントシェーダー内で均一な制御フローでのみ呼び出すべきです。 これらの関数を呼び出すたびに、derivative_uniformityの診断が、均一性解析で呼び出しが均一な制御フローであることが証明できない場合に発生します。
これらの関数が非均一な制御フローで呼び出された場合、結果は不定値となります。
注: 微分は暗黙のクアッド演算の一種です。 利用にはsubgroups拡張は不要です。
15.6.3. サブグループ演算
サブグループ組込み関数により、サブグループ内の呼び出し間で効率的な通信と計算が可能となります。 サブグループ演算はSIMT(single-instruction multiple-thread)演算です。
アクティブな呼び出しがサブグループ内で通信し、結果を決定します。 そのため、これらの関数は全呼び出しがアクティブなとき(すなわちサブグループレベルの均一な制御フローで)呼び出すと可搬性が最大化されます。
15.6.4. クアッド演算
クアッド組込み関数は、クアッド呼び出しに対して作用します。 これらはクアッド間のデータ通信に有用です。
アクティブな呼び出しがクアッド内で通信し、結果を決定します。 そのため、これらの関数は全呼び出しがアクティブなとき(すなわちクアッドレベルの均一な制御フローで)呼び出すと可搬性が最大化されます。
15.7. 浮動小数点数の評価
WGSL の浮動小数点機能は IEEE-754 標準を基にしていますが、GPU における妥協点を反映して機能が削減されており、移植性を高める追加のガードレールも設けられています。
15.7.1. IEEE-754 の概要
WGSL の浮動小数点型は IEEE-754 のバイナリ浮動小数点型に基づいています。
IEEE-754 バイナリ浮動小数点型は、拡張実数の数直線を次のように近似します:
-
この型は有限個の値の集合を持ち、次の異なるカテゴリが含まれます:
-
この型は次のような演算をサポートします:
-
この型のビット表現は次の特徴を持ちます:
-
固定ビット幅を持ち、各値のビット表現は、最上位ビットから最下位ビットに向かって連続する3つのビットフィールドで構成されます:
-
1ビットの 符号フィールド。
-
固定幅の 指数フィールド。
-
固定幅の 仮数部フィールド。
-
-
指数フィールド の解釈に関係する整数値の 指数バイアス。
-
有限範囲 とは、浮動小数点型の 区間 [low, high] であり、low がその型で最も小さい有限値、high が最も大きい有限値です。
注目すべき IEEE-754 の浮動小数点型は次の通りです:
-
binary16:
-
binary32:
-
binary64:
次のアルゴリズムは、浮動小数点値のビット表現を対応する 拡張実数値または NaN に対応付けます:
アルゴリズム: ビットの浮動小数点解釈入力: Bits は、バイナリ浮動小数点型の値のビット表現。
出力: F は Bits で表される浮動小数点値。
手順:
bias をその型の 指数バイアス とする。
tsw をその型の 仮数部フィールド のビット幅とする。
それぞれのフィールドの解釈値を Sign、E、T とする(いずれも符号なし整数)。
指数フィールド が全て1の場合:
Sign = 0 かつ T = 0 のとき、結果 F = +∞。
Sign = 1 かつ T = 0 のとき、結果 F = −∞。
T ≠ 0 のとき、結果 F は NaN。
それ以外で 指数フィールド が全て0の場合:
結果 F = (−1)Sign × 2−bias × T × 2−tsw+1。
T = 0 の場合、その値はゼロ。
各浮動小数点型には正のゼロと負のゼロが存在します。 負のゼロは、符号ビットが
1であるゼロ値です。 負のゼロと正のゼロは等値比較で等しいとみなされます。 IEEE-754 では負のゼロは WGSL では重要でない境界ケースを示すために使用されます。T ≠ 0 の場合、値 F は 非正規化 となります。 (デノーマライズ は非正規化の同義語です。)
それ以外の場合、指数フィールド が全て1でも全て0でもない場合:
結果 F = (−1)Sign × 2(E−bias) × ( 1 + T × 2−tsw )。
値 F は 正規化 です。
浮動小数点演算の 定義域 とは、演算がよく定義される 拡張実数 の入力集合です。
-
例えば、数学関数 √ の定義域は区間 [0, +∞] です:√は 0 未満の入力には定義されません。
-
定義域内で評価される場合、演算は無限精度の 拡張実数 中間結果に基づいて定義され、それが 丸めによって浮動小数点値に変換されます。
-
定義域外で評価される場合、 IEEE-754 の既定の例外処理規則により、実装は 例外 を発生させ、NaN を返すことが要求されます。 対照的に、WGSL では浮動小数点例外を義務付けておらず、代わりに 不定値 を返してもよいです。詳しくは § 15.7.2 IEEE-754 との相違点 を参照してください。
丸めは、拡張実数値 x を浮動小数点型の値 x' に対応付けます。 x が浮動小数点型の値である場合、丸めは x をそのまま x' に写します:x = x'。 x が型の 有限範囲 の外側にある場合、丸めはオーバーフローを引き起こします。 それ以外の場合、x' は x より大きい最も小さい浮動小数点値、あるいは x より小さい最大の浮動小数点値となります; どちらが選ばれるかは 丸めモード によって決まります。
一般に、NaN の入力を持つ演算は NaN を返します。 例外として:
-
NaN は他の浮動小数点値と等しい、未満、大きいのいずれにもなりません。これらの比較は偽となります。
IEEE-754 では5種類の 例外が定義されています:
-
不正な演算。 これは、拡張実数の定義域外の入力に対して演算が評価された場合に発生します。 このような演算は NaN を返します。 例:0 × +∞、
sqrt(−1)。 -
ゼロ除算。 これは、有限なオペランドに対して演算が厳密に無限大の結果となる場合に発生します。 例:1 ÷ 0、log(0)。
-
オーバーフロー。これは、中間結果が型の有限範囲を超えた場合に発生します。詳細は § 15.7.3 浮動小数点の丸めとオーバーフロー を参照してください。
-
不正確。これは、丸め後の結果が 中間結果 と異なる場合、 またはオーバーフローが発生した場合に発生します。
15.7.2. IEEE-754 との相違点
WGSL は IEEE-754 標準に準拠していますが、以下の点で異なります:
-
浮動小数点値 x を整数型に変換する際、 x はまず対象型の値域にクランプされる。 § 15.7.6 浮動小数点変換を参照のこと。
-
浮動小数点例外は生成されない。
-
シグナリング NaN は生成されない場合がある。 中間計算において、任意のシグナリング NaN はクワイエット NaN に変換される場合がある。
-
有限算術前提:
-
シェーダー実行前に生成されたオーバーフロー、 無限大、および NaN は、エラーを生成する。
-
有限値に対するconst式および override式は、 IEEE-754 の規則に従って、オーバーフロー、無限大、および NaN を 中間結果値として 生成する。
-
注: この規則は、 エラーを一貫して生成できるように、これらの種類の式について、 精度の限界内でオーバーフロー、無限大、および NaN を確実に検出することを 実装に要求する。
-
-
浮動小数点型のconst式がオーバーフローするか、 NaN または無限大に評価される場合、シェーダー作成エラーが発生する。
-
浮動小数点型のoverride式がオーバーフローするか、 NaN または無限大に評価される場合、パイプライン作成エラーが発生する。
-
-
実装は、 シェーダー実行中にオーバーフロー、無限大、および NaN が 存在しないと仮定してもよい。
-
-
実装は、浮動小数点ゼロ値の符号フィールドを無視してもよい。 すなわち、正の符号を持つゼロが負の符号を持つゼロのように振る舞ったり、その逆が起こったりする場合がある。
-
ゼロフラッシュとは、浮動小数点型の非正規化値を その型のゼロ値で置き換えることである。
-
§ 15.7.4 浮動小数点精度に列挙されている演算の 任意の入力または出力は、ゼロにフラッシュされる場合がある。
-
さらに、§ 17.2 ビット再解釈ビルトイン関数、§ 17.9 データパッキングビルトイン関数、または § 17.10 データアンパッキングビルトイン関数に列挙されている演算の 中間結果値は、 ゼロにフラッシュされる場合がある。
-
その他の演算は、非正規化数を保持することが要求される。
-
-
演算の精度は§ 15.7.4 浮動小数点精度に示される。
-
WGSL の一部のビルトイン関数は、対応する IEEE-754 演算とは異なるセマンティクスを持つ。 そのような場合は、WGSL ビルトイン関数の定義において必要に応じて列挙される。
例えば、WGSL の § 17.5.32 fma 関数は、通常の 乗算(丸めステップを含む)と加算(およびもう 1 つの丸めステップ)に展開される場合があるが、 IEEE-754 の
fusedMultiplyAdd演算は、最終的な丸めステップのみが 発生することを要求する。
15.7.3. 浮動小数点の丸めとオーバーフロー
オーバーフローする計算は、無限大または最も近い有限値へ丸められることがあります。 結果は、オーバーフローした中間結果値の大きさと、評価がシェーダーモジュール生成、パイプライン生成、またはシェーダー実行中かによって異なります。
浮動小数点型 T に対し、MAX(T) を T の最大正有限値、 2EMAX(T) を T で表現可能な最大の 2 のべき乗値と定義します。 特に EMAX(f32) = 127, EMAX(f16) = 15 です。
X を浮動小数点計算から得られる無限精度の中間結果とします。 式の最終値は、中間結果値 X' および X'' を介して、次のように2段階で決定されます:
X から T で丸めて X' を計算します:
-
X が 有限範囲内なら、X' は X を切り上げまたは切り下げした結果です。
-
X が NaN の場合、X' も NaN です。
-
MAX(T) < X < 2EMAX(T)+1 の場合、どちらの丸め方向も可能です:X' は MAX(T) または +∞ です。
-
2EMAX(T)+1 ≤ X の場合、X' = +∞ です。
-
注: この条件は IEEE-754 の規則に一致します。
-
-
−MAX(T) > X > −2EMAX(T)+1 の場合、どちらの丸め方向も可能です:X' は −MAX(T) または −∞ です。
-
−2EMAX(T)+1 ≥ X の場合、X' = −∞ です。
-
注: この条件は IEEE-754 の規則に一致します。
-
X' から式の最終値 X'' を計算するか、プログラムエラーを検出します:
-
X' が無限大または NaN である場合、有限算術前提により:
-
式がconst式である場合、 シェーダー作成エラーを生成する。
-
式がoverride式である場合、 パイプライン作成エラーを生成する。
-
-
それ以外の場合、X'' = X' である。
15.7.4. 浮動小数点精度
-
x が T に含まれる場合は x、
-
それ以外の場合:
-
x より大きい T の最小値、または
-
x より小さい T の最大値。
-
つまり、結果は丸めによって切り上げまたは切り下げされます: WGSL では丸めモードは指定されません。
注: 浮動小数点型には正および負の無限大が含まれるため、 正しく丸められた結果は有限値または無限大になる場合があります。
注: 無限精度で計算された演算結果は、ダブルの精度を超える精度が必要となる場合があります。
その一例として x - y で x=1.0 、y=1.17e-38(最小の正の正規化単精度浮動小数点数)の場合です。
これらの数値は指数が 126 離れています。IEEE-754 の binary64(倍精度)形式は仮数部が52ビットしかないため、
この減算では y の有効桁がすべて失われます。
丸めモードによっては、y が小さいが 0 でない場合、WGSL の式 x - y は x と同じ値になることがあります。
[ECMASCRIPT] では IEEE-754 の
roundTiesToEven 丸めモードに相当するものが使われています。
浮動小数点数 x の最小単位 ULP
は以下のように定義されます [Muller2005]:
-
xが浮動小数点型の有限範囲内にある場合、ULP(x) はa≤x≤bとなる二つの異なる有限浮動小数点数a,bの最小距離ulp(x) = mina,b|b - a|です。 -
それ以外の場合、ULP(x) は
bおよびa(最大および二番目に大きい表現可能な有限浮動小数点値)の差|b - a|です。
演算の精度は次の5通りのいずれかで示されます:
-
(非浮動小数点結果値に対して)正確な結果。
-
正しく丸められる。
-
絶対誤差の上限。
-
ULP で表現される相対誤差の上限。
-
精度が 継承されることを示す式。 すなわち、演算の精度は与えられた WGSL 式の評価精度として定義されます。 与えられた式は、その関数の正しい実装のひとつです。
継承元の式を評価する際、部分式の評価には浮動小数点評価の他の規則( 丸め、 オーバーフロー、 再結合、 融合、 ゼロへのフラッシュなど)も適用されます。
WebGPU の実装は演算を異なる方法で実装し、より高い精度や極端な入力への許容度を持つことがあります。
演算の精度が入力範囲について指定されている場合、 その範囲外の入力値に対する精度は未定義です。
許容される結果が結果型の有限範囲外の場合、§ 15.7.3 浮動小数点の丸めとオーバーフローの規則が適用されます。
15.7.4.1. 具体的な浮動小数点式の精度
| 式 | f32 の精度 | f16 の精度 |
|---|---|---|
x + y
| 正しく丸め | |
x - y
| 正しく丸め | |
x * y
| 正しく丸め | |
x / y
| 2.5 ULP(|y| が [2-126, 2126] の範囲)
| 2.5 ULP(|y| が [2-14, 214] の範囲)
|
x % y
| x - y * trunc(x/y) から継承
| |
-x
| 正しく丸め | |
x == y
| 正確な結果 | |
x != y
| 正確な結果 | |
x < y
| 正確な結果 | |
x <= y
| 正確な結果 | |
x > y
| 正確な結果 | |
x >= y
| 正確な結果 | |
| 組み込み関数 | f32 の精度 | f16 の精度 |
|---|---|---|
abs(x)
| 正しく丸め | |
acos(x)
|
より悪い方:
|
より悪い方:
|
acosh(x)
| log(x + sqrt(x * x - 1.0)) から継承
| |
asin(x)
|
より悪い方:
|
より悪い方:
|
asinh(x)
| log(x + sqrt(x * x + 1.0)) から継承
| |
atan(x)
| 4096 ULP | 5 ULP |
atan2(y, x)
| |x| が [2-126, 2126] の範囲で、y が有限で正規化の場合 4096 ULP
| |x| が [2-14, 214] の範囲で、y が有限で正規化の場合 5 ULP
|
atanh(x)
|
log( (1.0 + x) / (1.0 - x) ) * 0.5 から継承
| |
ceil(x)
| 正しく丸め | |
clamp(x,low,high)
|
正しく丸め。
無限精度の結果は
| |
cos(x)
| x が区間 [-π, π] の場合、絶対誤差最大 2-11
| x が区間 [-π, π] の場合、絶対誤差最大 2-7
|
cosh(x)
| (exp(x) + exp(-x)) * 0.5 から継承
| |
cross(x, x)
| (x[i] * y[j] - x[j] * y[i])(i ≠
j)から継承
| |
degrees(x)
| x * 57.295779513082322865 から継承
| |
determinant(m:mat2x2<T>)determinant(m:mat3x3<T>)determinant(m:mat4x4<T>)
|
無限 ULP。
注:WebGPU の実装は実用的な行列式関数を提供すべきです。
理想的な数学では、行列式は加算、減算、乗算で計算されます。 しかし、GPU は浮動小数点演算を用い、GPU 実装の行列式はオーバーフローや誤差への堅牢性よりも速度と単純さを重視します。 例えば、2x2 行列式の素朴な計算
( WGSL の行列式に有限な誤差境界がないのは、基盤となる実装にも同じ制約があるためです。 | |
distance(x, y)
| length(x - y) から継承
| |
dot(x, y)
| x[i] * y[i] の合計から継承
| |
dpdx(x)dpdxCoarse(x)dpdxFine(x)dpdy(x)dpdyCoarse(x)dpdyFine(x)fwidth(x)fwidthCoarse(x)fwidthFine(x) |
無限 ULP。
注:WebGPU の実装は実用的な微分関数を提供すべきです。
微分は、GPU 上の異なる呼び出し間の値の差( WGSL の微分に有限な誤差境界がないのは、基盤となる実装にも同じ制約があるためです。 | |
exp(x)
| 3 + 2 * |x| ULP
| 1 + 2 * |x| ULP
|
exp2(x)
| 3 + 2 * |x| ULP
| 1 + 2 * |x| ULP
|
faceForward(x, y, z)
| select(-x, x, dot(z, y) < 0.0) から継承
| |
floor(x)
| 正しく丸め | |
fma(x, y, z)
| x * y + z から継承
| |
fract(x)
| x - floor(x) から継承
| |
frexp(x)
| x がゼロまたは正規化時、正しく丸め
| |
inverseSqrt(x)
| 2 ULP | |
ldexp(x, y)
| 正しく丸め | |
length(x)
| ベクトルの場合 sqrt(dot(x, x))、スカラーの場合
sqrt(x*x) から継承
| |
log(x)
| x が区間 [0.5, 2.0] の場合、絶対誤差最大 2-21x が区間 [0.5, 2.0] の外の場合 3 ULP | x が区間 [0.5, 2.0] の場合、絶対誤差最大 2-7x が区間 [0.5, 2.0] の外の場合 3 ULP |
log2(x)
| x が区間 [0.5, 2.0] の場合、絶対誤差最大 2-21x が区間 [0.5, 2.0] の外の場合 3 ULP | x が区間 [0.5, 2.0] の場合、絶対誤差最大 2-7x が区間 [0.5, 2.0] の外の場合 3 ULP |
max(x, y)
|
正しく丸め
| |
min(x, y)
|
正しく丸め
| |
mix(x, y, z)
| x * (1.0 - z) + y * z から継承
| |
modf(x)
| 正しく丸め | |
normalize(x)
| x / length(x) から継承
| |
pack4x8snorm(x)
| 正しく丸められた中間結果値。正確な結果。 | |
pack4x8unorm(x)
| 正しく丸められた中間結果値。正確な結果。 | |
pack2x16snorm(x)
| 正しく丸められた中間結果値。正確な結果。 | |
pack2x16unorm(x)
| 正しく丸められた中間結果値。正確な結果。 | |
pack2x16float(x)
| 正しく丸められた中間結果値。正確な結果。 | |
pow(x, y)
| exp2(y * log2(x)) から継承
| |
quantizeToF16(x)
| 正しく丸め | |
radians(x)
| x * 0.017453292519943295474 から継承
| |
reflect(x, y)
| x - 2.0 * dot(x, y) * y から継承
| |
refract(x, y, z)
| z * x - (z * dot(y, x) + sqrt(k)) * y
から継承、ここで k = 1.0 - z * z * (1.0 - dot(y, x) * dot(y, x))k < 0.0
の場合、結果は厳密に 0.0
| |
round(x)
| 正しく丸め | |
sign(x)
| 正しく丸め | |
sin(x)
| x が区間 [-π, π] の場合、絶対誤差最大 2-11
| x が区間 [-π, π] の場合、絶対誤差最大 2-7
|
sinh(x)
| (exp(x) - exp(-x)) * 0.5 から継承
| |
saturate(x)
| 正しく丸め | |
smoothstep(edge0, edge1, x)
| t * t * (3.0 - 2.0 * t) から継承、ここで t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0)
| |
sqrt(x)
| 1.0 / inverseSqrt(x) から継承
| |
step(edge, x)
| 正しく丸め | |
tan(x)
| sin(x) / cos(x) から継承
| |
tanh(x)
|
より悪い方:
| |
transpose(x)
| 正しく丸め | |
trunc(x)
| 正しく丸め | |
unpack4x8snorm(x)
| 3 ULP | N/A |
unpack4x8unorm(x)
| 3 ULP | N/A |
unpack2x16snorm(x)
| 3 ULP | N/A |
unpack2x16unorm(x)
| 3 ULP | N/A |
unpack2x16float(x)
| 正しく丸め | N/A |
subgroupBroadcast(x, i)
| 正しく丸め | |
subgroupBroadcastFirst(x)
| 正しく丸め | |
subgroupAdd(x)
| アクティブなサブグループ呼び出し全ての x の合計から継承 | |
subgroupExclusiveAdd(x)
| アクティブなサブグループ呼び出しのうち、サブグループ呼び出し ID が現在の ID 未満のものの x の合計から継承 | |
subgroupInclusiveAdd(x)
| アクティブなサブグループ呼び出しのうち、サブグループ呼び出し ID が現在の ID 以下のものの x の合計から継承 | |
subgroupMul(x)
| アクティブなサブグループ呼び出し全ての x の積から継承 | |
subgroupExclusiveMul(x)
| アクティブなサブグループ呼び出しのうち、サブグループ呼び出し ID が i 番目呼び出しの ID 未満の xi の積から継承 | |
subgroupInclusiveMul(x)
| アクティブなサブグループ呼び出しのうち、サブグループ呼び出し ID が i 番目呼び出しの ID 以下の xi の積から継承 | |
subgroupMax(x)
| アクティブなサブグループ呼び出し全ての max(x) から継承 | |
subgroupMin(x)
| アクティブなサブグループ呼び出し全ての min(x) から継承 | |
subgroupShuffle(x, id)
| 正しく丸め | |
subgroupShuffleDown(x, delta)
| 正しく丸め | |
subgroupShuffleUp(x, delta)
| 正しく丸め | |
subgroupShuffleXor(x, mask)
| 正しく丸め | |
quadBroadcast(x, id)
| 正しく丸め | |
quadSwapDiagonal(x)
| 正しく丸め | |
quadSwapX(x)
| 正しく丸め | |
quadSwapY(x)
| 正しく丸め | |
15.7.4.2. AbstractFloat 式の精度
AbstractFloat演算の精度は以下の通りです:
-
対応するf32演算で正確な結果が要求される場合、正確な結果が必要です。
-
fract(x)の誤差はx - floor(x)から継承され、中間計算は AbstractFloat 演算として行われます。 -
それ以外の場合、対応するf32演算の誤差は絶対誤差、相対誤差、実装由来の誤差、またはそれらの組み合わせです。 この場合、AbstractFloatの誤差は無制限です。
-
ただし、AbstractFloat演算の誤差は、絶対値で対応するf32演算の誤差を超えないべきです。
-
この推奨は、型を f32 から AbstractFloat に変更したときに精度が低下しないようにするためのものです。
-
演算は WebAssembly [WASM-CORE-2] や ECMAScript [ECMASCRIPT] 環境で評価されることがあり、それらの仕様では多くの数値計算に誤差境界が定められていません。 例えば ECMAScript では多くの浮動小数点演算が 実装依存近似とされています。 実装は理想に近づくよう努力が推奨されていますが、厳密な要件はありません。
-
ULP は AbstractFloat値の場合、 AbstractFloat が IEEE-754 の binary64型と同一であると仮定します。
f32値における1ULPは、IEEE-754 binary64値の1ULPの229倍の大きさです。 これは binary64 の仮数部が f32 より 29ビット長いからです。
例えば、演算の真の結果値が x だが、計算結果が x' となった場合、 その誤差 x-x' が f32 で 3ULP なら、同じ絶対誤差 x-x' は AbstractFloat では 3·229 ULP となります。
15.7.5. 再結合と融合
再結合とは、式中の演算の順序を変更し、厳密に計算した場合に同じ答えが得られるようにすることです。例:
-
(a + b) + cはa + (b + c)に再結合されます -
(a - b) + cは(a + c) - bに再結合されます -
(a * b) / cは(a / c) * bに再結合されます
しかし、浮動小数点で計算すると結果が異なる場合があります。 再結合された結果は近似による不正確さや、中間結果の計算でオーバーフローや NaN を引き起こす可能性があります。
実装は演算を再結合しても構いません。
実装は、変換後の式が元の形式と同等以上に精度が高ければ、演算を融合しても構いません。 例えば、融合乗算加算(fused multiply-add)実装は、乗算と加算を個別に行うより高精度な場合があります。
15.7.6. 浮動小数点変換
この節では、浮動小数点型がソースまたは変換先となるスカラー変換の詳細を説明します。
この節でいう浮動小数点型は、次のいずれかです:
-
WGSL の f32、f16、AbstractFloat 型。
-
IEEE-754 浮動小数点標準で定義されたバイナリ形式に対応する仮想型。
注: f32 WGSL 型は IEEE-754 の binary32 形式、f16 WGSL 型は IEEE-754 の binary16 形式に対応します。
スカラー浮動小数点から整数型への変換アルゴリズム:
浮動小数点スカラー値 X を整数スカラー型 T に変換するには:
注: NaN 以外の場合、浮動小数点から整数への変換は 変換先型の範囲内に値をクランプし、ゼロ方向に丸めます。 このクランプ要件は WGSL が意味のある結果を保証する箇所であり、C や C++ では未定義動作となり、 IEEE-754 では不正な演算例外と NaN が要求される場面です。
-
3.9f を u32 に変換すると 3u となる
-
-1f を u32 に変換すると 0u となる
-
1e20f を u32 に変換すると、u32 で表現可能な 最大の浮動小数点値である 4294967040u となる
-
これは u32 の最大値 4294967295u より小さいことに注意
-
-3.9f を i32 に変換すると -3i となる
-
1e20f を i32 に変換すると、i32 の 最大値である 2147483520i となる
-
これは i32 の最大値 2147483647i より小さいことに注意
-
-1e20f を i32 に変換すると、i32 の 最小値である i32(-2147483648) となる
数値スカラーから浮動小数点への変換アルゴリズム:
アルゴリズム: 数値スカラー変換から浮動小数点へ入力:
X:型 S の数値スカラー値
T:変換先の浮動小数点型
出力: XOut:X を型 T に変換した結果、またはエラー
手順:
X が元の型 S の NaN なら、XOut は型 T の NaN。
X が変換先型 T に正確に表現できる場合、XOut は X と等しい T の値。
それ以外の場合、X は T で正確に表現できない:
X が T の隣接する有限値の間にある場合、XOut はそのいずれか。 WGSL は高い方か低い方か指定せず、変換ごとに異なる場合もある。
それ以外で、X が変換先型 T の有限範囲外の場合:
X の式がconst式である場合、シェーダー作成エラーが発生する。
X の式がoverride式である場合、パイプライン作成エラーが発生する。
それ以外の場合、変換は次のように進行する:
X' を元の値 X に設定する。
ソース型 S が、宛先型 T よりも多くの仮数ビットを持つ 浮動小数点型である場合、ソース値 X の余分な仮数ビットは 破棄される場合がある(すなわち、0 であるかのように扱われる)。 それに応じて X' を更新する。
X' が宛先型 T の最も正または最も負の有限値である場合、 XOut = X' と設定する。
それ以外の場合、XOut を宛先型 T の無限大値に、 X' と同じ符号で設定する。
注: 整数値が2つの隣接する浮動小数点値の間に位置する場合もあります。 特に f32 型は 23ビットの仮数部を持ちます。 さらに、浮動小数点値が正規化範囲内(指数が極端でない)なら、仮数部は 小数部ビットに加え最上位の23ビット目に1ビットが追加されます。 例えば整数 228 と 1+228 は同じ浮動小数点値にマッピングされます。 最下位1ビットの差が浮動小数点型で表現できません。 このような衝突は絶対値が 225 以上の隣接整数のペアで発生します。
注: 元の型が i32 または u32 のいずれかであり、宛先型が f32 である場合、元の値は常に 宛先型の範囲内にある。
注: ソース型がターゲット浮動小数点型より指数部・仮数部ビットが少ない場合、元の値は必ず変換先型の範囲内です。
15.7.7. 浮動小数点式および組み込み関数の定義域
前節では、浮動小数点式が定義域外で評価された場合の期待される挙動を説明しています。
§ 8.7 算術式と§ 17.5 数値組み込み関数では、浮動小数点式と組み込み関数の定義域を定義しています。 特に制限がない場合、その演算の定義域は全ての有限・無限入力を含みます。 それ以外の場合は明示的な定義域が記載されています。
多くの場合、WGSL の演算が IEEE-754 で定義されている演算に対応している場合、定義域も一致します。
例えば WGSL および IEEE-754 の acos 演算は定義域が [−1,1] です。
要素単位演算で明示的な定義域がある場合は、スカラーケースのみ記載されます。ベクトルの場合は要素単位の意味から推論されます。
WGSL の一部の演算は他の WGSL 式で実装される場合があります。 § 15.7.4 浮動小数点精度では、そのような演算の精度を継承としています。 これらの演算の定義域を列挙する際は、以下のいずれかとなります:
-
定義域が明示的に記載されている場合
-
定義域が 線形項から推論とされている場合、定義域は次のように導かれます:
-
元の演算を「継承」式で置き換え、加算・減算・乗算の組み合わせとして扱う。
-
残った演算の定義域制約をパラメータに適用・合成する。
-
例:2要素ベクトル a、b に対する dot(a,b) 関数の精度は、式
a[0] * b[0] + a[1] * b[1] から継承されます。
これは2回の浮動小数点乗算と1回の浮動小数点加算を利用します。
したがって、定義域は以下を除く拡
-
浮動小数点の乗算は、片方のオペランドがゼロでもう片方が無限大の場合を除き、拡張実数上でよく定義されています。
-
浮動小数点の加算は、二つのオペランドが符号が逆の無限大の場合を除き、よく定義されています。
-
したがって、定義域は拡張実数の2要素ベクトル a と b の全ての組み合わせですが、以下を除きます:
-
乗算から導かれるもの:
-
a[i] がゼロで b[i] が無限大の場合。
-
a[i] が無限大で b[i] がゼロの場合。
-
-
加算から導かれるもの:
-
a[0] × b[0] が +∞ かつ a[1] × b[1] が +∞ の場合。
-
a[0] × b[0] が −∞ かつ a[1] × b[1] が −∞ の場合。
-
-
16. キーワードとトークンの概要
16.1. キーワードの概要
-
alias -
break -
case -
const -
const_assert -
continue -
continuing -
default -
diagnostic -
discard -
else -
enable -
false -
fn -
for -
if -
let -
loop -
override -
requires -
return -
struct -
switch -
true -
var -
while
16.2. 予約語
予約語は、将来使用のために予約されているトークンです。 WGSLモジュールは予約語を含めてはなりません。
以下は予約語です:
| 'NULL'
| 'Self'
| 'abstract'
| 'active'
| 'alignas'
| 'alignof'
| 'as'
| 'asm'
| 'asm_fragment'
| 'async'
| 'attribute'
| 'auto'
| 'await'
| 'become'
| 'cast'
| 'catch'
| 'class'
| 'co_await'
| 'co_return'
| 'co_yield'
| 'coherent'
| 'column_major'
| 'common'
| 'compile'
| 'compile_fragment'
| 'concept'
| 'const_cast'
| 'consteval'
| 'constexpr'
| 'constinit'
| 'crate'
| 'debugger'
| 'decltype'
| 'delete'
| 'demote'
| 'demote_to_helper'
| 'do'
| 'dynamic_cast'
| 'enum'
| 'explicit'
| 'export'
| 'extends'
| 'extern'
| 'external'
| 'fallthrough'
| 'filter'
| 'final'
| 'finally'
| 'friend'
| 'from'
| 'fxgroup'
| 'get'
| 'goto'
| 'groupshared'
| 'highp'
| 'impl'
| 'implements'
| 'import'
| 'inline'
| 'instanceof'
| 'interface'
| 'layout'
| 'lowp'
| 'macro'
| 'macro_rules'
| 'match'
| 'mediump'
| 'meta'
| 'mod'
| 'module'
| 'move'
| 'mut'
| 'mutable'
| 'namespace'
| 'new'
| 'nil'
| 'noexcept'
| 'noinline'
| 'nointerpolation'
| 'non_coherent'
| 'noncoherent'
| 'noperspective'
| 'null'
| 'nullptr'
| 'of'
| 'operator'
| 'package'
| 'packoffset'
| 'partition'
| 'pass'
| 'patch'
| 'pixelfragment'
| 'precise'
| 'precision'
| 'premerge'
| 'priv'
| 'protected'
| 'pub'
| 'public'
| 'readonly'
| 'ref'
| 'regardless'
| 'register'
| 'reinterpret_cast'
| 'require'
| 'resource'
| 'restrict'
| 'self'
| 'set'
| 'shared'
| 'sizeof'
| 'smooth'
| 'snorm'
| 'static'
| 'static_assert'
| 'static_cast'
| 'std'
| 'subroutine'
| 'super'
| 'target'
| 'template'
| 'this'
| 'thread_local'
| 'throw'
| 'trait'
| 'try'
| 'type'
| 'typedef'
| 'typeid'
| 'typename'
| 'typeof'
| 'union'
| 'unless'
| 'unorm'
| 'unsafe'
| 'unsized'
| 'use'
| 'using'
| 'varying'
| 'virtual'
| 'volatile'
| 'wgsl'
| 'where'
| 'with'
| 'writeonly'
| 'yield'
16.3. 構文トークン
構文トークンは、 特殊なコードポイントの並びであり、以下の目的で使用されます:
-
式演算子を表記するため、または
-
句読点として:他の文法要素をグループ化、並べる、または区切るため。
構文トークンは次の通りです:
-
'&'(コードポイント:U+0026) -
'&&'(コードポイント:U+0026U+0026) -
'->'(コードポイント:U+002DU+003E) -
'@'(コードポイント:U+0040) -
'/'(コードポイント:U+002F) -
'!'(コードポイント:U+0021) -
'['(コードポイント:U+005B) -
']'(コードポイント:U+005D) -
'{'(コードポイント:U+007B) -
'}'(コードポイント:U+007D) -
':'(コードポイント:U+003A) -
','(コードポイント:U+002C) -
'='(コードポイント:U+003D) -
'=='(コードポイント:U+003DU+003D) -
'!='(コードポイント:U+0021U+003D) -
'>'(コードポイント:U+003E)(また、テンプレート曖昧性解消用_greater_than) -
'>='(コードポイント:U+003EU+003D)(また、テンプレート曖昧性解消用_greater_than_equal) -
'>>'(コードポイント:U+003EU+003E)(また、テンプレート曖昧性解消用_shift_right) -
'<'(コードポイント:U+003C)(また、テンプレート曖昧性解消用_less_than) -
'<='(コードポイント:U+003CU+003D)(また、テンプレート曖昧性解消用_less_than_equal) -
'<<'(コードポイント:U+003CU+003C)(また、テンプレート曖昧性解消用_shift_left) -
'%'(コードポイント:U+0025) -
'-'(コードポイント:U+002D) -
'--'(コードポイント:U+002DU+002D) -
'.'(コードポイント:U+002E) -
'+'(コードポイント:U+002B) -
'++'(コードポイント:U+002BU+002B) -
'|'(コードポイント:U+007C) -
'||'(コードポイント:U+007CU+007C) -
'('(コードポイント:U+0028) -
')'(コードポイント:U+0029) -
';'(コードポイント:U+003B) -
'*'(コードポイント:U+002A) -
'~'(コードポイント:U+007E) -
'_'(コードポイント:U+005F) -
'^'(コードポイント:U+005E) -
'+='(コードポイント:U+002BU+003D) -
'-='(コードポイント:U+002DU+003D) -
'*='(コードポイント:U+002AU+003D) -
'/='(コードポイント:U+002FU+003D) -
'%='(コードポイント:U+0025U+003D) -
'&='(コードポイント:U+0026U+003D) -
'|='(コードポイント:U+007CU+003D) -
'^='(コードポイント:U+005EU+003D) -
'>>='(コードポイント:U+003EU+003EU+003D)(また、テンプレート曖昧性解消用_shift_right_assign) -
'<<='(コードポイント:U+003CU+003CU+003D)(また、テンプレート曖昧性解消用_shift_left_assign) -
_template_args_end-
テキスト:
'>'(コードポイント:U+003E) -
このトークンはgreater_than 構文トークンと同じテキストです。
-
テンプレートリスト曖昧性解消によって生成され、テンプレートリストの最後のトークンとして使用されます。
-
-
_template_args_start-
テキスト:
'<'(コードポイント:U+003C) -
このトークンはless_than構文トークンと同じテキストです。
-
テンプレートリスト曖昧性解消によって生成され、テンプレートリストの最初のトークンとして使用されます。
-
-
_disambiguate_template-
テキスト:なし
-
§ 3.1 構文解析で示されている標準のパーサー定式化では、このトークンは何の役割も果たさず、実質的に無視されます。 無視するために、スキャナーは常にこれに空文字列との一致に成功します。
-
§ 3.1 構文解析で示されている代替のパーサー定式化では、このトークンはテンプレートリスト探索を必要に応じてスキャナーに実行させるトリガーとなります(詳細はそのセクションを参照)。
-
17. 組み込み関数
いくつかの関数は事前宣言されており、 実装によって提供されるため、WGSLモジュールで常に利用可能です。 これらは組み込み関数と呼ばれます。
組み込み関数は、同じ名前を持つ関数群であり、 それぞれは仮引数の数、順序、型によって区別されます。 それぞれの異なる関数バリエーションはオーバーロードです。
注: 各ユーザー定義関数は 1つのオーバーロードしか持ちません。
各オーバーロードは以下の内容で記述されます:
組み込み関数を呼び出す際、すべての引数は関数の評価が始まる前に評価されます。 § 11.2 関数呼び出しを参照してください。
17.1. コンストラクタ組み込み関数
値コンストラクタ組み込み関数は、 指定した型の値を明示的に生成します。
WGSL は、すべての事前宣言型およびすべての 構築可能な 構造体型に対して値コンストラクターを提供する。 そのようなコンストラクタービルトイン関数は、その型と同じ綴り、またはその型の型エイリアスと同じ綴りを持つ。 そのようなビルトイン関数が使用される場所では、識別子は その型または型エイリアスの スコープ内に なければならず、 その識別子は 別の宣言に 解決されては ならない。
注: frexp、 modf、およびatomicCompareExchangeWeakが返す構造体型は WGSLモジュール内で記述できません。
注: その型の値宣言は、そのWGSLテキストのその文において有効でなければなりません。
WGSLは2種類の値コンストラクタを提供します:
-
値コンストラクタ(変換も提供)
17.1.1. ゼロ値組み込み関数
各具象かつ構築可能な T は、
一意なゼロ値を持ち、
WGSL では型の後に空の丸括弧の組を続けて書かれる、対応する組み込み関数を持つ:
T ()。
抽象数値
型もゼロ値を持つが、それらにアクセスする組み込み関数は存在しない。
ゼロ値は次のとおりである:
-
bool()はfalseである -
i32()は 0i である -
u32()は 0u である -
f32()は 0.0f である -
f16()は 0.0h である -
型 T の N 成分ベクトルのゼロ値は、T のゼロ値からなる N 成分ベクトルである。
-
型 T の C 列 R 行行列のゼロ値は、 その次元を持ち、T のゼロ値で埋められた行列である。
-
要素型 E を持つ構築可能な N 要素配列のゼロ値は、 E のゼロ値からなる N 個の要素の配列である。
-
構築可能な構造体型 S のゼロ値は、ゼロ値のメンバーを持つ構造体値 S である。
-
AbstractInt のゼロ値は 0 である。
-
AbstractFloat のゼロ値は 0.0 である。
注記: WGSL には、アトミック型、 実行時サイズ配列、または構築可能でない他の型に対するゼロ組み込み関数はない。
| オーバーロード |
|
| パラメータ化 | T は具象な構築可能型である。 |
| 説明 | 型 T のゼロ値を
構築する。
|
注記: AbstractInt のゼロで埋められたベクトルは、
vec2()、vec3()、および vec4() として書ける。
vec2< f32> () // f32 成分 2 個のゼロ値ベクトル。 vec2< f32> ( 0.0 , 0.0 ) // 同じ値を明示的に書いたもの。 vec3< i32> () // i32 成分 3 個のゼロ値ベクトル。 vec3< i32> ( 0 , 0 , 0 ) // 同じ値を明示的に書いたもの。
struct Student { grade : i32, GPA : f32, attendance : array< bool, 4 > } fn func () { var s : Student ; // Student のゼロ値 s = Student (); // 同じ値を明示的に書いたもの。 s = Student ( 0 , 0.0 , array< bool, 4 > ( false , false , false , false )); // ゼロ値メンバーで書いた同じ値。 s = Student ( i32(), f32(), array< bool, 4 > ()); }
17.1.2. 値コンストラクタ組み込み関数
以下の小節で定義される組み込み関数は、構築可能な値を以下の方法で生成します:
-
同じ型の既存の値をコピー(つまり恒等関数)、または
-
明示的な成分リストから複合値を生成。
-
他の値型から変換。
ベクトルおよび行列型のコンストラクタは、成分やサブベクトルの組み合わせから、成分型が一致するベクトル・行列値を構築します。 ベクトルや行列の構築では、対象型の次元のみを指定し、成分型はコンストラクタ引数から推論されるオーバーロードもあります。
17.1.2.1. array
| オーバーロード |
|
| パラメータ化 | T は具象かつ構築可能である
|
| 説明 |
要素から配列を
構築する。
注記: array<T,N> は構築可能である。なぜなら、その要素数は コンストラクタへの引数の数に等しく、したがって シェーダー作成時に完全に決定されるからである。 |
| オーバーロード |
|
| パラメータ化 | T は構築可能である
|
| 説明 |
要素から配列を
構築する。
成分型は要素の型から推論される。 配列のサイズは要素の数によって決定される。 |
17.1.2.2. bool
| オーバーロード |
|
| パラメータ化 | Tはスカラー型です。
|
| 説明 |
bool値を構築します。
もし |
17.1.2.3. f16
| オーバーロード |
|
| パラメータ化 | Tはスカラー型です
|
| 説明 |
f16値を構築します。
もし |
17.1.2.4. f32
| オーバーロード |
|
| パラメータ化 | Tは具体的スカラー型です
|
| 説明 |
f32値を構築します。
もし |
17.1.2.5. i32
| オーバーロード |
|
| パラメータ化 | T はスカラー型である
|
| 説明 |
i32 値を構築する。
|
17.1.2.6. mat2x2
| オーバーロード |
|
| パラメータ化 | Tはf16またはf32SはAbstractFloat、f16、またはf32です
|
| 説明 |
2x2列主導の行列のコンストラクタです。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32です
|
| 説明 | 列ベクトルから2x2列主導行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32です
|
| 説明 |
要素から2x2列主導行列を構築します。
mat2x2(vec2(e1,e2), vec2(e3,e4))と同じです。 |
17.1.2.7. mat2x3
| オーバーロード |
|
| パラメータ化 | T は f16 または f32S は AbstractFloat、f16、または f32
|
| 説明 |
2x3 列主導 行列のコンストラクタ。
|
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat、f16、または f32
|
| 説明 | 列ベクトルから 2x3 列主導 行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat、f16、または f32
|
| 説明 |
要素から 2x3 列主導 行列を構築します。
mat2x3(vec3(e1,e2,e3), vec3(e4,e5,e6)) と同じです。 |
17.1.2.8. mat2x4
| オーバーロード |
|
| パラメータ化 | T は f16 または f32S は AbstractFloat、f16、または f32
|
| 説明 |
2x4 列主導 行列のコンストラクタ。
|
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat、f16、または f32
|
| 説明 | 列ベクトルから 2x4 列主導 行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat、f16、または f32
|
| 説明 |
要素から 2x4 列主導 行列を構築します。
mat2x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8)) と同じです。 |
17.1.2.9. mat3x2
| オーバーロード |
|
| パラメータ化 | T は f16 または f32S は AbstractFloat、f16、または f32
|
| 説明 |
3x2 列主導 行列のコンストラクタ。
|
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat、f16、または f32
|
| 説明 | 列ベクトルから 3x2 列主導 行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat、f16、または f32
|
| 説明 |
要素から 3x2 列主導 行列を構築します。
mat3x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6)) と同じです。 |
17.1.2.10.
mat3x3
| オーバーロード |
|
| パラメータ化 | Tはf16またはf32SはAbstractFloat、f16、またはf32
|
| 説明 |
3x3列主導行列のコンストラクタ。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 | 列ベクトルから3x3列主導行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 |
要素から3x3列主導行列を構築します。
mat3x3(vec3(e1,e2,e3), vec3(e4,e5,e6), vec3(e7,e8,e9))と同じです。 |
17.1.2.11.
mat3x4
| オーバーロード |
|
| パラメータ化 | Tはf16またはf32SはAbstractFloat、f16、またはf32
|
| 説明 |
3x4列主導行列のコンストラクタ。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 | 列ベクトルから3x4列主導行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 |
要素から3x4列主導行列を構築します。
mat3x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8), vec4(e9,e10,e11,e12))と同じです。 |
17.1.2.12.
mat4x2
| オーバーロード |
|
| パラメータ化 | Tはf16またはf32SはAbstractFloat、f16、またはf32
|
| 説明 |
4x2列主導行列のコンストラクタ。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 | 列ベクトルから4x2列主導行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 |
要素から4x2列主導行列を構築します。
mat4x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6), vec2(e7,e8))と同じです。 |
17.1.2.13.
mat4x3
| オーバーロード |
|
| パラメータ化 | Tはf16またはf32SはAbstractFloat、f16、またはf32
|
| 説明 |
4x3列主導行列のコンストラクタ。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 | 列ベクトルから4x3列主導行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 |
要素から4x3列主導行列を構築します。
mat4x3(vec3(e1,e2,e3), vec3(e4,e5,e6), vec3(e7,e8,e9), vec3(e10,e11,e12))と同じです。 |
17.1.2.14.
mat4x4
| オーバーロード |
|
| パラメータ化 | Tはf16またはf32SはAbstractFloat、f16、またはf32
|
| 説明 |
4x4列主導行列のコンストラクタ。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 | 列ベクトルから4x4列主導行列を構築します。 |
| オーバーロード |
|
| パラメータ化 | TはAbstractFloat、f16、またはf32
|
| 説明 |
要素から4x4列主導行列を構築します。
mat4x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8), vec4(e9,e10,e11,e12), vec4(e13,e14,e15,e16))と同じです。 |
17.1.2.15. 構造体
| オーバーロード |
|
| パラメータ化 | Sは、メンバーの型がT1...TNである構築可能な構造体型です。
|
| 説明 | メンバーから型Sの構造体を構築します。
|
17.1.2.16. u32
| オーバーロード |
|
| パラメータ化 | T はスカラー型である
|
| 説明 |
u32 値を構築する。
|
|
注:
AbstractInt からの
オーバーロードが存在するのは、 |
17.1.2.17. vec2
| オーバーロード |
|
| パラメータ化 | Tは具体的なスカラー型Sはスカラー型
|
| 説明 | 2成分のベクトルをeを両成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tは具体的なスカラー型Sはスカラー型
|
| 説明 |
成分ごとの2成分ベクトルをe.xとe.yを成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの2成分ベクトルをe1とe2を成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractInt
|
| 説明 | vec2(0,0)の値を返します。
|
17.1.2.18. vec3
| オーバーロード |
|
| パラメータ化 | Tは具体的なスカラー型Sはスカラー型
|
| 説明 | 3成分ベクトルをeをすべての成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tは具体的なスカラー型Sはスカラー型
|
| 説明 |
成分ごとの3成分ベクトルをe.x、e.y、e.zを成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの3成分ベクトルをe1、e2、e3を成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの3成分ベクトルをv1.x、v1.y、e1を成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの3成分ベクトルをe1、v1.x、v1.yを成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractInt
|
| 説明 | vec3(0,0,0)の値を返します。
|
17.1.2.19. vec4
| オーバーロード |
|
| パラメータ化 | Tは具体的なスカラー型Sはスカラー型
|
| 説明 | 4成分ベクトルをeをすべての成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tは具体的なスカラー型Sはスカラー型
|
| 説明 |
成分ごとの4成分ベクトルをe.x、e.y、e.z、e.wを成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの4成分ベクトルをe1、e2、e3、e4を成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの4成分ベクトルをe1、v1.x、v1.y、e2を成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの4成分ベクトルをe1、e2、v1.x、v1.yを成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの4成分ベクトルをv1.x、v1.y、v2.x、v2.yを成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの4成分ベクトルをv1.x、v1.y、e1、e2を成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | Tはスカラー型
|
| 説明 | 成分ごとの4成分ベクトルをv1.x、v1.y、v1.z、e1を成分として構築します。
|
| オーバーロード |
|
| パラメータ化 | TはAbstractInt
|
| 説明 | vec4(0,0,0,0)の値を返します。
|
17.2. ビット再解釈組み込み関数
17.2.1. bitcast
bitcast 組み込み関数は、ある型の値のビット表現を別の型の値として再解釈するために使用されます。
内部レイアウトの規則は § 14.4.4 値の内部レイアウトで説明されています。
| オーバーロード |
|
| パラメータ化 | T は具象な数値スカラーまたは具象な数値ベクトルである
|
| 説明 | 恒等変換。 成分ごと。 T がベクトルである場合。結果は e である。
|
| オーバーロード |
|
| パラメータ化 | S は i32、u32、または f32 であるT は S ではなく、i32、u32、または f32 である
|
| 説明 | T としてのビットの再解釈。結果は、 e 内のビットを T 値として再解釈したものである。
|
| オーバーロード |
|
| パラメータ化 | S は i32、u32、または f32 であるT は S ではなく、i32、u32、または f32 である
|
| 説明 | T としてのビットの成分ごとの
再解釈。結果は、 e 内のビットを vecN<T> 値として再解釈したものである。
|
| オーバーロード |
|
| パラメータ化 | |
| 説明 |
e が u32
として表現可能であれば恒等演算であり、
そうでない場合はシェーダー作成エラーが発生する。
すなわち、u32(e) と同じ結果を生成する。
|
| オーバーロード |
|
| パラメータ化 | T は i32、u32、または f32 である
|
| 説明 | T としてのビットの成分ごとの
再解釈。結果は、内部レイアウト規則に従って、 e 内の 32 ビットを T 値として再解釈したものである。
|
| オーバーロード |
|
| パラメータ化 | T は i32、u32、または f32 である |
| 説明 | T としてのビットの成分ごとの
再解釈。結果は、内部レイアウト規則に従って、 e 内の 64 ビットを T 値として再解釈したものである。
|
| オーバーロード |
|
| パラメータ化 | T は i32、u32、または f32 である
|
| 説明 | f16 としてのビットの成分ごとの
再解釈。 結果は、内部レイアウト規則に従って、 e 内の 32 ビットを f16 値として再解釈したものである。
|
| オーバーロード |
|
| パラメータ化 | T は i32、u32、または f32 である
|
| 説明 | vec2<f16> としてのビットの成分ごとの
再解釈。結果は、内部レイアウト規則に従って、 e 内の 64 ビットを f16 値として再解釈したものである。
|
17.3. 論理組み込み関数
17.3.1. all
| オーバーロード |
|
| 説明 | e の各要素が true の場合に true を返します。
|
| オーバーロード |
|
| 説明 | e を返します。
|
17.3.2. any
| オーバーロード |
|
| 説明 | e のいずれかの要素が true の場合に true を返します。
|
| オーバーロード |
|
| 説明 | e を返します。
|
17.3.3. select
| オーバーロード |
|
| パラメータ化 | T は スカラー または ベクター
|
| 説明 | cond が true の場合は t、そうでない場合は f を返します。
|
| オーバーロード |
|
| パラメータ化 | T は スカラー
|
| 説明 | 要素ごとに選択します。結果の要素 i は
select(f[i], t[i], cond[i]) として評価されます。
|
17.4. 配列組み込み関数
17.4.1.
arrayLength
| オーバーロード |
|
| パラメータ化 | E は 実行時サイズ配列の要素型,アクセスモード AM は read または read_write
|
| 説明 |
NRuntime、すなわち実行時サイズ配列内の要素数を返します。
詳細は § 13.3.4 バッファバインディングによる実行時サイズ配列要素数の決定 を参照してください。 |
struct PointLight { position: vec3f, color : vec3f, } struct LightStorage { pointCount : u32, point : array< PointLight > , } @group ( 0 ) @binding ( 1 ) var < storage> lights : LightStorage ; fn num_point_lights () -> u32{ return arrayLength ( & lights . point ); }
17.5. 数値組み込み関数
17.5.1. abs
| オーバーロード |
|
| パラメータ化 | S は AbstractInt, AbstractFloat, i32, u32, f32, または f16 T は S または vecN<S> |
| 説明 |
e の絶対値。
要素ごと、T がベクターの場合。
|
17.5.2. acos
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
e の逆余弦(cos-1)の主値(ラジアン)を返します。すなわち、 cos(x) = e となる 0 ≤ x ≤ π の
x を近似します。
要素ごと、 |
| スカラー定義域 | 区間 [−1, 1] |
17.5.3. acosh
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
x の逆双曲線余弦(cosh-1)を双曲線角として返します。すなわち、 cosh(a) = x となる 0 ≤ a ≤ +∞ の a を近似します。
要素ごと、 |
| スカラー定義域 | 区間 [1, +∞] |
17.5.4. asin
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
e の逆正弦(sin-1)の主値(ラジアン)を返します。すなわち、 sin(x) = e となる -π/2 ≤ x ≤ π/2 の
x を近似します。
要素ごと、 |
| スカラー定義域 | 区間 [−1, 1] |
17.5.5. asinh
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
y の逆双曲線正弦(sinh-1)を双曲線角として返します。すなわち、 sinh(y) = a となる a を近似します。
要素ごと、 |
17.5.6. atan
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
e の逆正接(tan-1)の主値(ラジアン)を返します。すなわち、 tan(x) = e となる − π/2 ≤ x ≤ π/2 の
x を近似します。
要素ごと、 |
17.5.7. atanh
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
t の逆双曲線正接(tanh-1)を双曲線角として返します。すなわち、 tanh(a) = t となる a を近似します。
要素ごと、 |
| スカラー定義域 | 区間 [−1, 1] |
17.5.8. atan2
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
角度(ラジアン単位)を区間 [-π, π] で返し、その正接が
y÷x となります。
結果の象限は
注: 結果の誤差は無制限です:
要素ごと、 |
17.5.9. ceil
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | 天井(ceil)を
e に対して返します。
要素ごと、T がベクターの場合。
|
17.5.10. clamp
| オーバーロード |
|
| パラメータ化 | S は AbstractInt, AbstractFloat, i32, u32, f32, または f16 T は S または vecN<S> |
| 説明 |
e の値を範囲内に制限します。
要素ごと、
|
17.5.11. cos
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e(ラジアン単位)の余弦を返します。
要素ごと、T がベクターの場合。
|
| スカラー定義域 | 区間 (−∞, +∞) |
17.5.12. cosh
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
a(双曲線角)の双曲線余弦を返します。
純粋な数学関数 (ea +
e−a)÷2 を近似しますが、必ずしもその方法で計算されるわけではありません。
要素ごと、 |
17.5.13.
countLeadingZeros
| オーバーロード |
|
| パラメータ化 | T は i32, u32, vecN<i32>, または vecN<u32>
|
| 説明 | T がスカラー型の場合、e の最上位ビットから連続する 0 のビット数。要素ごと、 T がベクターの場合。一部の言語では "clz" とも呼ばれます。 |
17.5.14.
countOneBits
| オーバーロード |
|
| パラメータ化 | T は i32, u32, vecN<i32>, または vecN<u32>
|
| 説明 | e の表現に含まれる 1 のビット数。"population count" とも呼ばれます。 要素ごと、 T がベクターの場合。
|
17.5.15.
countTrailingZeros
| オーバーロード |
|
| パラメータ化 | T は i32, u32, vecN<i32>, または vecN<u32>
|
| 説明 | T がスカラー型の場合、e の最下位ビットから連続する 0 のビット数。要素ごと、 T がベクターの場合。一部の言語では "ctz" とも呼ばれます。 |
17.5.16. cross
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat, f32, または f16
|
| 説明 | e1 と e2 の外積を返します。
|
| 定義域 |
線形項から暗黙的に決定される可能な実装:
|
17.5.17. degrees
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | ラジアンから度への変換(e1 × 180 ÷ π の近似)。
要素ごと、T がベクターの場合
|
17.5.18.
determinant
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat, f32, または f16
|
| 説明 | e の行列式を返します。
|
| 定義域 | 標準的な数学的な行列式定義における線形項から暗黙的に決定。 |
17.5.19. distance
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
e1 と e2 の距離を返します(例:
length(e1 - e2))。
定義域は、
減算 e1−e2 が有効なすべてのベクター (e1,e2) です。
すなわち、ある要素 |
17.5.20. dot
| オーバーロード |
|
| パラメータ化 | T は AbstractInt, AbstractFloat, i32, u32, f32, または f16
|
| 説明 | e1 と e2 のドット積(内積)を返します。
|
| 定義域 | 線形項の和(e1[i] × e2[i])から暗黙的に決定されます。 |
17.5.21.
dot4U8Packed
| オーバーロード |
|
| 説明 | e1 および e2 は4つの8ビット符号なし整数成分を持つベクターとして解釈されます。
この2つのベクターの符号なし整数ドット積を返します。
|
17.5.22.
dot4I8Packed
| オーバーロード |
|
| 説明 | e1 および e2 は4つの8ビット符号付き整数成分を持つベクターとして解釈されます。
この2つのベクターの符号付き整数ドット積を返します。各成分は乗算前にi32へ符号拡張され、その後加算はWGSLのi32で行われます(加算はオーバーフローしません。結果は数学的に-65024から65536の範囲に収まるため、i32で十分表現可能です)。
|
17.5.23. exp
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e1 の自然指数関数(例:ee1)を返します。
要素ごと、T がベクターの場合。
|
17.5.24. exp2
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e の2乗(例:2e)を返します。
要素ごと、T がベクターの場合。
|
17.5.25.
extractBits (signed)
| オーバーロード |
|
| パラメータ化 | T は i32 または vecN<i32>
|
| 説明 |
整数からビットを読み取り、符号拡張を行います。
T がベクターの場合。
|
17.5.26.
extractBits (unsigned)
| オーバーロード |
|
| パラメータ化 | T は u32 または vecN<u32>
|
| 説明 |
整数からビットを読み取り、符号拡張はしません。
T がベクターの場合。
|
17.5.27.
faceForward
| オーバーロード |
|
| パラメータ化 | T は vecN<AbstractFloat>, vecN<f32>, または vecN<f16>
|
| 説明 | dot(e2, e3) が負の場合は e1 を、そうでなければ -e1 を返します。
|
| 定義域 | dot(e2,e3) 演算に由来する定義域制約:線形項(e2[i] ×
e3[i])の和から暗黙的に決定されます。
|
17.5.28. firstLeadingBit (signed)
| オーバーロード |
|
| パラメータ化 | T は i32 または vecN<i32>
|
| 説明 |
スカラー T の場合、結果は以下の通りです:
要素ごと、 |
|
注:符号付き整数は2の補数表現であるため、 符号ビットは最上位ビット位置に現れます。 |
17.5.29. firstLeadingBit (unsigned)
| オーバーロード |
|
| パラメータ化 | T は u32 または vecN<u32>
|
| 説明 |
スカラー T の場合、結果は以下の通りです:
T がベクターの場合。
|
17.5.30.
firstTrailingBit
| オーバーロード |
|
| パラメータ化 | T は i32, u32, vecN<i32>, または vecN<u32>
|
| 説明 |
スカラー T の場合、結果は以下の通りです:
T がベクターの場合。
|
17.5.31. floor
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e の床(floor)を返します。
要素ごと、T がベクターの場合。
|
17.5.32. fma
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
e1 * e2 + e3 を返します。
要素ごと、T がベクターの場合。
注: 注:
IEEE-754
の |
| 定義域 | 線形項(e2 × e2 + e3)から暗黙的に決定されます。 |
17.5.33. fract
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e - floor(e) として計算される e の小数部分を返します。要素ごと、 T がベクターの場合。
|
|
注: 有効な結果は閉区間 [0, 1.0] に収まります。
例えば |
17.5.34. frexp
| オーバーロード |
|
| パラメータ化 | T は f32
|
| 説明 |
e を小数部と指数部に分割します。
注: |
|
注: |
| オーバーロード |
|
| パラメータ化 | T は f16
|
| 説明 |
e を小数部と指数部に分割します。
注: |
|
注: |
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat
|
| 説明 |
e を小数部と指数部に分割します。
注: AbstractFloat 式で無限大や NaN になるとシェーダー生成エラーとなります。
注: |
|
注: |
| オーバーロード |
|
| パラメータ化 | T は vecN<f32>
|
| 説明 |
e の各要素 ei を小数部と指数部に分割します。
注: |
|
注: |
| オーバーロード |
|
| パラメータ化 | T は vecN<f16>
|
| 説明 |
e の各要素 ei を小数部と指数部に分割します。
注: |
|
注: |
| オーバーロード |
|
| パラメータ化 | T は vecN<AbstractFloat>
|
| 説明 |
e の各要素 ei を小数部と指数部に分割します。
注: AbstractFloat 式で無限大や NaN になるとシェーダー生成エラーとなります。
注: |
|
注:
|
17.5.35.
insertBits
| オーバーロード |
|
| パラメータ化 | T は i32, u32, vecN<i32>, または vecN<u32>
|
| 説明 |
整数のビットを設定します。
T がベクターの場合。
|
17.5.36.
inverseSqrt
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | sqrt(e) の逆数を返します。
要素ごと、T がベクターの場合。
|
| スカラー定義域 | 区間 [0, +∞] |
17.5.37. ldexp
| オーバーロード |
|
| パラメータ化 |
S は AbstractFloat、f32、または f16 である T は S または vecN<S> である I は AbstractInt、i32、vecN<AbstractInt>、または vecN<i32> であるT がベクトルである場合、かつその場合に限り、I はベクトルであるT が抽象になれるのは、I も抽象である場合に限り、その逆も同様である
注記: いずれかのパラメーターが具象である場合、 もう一方のパラメーターは (適用可能であれば)自動変換によって 具象 型になり、結果は 具象 型になる。 |
| 説明 |
次を除き、e1 * 2e2 を返す:
ここで、bias は浮動小数点形式の指数バイアスである:
x = ldexp(frexp(x).fract, frexp(x).exp)
注記:
|
17.5.38. length
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
e の長さを返します。T がスカラーの場合は絶対値。T がベクター型の場合は sqrt(e[0]2
+ e[1]2 + ...) で評価。
注: スカラーの場合 |
17.5.39. log
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e の自然対数を返します。
要素ごと、T がベクターの場合。
|
| スカラー定義域 | 区間 [0, +∞] |
17.5.40. log2
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e の底2の対数を返します。
要素ごと、T がベクターの場合。
|
| スカラー定義域 | 区間 [0, +∞] |
17.5.41.
max
| オーバーロード |
|
| パラメータ化 | S は AbstractInt, AbstractFloat, i32, u32, f32, または f16 T は S または vecN<S> |
| 説明 |
e1 が e2 より小さい場合は e2 を、そうでなければ e1 を返します。
要素ごと、T がベクターの場合。
|
17.5.42.
min
| オーバーロード |
|
| パラメータ化 | S は AbstractInt, AbstractFloat, i32, u32, f32, または f16 T は S または vecN<S> |
| 説明 |
e2 が e1 より小さい場合は e2 を、そうでなければ e1 を返します。
要素ごと、T がベクターの場合。
|
17.5.43. mix
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e1 と e2 の線形合成(例:e1 * (T(1) - e3) + e2 * e3)を返します。
要素ごと、T がベクターの場合。
|
| 定義域 | 線形項(e1[i] × (1 − e3[i]) + e2[i] × e3[i]、 e2[i] × e2[i] + e3[i])から暗黙的に決定されます。 |
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat, f32, または f16T2 は vecN<T>
|
| 説明 | e1 と e2 の要素ごとの線形合成を、スカラー合成係数 e3 で各要素に適用します。mix(e1, e2, T2(e3)) と同じです。
|
| 定義域 | 線形項(e1[i] × (1 − e3) + e2[i] × e3)から暗黙的に決定されます。 |
17.5.44. modf
| オーバーロード |
|
| パラメータ化 | T は f32
|
| 説明 |
e を小数部と整数部に分割します。
整数部は trunc(
|
|
注: |
| オーバーロード |
|
| パラメータ化 | T は f16
|
| 説明 |
e を小数部と整数部に分割します。
整数部は trunc(
|
|
注: |
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat
|
| 説明 |
e を小数部と整数部に分割します。
整数部は trunc(
|
|
注: |
| オーバーロード |
|
| パラメータ化 | T は vecN<f32>
|
| 説明 |
e の各要素を小数部と整数部に分割します。
整数部および小数部の
|
|
注: |
| オーバーロード |
|
| パラメータ化 | T は vecN<f16>
|
| 説明 |
e の各要素を小数部と整数部に分割します。
整数部および小数部の
|
|
注: |
| オーバーロード |
|
| パラメータ化 | T は vecN<AbstractFloat>
|
| 説明 |
e の各要素を小数部と整数部に分割します。
整数部および小数部の
|
|
注:
|
17.5.45.
normalize
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat, f32, または f16
|
| 説明 |
e と同じ方向の単位ベクトルを返します。
定義域はゼロベクトル以外のすべてのベクトルです。 |
17.5.46. pow
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e1 の e2 乗を返します。
要素ごと、T がベクターの場合。
|
| スカラー定義域 |
拡張実数
(x,y) の全ての組み合わせ。ただし:
結果が |
17.5.47.
quantizeToF16
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
32ビット浮動小数点値 e を、
IEEE-754 の
binary16
値に変換し、さらに
IEEE-754 binary32 値に戻したかのように量子化します。
中間の binary16 値はゼロクリアされる場合があります。すなわち、 中間の binary16 値が非正規化の場合、最終結果がゼロになる場合があります。 § 15.7.6 浮動小数点変換も参照。 要素ごと、 |
|
注: vec2<f32> の場合は
|
17.5.48. radians
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | 度からラジアンへの変換(e1 × π ÷ 180 の近似)。
要素ごと、T がベクターの場合
|
17.5.49. reflect
| オーバーロード |
|
| パラメータ化 | T は vecN<AbstractFloat>, vecN<f32>, または vecN<f16>
|
| 説明 | 入射ベクトル e1 と表面の向き e2 について、
反射方向 e1 - 2 * dot(e2, e1) * e2 を返します。
|
17.5.50. refract
| オーバーロード |
|
| パラメータ化 | T は vecN<I>I は AbstractFloat, f32, または f16
|
| 説明 | 入射ベクトル e1、表面法線 e2、屈折率の比 e3 について、
k = 1.0 - e3 * e3 * (1.0 - dot(e2, e1) * dot(e2, e1)) とする。
k < 0.0 の場合は屈折ベクトル 0.0 を返し、それ以外の場合は
屈折ベクトル e3 * e1 - (e3 * dot(e2, e1) + sqrt(k)) * e2 を返します。
入射ベクトル e1 と法線 e2 はスネルの法則に従い正規化されていることが望ましく、
そうでない場合、結果は物理的な振る舞いと一致しない可能性があります。
|
17.5.51.
reverseBits
| オーバーロード |
|
| パラメータ化 | T は i32, u32, vecN<i32>, または vecN<u32>
|
| 説明 | e のビットを反転します:結果のビット位置 k は e のビット位置 31 -k
と等しくなります。要素ごと、 T がベクターの場合。
|
17.5.52. round
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | 結果は e に最も近い整数 k(浮動小数点値)になります。e が整数 k と k + 1 のちょうど中間の場合は、
k が偶数なら k を、奇数なら k + 1 を返します。要素ごと、 T がベクターの場合。
|
17.5.53.
saturate
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | clamp(e, 0.0, 1.0) を返します。
要素ごと、T がベクターの場合。
|
17.5.54. sign
| オーバーロード |
|
| パラメータ化 | S は AbstractInt, AbstractFloat, i32, f32, または f16 T は S または vecN<S> |
| 説明 |
結果は以下の通りです:
要素ごと、 |
17.5.55. sin
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e(ラジアン単位)の正弦を返します。
要素ごと、T がベクターの場合。
|
| スカラー定義域 | 区間 (−∞, +∞) |
17.5.56. sinh
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
a(双曲線角)の双曲線正弦を返します。
純粋な数学関数
(ea − e−a)÷2 を近似しますが、必ずしもその方法で計算されるわけではありません。
要素ごと、 |
17.5.57.
smoothstep
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
0 から 1 へのスムーズなエルミート補間を返します。
要素ごと、T がベクターの場合。
スカラー 定性的には:
|
17.5.58. sqrt
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e の平方根を返します。
要素ごと、T がベクターの場合。
|
| スカラー定義域 | 区間 [0, +∞] |
17.5.59. step
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | edge ≤ x の場合は 1.0、そうでなければ 0.0 を返します。
要素ごと、T がベクターの場合。
|
17.5.60. tan
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | e(ラジアン単位)の正接を返します。
要素ごと、T がベクターの場合。
|
| スカラー定義域 | 区間 (−∞, +∞) |
17.5.61. tanh
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 |
a(双曲線角)の双曲線正接を返します。
純粋な数学関数
(ea − e−a) ÷ (ea +
e−a)
を近似しますが、必ずしもその方法で計算されるわけではありません。
要素ごと、 |
17.5.62.
transpose
| オーバーロード |
|
| パラメータ化 | T は AbstractFloat, f32, または f16
|
| 説明 | e の転置行列を返します。
|
17.5.63. trunc
| オーバーロード |
|
| パラメータ化 | S は AbstractFloat, f32, または f16 T は S または vecN<S> |
| 説明 | truncate(e)、すなわち絶対値が e
の絶対値以下となる最も近い整数値を返します。
要素ごと、T がベクターの場合。
|
17.6. 微分組み込み関数
§ 15.6.2 微分 を参照。
これらの関数の呼び出し:
-
発動:一様性解析で 呼び出しが一様な制御フローであることが証明できない場合、 derivative_uniformity 診断を発生させます。
17.6.1. dpdx
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ座標 x に関する e の偏微分。
結果は dpdxFine(e) または dpdxCoarse(e) のいずれかと同じです。
|
17.6.2. dpdxCoarse
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ座標 x に関する e の偏微分(局所差分を利用)。
dpdxFine(e) よりも一意の位置が少なくなる場合があります。
|
17.6.3. dpdxFine
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ座標 x に関する e の偏微分を返します。
|
17.6.4. dpdy
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ座標 y に関する e の偏微分。
結果は dpdyFine(e) または dpdyCoarse(e) のいずれかと同じです。
|
17.6.5. dpdyCoarse
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ座標 y に関する e の偏微分(局所差分を利用)。
dpdyFine(e) よりも一意の位置が少なくなる場合があります。
|
17.6.6. dpdyFine
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ座標 y に関する e の偏微分を返します。
|
17.6.7. fwidth
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
abs(dpdx(e)) + abs(dpdy(e)) を返します。
|
17.6.8.
fwidthCoarse
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
abs(dpdxCoarse(e)) + abs(dpdyCoarse(e)) を返します。
|
17.6.9. fwidthFine
| オーバーロード |
|
| パラメータ化 | T は f32 または vecN<f32>
|
| 説明 |
abs(dpdxFine(e)) + abs(dpdyFine(e)) を返します。
|
17.7. テクスチャ組み込み関数
パラメータ値は、各テクスチャ型に対して有効である必要があります(必須)。
17.7.1. textureDimensions
テクスチャまたはテクスチャのミップレベルの次元(テクセル数)を返します。
| パラメータ化 | オーバーロード |
|---|---|
| ST は i32、
u32、または f32 である F はテクセルフォーマットである A はアクセスモードである T は texture_1d<ST> または texture_storage_1d<F,A> である
|
|
|
ST は i32、
u32、または f32 である T は texture_1d<ST> である
|
|
| ST は i32、
u32、または f32 である F はテクセルフォーマットである A はアクセスモードである T は texture_2d<ST>、texture_2d_array<ST>、
texture_cube<ST>、
texture_cube_array<ST>、texture_multisampled_2d<ST>、
texture_depth_2d、texture_depth_2d_array、
texture_depth_cube、
texture_depth_cube_array、texture_depth_multisampled_2d、
texture_storage_2d<F,A>、texture_storage_2d_array<F,A>、
または texture_external である
|
|
|
ST は i32、
u32、または f32 である T は texture_2d<ST>、texture_2d_array<ST>、
texture_cube<ST>、
texture_cube_array<ST>、texture_depth_2d、
texture_depth_2d_array、
texture_depth_cube、または texture_depth_cube_array である
|
|
| ST は i32、
u32、または f32 である F はテクセルフォーマットである A はアクセスモードである T は texture_3d<ST> または texture_storage_3d<F,A> である
|
|
|
ST は i32、
u32、または f32 である T は texture_3d<ST> である
|
|
パラメータ:
t
| サンプルテクスチャ型、 マルチサンプルテクスチャ型、デプステクスチャ型、 ストレージテクスチャ型、または 外部テクスチャ型 のいずれかのテクスチャ。 |
level
|
ミップレベル。レベル0がテクスチャのフルサイズです。 省略時はレベル0の次元を返します。 |
戻り値:
テクスチャの座標次元を返します。
つまり、戻り値は論理テクセルアドレスの座標の整数範囲を示し、 ミップレベル数、配列サイズ、サンプル数は含みません。
キューブ型テクスチャの場合、各面の次元を返します。 キューブ面は正方形なので、戻り値の x, y 成分は等しくなります。
level が範囲 [0, textureNumLevels(t)) の外の場合、戻り値型の不定値
を返す場合があります。
17.7.2. textureGather
テクスチャギャザー 操作は2D、2D配列、キューブ、またはキューブ配列テクスチャから読み込み、 以下のように4成分のベクターを計算します:
-
線形フィルタリングによるサンプリング操作で使用される4つのテクセルを、ミップレベル0から選びます:
-
指定した座標、配列インデックス(存在する場合)、およびオフセット(存在する場合)を使用します。
-
テクセルは隣接しており、テクスチャ空間座標(u,v)で見ると正方形を形成します。
-
テクスチャ端、キューブ面端、またはキューブ角のテクセルが選ばれた場合、通常のテクスチャサンプリングと同様に扱われます。
-
-
各テクセルごとに1つのチャンネルを読み取り、スカラー値に変換します。
-
非デプステクスチャの場合、ゼロ基準の
componentパラメータで使用するチャンネルを指定します。-
テクスチャフォーマットが指定チャンネルをサポートしている、すなわち
componentチャンネル数より多い場合:-
テクセル値が
vの場合、スカラー値v[component]を返します。
-
-
それ以外の場合:
-
componentが1または2の場合は0.0を返します。 -
componentが3(アルファチャンネル)の場合は1.0を返します。
-
-
-
デプステクスチャの場合は、テクセル値を返します。(デプステクスチャは1チャンネルのみ。)
-
-
前のステップで得られたスカラーを、テクセルの相対座標に応じて以下のように4成分ベクターに並べて返します:
-
結果成分 相対テクセル座標 x (umin,vmax) y (umax,vmax) z (umax,vmin) w (umin,vmin)
-
4つのテクセルは、WebGPU サンプラー記述子に記載されたサンプリング領域を形成します。
| パラメータ化 | オーバーロード |
|---|---|
| C は i32、または
u32 である ST は i32、 u32、または f32 である |
|
| C は i32、または
u32 である ST は i32、 u32、または f32 である |
|
| C は i32、または
u32 である A は i32、または u32 である ST は i32、 u32、または f32 である |
|
| C は i32、または
u32 である A は i32、または u32 である ST は i32、 u32、または f32 である |
|
| C は i32、または
u32 である ST は i32、 u32、または f32 である |
|
| C は i32、または
u32 である A は i32、または u32 である ST は i32、 u32、または f32 である |
|
| |
| |
| |
| A は i32、または u32 である |
|
| A は i32、または u32 である |
|
| A は i32、または u32 である |
|
パラメータ:
component
|
非深度テクスチャにのみ適用される。
選択されたテクセルから読み取るチャンネルのインデックス。 指定される場合、 component 式は
const式でなければならない(例:1)。その値は少なくとも 0、最大で 3 でなければならない。 この範囲外の値はシェーダー作成エラーとなる。 |
t
| 読み取り元のサンプルテクスチャまたは深度テクスチャ。 |
s
| サンプラー型。 |
coords
| テクスチャ座標。 |
array_index
|
0 始まりのテクスチャ配列インデックス。 この値は [0, textureNumLayers(t) - 1] の範囲にクランプされる。
|
offset
|
テクスチャをサンプリングする前に、非正規化テクスチャ座標に適用される
オプションのテクセルオフセット。このオフセットは、任意の
テクスチャラッピングモードを適用する前に適用される。offset 式はconst式でなければならない(例:
vec2<i32>(1, 2))。各 offset コンポーネントは少なくとも -8、最大で
7 でなければならない。この範囲外の値はシェーダー作成エラーとなる。
|
戻り値:
選択されたテクセルから指定チャンネルの成分を抜き出して並べた4成分ベクターを返します(上記参照)。
@group ( 0 ) @binding ( 0 ) var t : texture_2d< f32> ; @group ( 0 ) @binding ( 1 ) var dt : texture_depth_2d; @group ( 0 ) @binding ( 2 ) var s : sampler; fn gather_x_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 0 , t , s , c ); } fn gather_y_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 1 , t , s , c ); } fn gather_z_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 2 , t , s , c ); } fn gather_depth_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( dt , s , c ); }
17.7.3.
textureGatherCompare
テクスチャギャザー比較操作は、デプステクスチャ内の4つのテクセルについて深度比較を行い、結果を1つのベクターにまとめて返します:
-
線形フィルタリングを用いた深度サンプリング操作で使用される4つのテクセルをミップレベル0から選びます:
-
指定した座標、配列インデックス(存在する場合)、およびオフセット(存在する場合)を使用します。
-
テクセルは隣接しており、テクスチャ空間座標(u,v)で正方形を形成します。
-
テクスチャ端、キューブ面端、またはキューブ角のテクセルが選ばれた場合は、通常のテクスチャサンプリング時と同様に扱われます。
-
-
各テクセルについて深度参照値と比較を行い、比較サンプラーのパラメータに従い0.0または1.0を返します。
-
前のステップで得られた比較結果を、テクセルの相対座標に応じて下表のように4成分ベクターとして返します:
-
結果成分 相対テクセル座標 x (umin,vmax) y (umax,vmax) z (umax,vmin) w (umin,vmin)
-
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A は i32、または u32 |
|
| A は i32、または u32 |
|
| |
| A は i32、または u32 |
|
パラメーター:
t
| 読み取り元のdepth テクスチャー。 |
s
| sampler comparison。 |
coords
| テクスチャー座標。 |
array_index
|
0 始まりのテクスチャー配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] にクランプされることになる。
|
depth_ref
| サンプリングされた depth 値と比較する参照値。 |
offset
|
テクスチャーをサンプリングする前に、正規化されていないテクスチャー座標に適用される
省略可能な texel オフセット。このオフセットは、いかなる
テクスチャーラッピングモードを適用する前に適用される。offset 式はconst-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は、少なくとも -8 かつ最大
7 でなければならない。この範囲外の値は
shader-creation error になる。
|
戻り値:
選択したテクセルの比較結果を成分とする4成分ベクター(上記参照)を返します。
@group ( 0 ) @binding ( 0 ) var dt : texture_depth_2d; @group ( 0 ) @binding ( 1 ) var s : sampler; fn gather_depth_compare ( c : vec2< f32> , depth_ref : f32) -> vec4< f32> { return textureGatherCompare ( dt , s , c , depth_ref ); }
17.7.4. textureLoad
サンプリングやフィルタリングを行わずに、テクスチャから単一のテクセルを読み取ります。
| パラメーター化 | オーバーロード |
|---|---|
| C は i32、または u32 L は i32、または u32 ST は i32、u32、または f32 |
|
| C は i32、または u32 L は i32、または u32 ST は i32、u32、または f32 |
|
| C は i32、または u32 A は i32、または u32 L は i32、または u32 ST は i32、u32、または f32 |
|
| C は i32、または u32 L は i32、または u32 ST は i32、u32、または f32 |
|
| C は i32、または u32 S は i32、または u32 ST は i32、u32、または f32 |
|
| C は i32、または u32 L は i32、または u32 |
|
| C は i32、または u32 A は i32、または u32 L は i32、または u32 |
|
| C は i32、または u32 S は i32、または u32 |
|
| C は i32、または u32 |
|
| C は i32、または u32 AM は read または read_write CF は storage texel format F に依存する。 texel format から channel format への対応については、texel format 表を参照。 |
|
| C は i32、または u32 AM は read または read_write CF は storage texel format F に依存する。 texel format から channel format への対応については、texel format 表を参照。 |
|
| C は i32、または u32 AM は read または read_write A は i32 または u32 CF は storage texel format F に依存する。 texel format から channel format への対応については、texel format 表を参照。 |
|
| C は i32、または u32 AM は read または read_write CF は storage texel format F に依存する。 texel format から channel format への対応については、texel format 表を参照。 |
|
パラメータ:
t
| サンプルテクスチャ、 マルチサンプルテクスチャ、 デプステクスチャ、 ストレージテクスチャ、または 外部テクスチャ |
coords
| 0始まりのテクセル座標。 |
array_index
| 0始まりのテクスチャ配列インデックス。 |
level
| ミップレベル。レベル0はテクスチャのフルサイズ。 |
sample_index
| マルチサンプルテクスチャの0始まりのサンプルインデックス。 |
戻り値:
フィルタリングされていないテクセルデータ。
論理テクセルアドレスが不正な場合:
-
coordsのいずれかの要素が、対応する要素の範囲[0, textureDimensions(t, level))外の場合 -
array_indexが[0, textureNumLayers(t))の範囲外の場合 -
levelが[0, textureNumLevels(t))の範囲外の場合 -
sample_indexが[0, textureNumSamples(s))の範囲外の場合
論理テクセルアドレスが不正な場合、組み込み関数は次のいずれかを返します:
-
テクスチャの範囲内にあるいずれかのテクセルのデータ。
-
非深度テクスチャの場合、次のいずれか:
-
適切な型のベクトル (0,0,0,0) または (0,0,0,1) に、texture view swizzle を適用したもの、または
-
適切な型のベクトル (0,0,0,0) または (0,0,0,1) に、texture view swizzle を適用しないもの。
-
-
深度テクスチャの場合は 0.0。
17.7.5. textureNumLayers
配列化テクスチャのレイヤー(要素)数を返します。
| パラメーター化 | オーバーロード |
|---|---|
| F はtexel
formatである A はaccess modeである ST は i32、u32、または f32 である T は texture_2d_array<ST>、texture_cube_array<ST>、
texture_depth_2d_array、texture_depth_cube_array、
または texture_storage_2d_array<F,A> である
|
|
パラメータ:
t
| サンプルテクスチャ、 デプステクスチャ、 または ストレージテクスチャの配列テクスチャ。 |
戻り値:
テクスチャがキューブベースの場合は、キューブ配列テクスチャ内のキューブ数を返します。
それ以外の場合は、配列化テクスチャ内のレイヤー(テクセルの同種グリッド)数を返します。
17.7.6. textureNumLevels
テクスチャのミップレベル数を返します。
| パラメーター化 | オーバーロード |
|---|---|
| ST は i32、u32、または f32 である T は texture_1d<ST>、texture_2d<ST>、
texture_2d_array<ST>、texture_3d<ST>、
texture_cube<ST>、texture_cube_array<ST>、
texture_depth_2d、texture_depth_2d_array、
texture_depth_cube、または texture_depth_cube_array である
|
|
パラメータ:
t
| サンプルテクスチャまたはデプステクスチャ。 |
戻り値:
テクスチャのミップレベル数を返します。
17.7.7. textureNumSamples
マルチサンプルテクスチャ内のテクセルごとのサンプル数を返します。
| パラメーター化 | オーバーロード |
|---|---|
| ST は i32、u32、または f32 である T は texture_multisampled_2d<ST>
または texture_depth_multisampled_2d である
|
|
パラメータ:
t
| マルチサンプルテクスチャ。 |
戻り値:
サンプル数を マルチサンプルテクスチャに対して返します。
17.7.8. textureSample
テクスチャーをサンプリングする。
なければならないのは、 fragment shader stage 内でのみ使用されること。
uniformity analysis が、この関数への呼び出しがuniform control flow内にあることを証明できない場合、 derivative_uniformity diagnostic がtriggeredされる。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| |
| A は i32、または u32 |
|
| A は i32、または u32 |
|
T は texture_3d<f32>、または texture_cube<f32>
|
|
| |
| A は i32、または u32 |
|
| |
| |
| A は i32、または u32 |
|
| A は i32、または u32 |
|
| |
| A は i32、または u32 |
|
パラメーター:
t
| サンプリング対象のsampled または depth テクスチャー。 |
s
| sampler 型。 |
coords
| サンプリングに使用されるテクスチャー座標。 |
array_index
|
サンプリング対象の 0 始まりのテクスチャー配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] にクランプされることになる。
|
offset
|
テクスチャーをサンプリングする前に、正規化されていないテクスチャー座標に適用される
省略可能な texel オフセット。このオフセットは、いかなる
テクスチャーラッピングモードを適用する前に適用される。offset 式はconst-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は、少なくとも -8 かつ最大
7 でなければならない。この範囲外の値は
shader-creation error になる。
|
戻り値:
サンプリングされた値。
non-uniform control flow内で呼び出された場合、不定 値が発生する。
17.7.9. textureSampleBias
mip レベルへのバイアスを付けてテクスチャーをサンプリングする。
なければならないのは、 fragment shader stage 内でのみ使用されること。
uniformity analysis が、この関数への呼び出しがuniform control flow内にあることを証明できない場合、 derivative_uniformity diagnostic がtriggeredされる。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A は i32、または u32 |
|
| A は i32、または u32 |
|
T は texture_3d<f32>、または texture_cube<f32>
|
|
| |
| A は i32、または u32 |
|
パラメーター:
t
| サンプリング対象のsampled texture。 |
s
| sampler 型。 |
coords
| サンプリングに使用されるテクスチャー座標。 |
array_index
|
サンプリング対象の 0 始まりのテクスチャー配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] にクランプされることになる。
|
bias
|
サンプリング前に mip レベルに適用するバイアス。 この値は範囲 [-16.0, 15.99] にクランプされることになる。
|
offset
|
テクスチャーをサンプリングする前に、正規化されていないテクスチャー座標に適用される
省略可能な texel オフセット。このオフセットは、いかなる
テクスチャーラッピングモードを適用する前に適用される。offset 式はconst-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は、少なくとも -8 かつ最大
7 でなければならない。この範囲外の値は
shader-creation error になる。
|
戻り値:
サンプリングされた値。
17.7.10.
textureSampleCompare
depth texture をサンプリングし、サンプリングされた depth 値を参照値と比較する。
なければならないのは、 fragment shader stage 内でのみ使用されること。
uniformity analysis が、この関数への呼び出しがuniform control flow内にあることを証明できない場合、 derivative_uniformity diagnostic がtriggeredされる。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A は i32、または u32 |
|
| A は i32、または u32 |
|
| |
| A は i32、または u32 |
|
パラメーター:
t
| サンプリング対象のdepth texture。 |
s
| sampler_comparison 型。 |
coords
| サンプリングに使用されるテクスチャー座標。 |
array_index
|
サンプリング対象の 0 始まりのテクスチャー配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] にクランプされることになる。
|
depth_ref
| サンプリングされた depth 値と比較する参照値。 |
offset
|
テクスチャーをサンプリングする前に、正規化されていないテクスチャー座標に適用される
省略可能な texel オフセット。このオフセットは、いかなる
テクスチャーラッピングモードを適用する前に適用される。offset 式はconst-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は、少なくとも -8 かつ最大
7 でなければならない。この範囲外の値は
shader-creation error になる。
|
戻り値:
[0.0..1.0] の範囲内の値。
サンプリングされた各テクセルは、sampler_comparison によって定義される比較
演算子を使用して参照値と比較され、その結果、各テクセルについて 0 または
1
の値になる。
サンプラーがバイリニアフィルタリングを使用する場合、返される値は これらの値のフィルター済み平均であり、そうでなければ 単一テクセルの比較結果が返される。
17.7.11.
textureSampleCompareLevel
デプステクスチャをサンプリングし、サンプリングされた深度値を参照値と比較します。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A は i32、または u32 |
|
| A は i32、または u32 |
|
| |
| A は i32、または u32 |
|
パラメーター:
t
| サンプリング対象のdepth texture。 |
s
| sampler_comparison 型。 |
coords
| サンプリングに使用されるテクスチャー座標。 |
array_index
|
サンプリング対象の 0 始まりのテクスチャー配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] にクランプされることになる。
|
depth_ref
| サンプリングされた depth 値と比較する参照値。 |
offset
|
テクスチャーをサンプリングする前に、正規化されていないテクスチャー座標に適用される
省略可能な texel オフセット。このオフセットは、いかなる
テクスチャーラッピングモードを適用する前に適用される。offset 式はconst-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は、少なくとも -8 かつ最大
7 でなければならない。この範囲外の値は
shader-creation error になる。
|
戻り値:
範囲[0.0..1.0]の値。
textureSampleCompareLevel関数はtextureSampleCompareと同じですが、以下の違いがあります:
-
textureSampleCompareLevelは常にミップレベル0のテクセルをサンプリングします。-
この関数は微分を計算しません。
-
textureSampleCompareLevelを一様な制御フローで呼び出す必要はありません。
-
-
textureSampleCompareLevelは任意のシェーダーステージで呼び出すことができます。
17.7.12.
textureSampleGrad
明示的な勾配を使ってテクスチャをサンプリングします。
| パラメータ化 | オーバーロード |
|---|---|
| |
| |
| A は i32、または u32 |
|
| A は i32、または u32 |
|
T は texture_3d<f32>、または texture_cube<f32>
|
|
| |
| A は i32、または u32 |
|
パラメーター:
t
| サンプリングするサンプリング対象テクスチャ。 |
s
| サンプラー。 |
coords
| サンプリングに使用されるテクスチャ座標。 |
array_index
|
サンプリングする 0 始まりのテクスチャ配列インデックス。 この値は [0, textureNumLayers(t) - 1] の範囲に
クランプされる。
|
ddx
| サンプリング位置の計算に使用される x 方向の微分ベクトル。 |
ddy
| サンプリング位置の計算に使用される y 方向の微分ベクトル。 |
offset
|
テクスチャをサンプリングする前に、正規化されていないテクスチャ座標へ
適用される省略可能なテクセルオフセット。このオフセットは、
いずれのテクスチャラッピングモードを適用する前に適用される。offset 式は 必ず const-expression でなければならない(例:
vec2<i32>(1, 2))。各 offset 成分は 必ず -8 以上 7 以下でなければならない。
この範囲外の値は
shader-creation error になる。
|
戻り値:
サンプリングされた値。
17.7.13.
textureSampleLevel
明示的なミップレベルを指定してテクスチャをサンプリングします。
| パラメータ化 | オーバーロード |
|---|---|
| |
| |
| |
| A は i32、または u32 |
|
| A は i32、または u32 |
|
T は texture_3d<f32>、または texture_cube<f32>
|
|
| |
| A は i32、または u32 |
|
| L は i32、または u32 |
|
| L は i32、または u32 |
|
| A は i32、または u32 L は i32、または u32 |
|
| A は i32、または u32 L は i32、または u32 |
|
| L は i32、または u32 |
|
| A は i32、または u32 L は i32、または u32 |
|
パラメーター:
t
| サンプリングするサンプリング対象または深度テクスチャ。 |
s
| サンプラー型。 |
coords
| サンプリングに使用されるテクスチャ座標。 |
array_index
|
サンプリングする 0 始まりのテクスチャ配列インデックス。 この値は [0, textureNumLayers(t) - 1] の範囲に
クランプされる。
|
level
|
ミップレベル。レベル 0 にはテクスチャのフルサイズ版が含まれる。
level が f32 である関数では、小数値は、その形式が
Texture Format Capabilities
に従ってフィルター可能である場合、2 つのレベル間を補間できる。
|
offset
|
テクスチャをサンプリングする前に、正規化されていないテクスチャ座標へ
適用される省略可能なテクセルオフセット。このオフセットは、
いずれのテクスチャラッピングモードを適用する前に適用される。offset 式は 必ず const-expression でなければならない(例:
vec2<i32>(1, 2))。各 offset 成分は 必ず -8 以上 7 以下でなければならない。
この範囲外の値は
shader-creation error になる。
|
戻り値:
サンプリングされた値。
17.7.14.
textureSampleBaseClampToEdge
テクスチャビューのベースレベルをサンプリングし、 テクスチャ座標は以下の通りエッジにクランプされます。
| パラメータ化 | オーバーロード |
|---|---|
Tはtexture_2d<f32>またはtexture_external
|
|
パラメータ:
t
| サンプリング対象のサンプルテクスチャまたは外部テクスチャ。 |
s
| サンプラー型。 |
coords
|
サンプリングに使用するテクスチャ座標。
サンプリング前に、指定した座標は必ず以下の矩形範囲にクランプされます:
ここで
注: ハーフテクセル調整により、
サンプラーの |
戻り値:
サンプリングされた値。
17.7.15. textureStore
テクスチャに単一のテクセルを書き込みます。
| パラメータ化 | オーバーロード |
|---|---|
| F はテクセル
形式 C は i32、または u32 AM は write または read_write CF はストレージ・テクセル形式 F に依存する。 テクセル形式からチャンネル形式への対応については テクセル形式の表を 参照。 |
|
| F はテクセル
形式 C は i32、または u32 AM は write または read_write CF はストレージ・テクセル形式 F に依存する。 テクセル形式からチャンネル形式への対応については テクセル形式の表を 参照。 |
|
| F はテクセル
形式 C は i32、または u32 AM は write または read_write A は i32、または u32 CF はストレージ・テクセル形式 F に依存する。 テクセル形式からチャンネル形式への対応については テクセル形式の表を 参照。 |
|
| F はテクセル
形式 C は i32、または u32 AM は write または read_write CF はストレージ・テクセル形式 F に依存する。 テクセル形式からチャンネル形式への対応については テクセル形式の表を 参照。 |
|
パラメータ:
t
| 書き込み専用ストレージテクスチャまたは 読書き可能ストレージテクスチャ |
coords
|
0始まりのテクセル座標。 |
array_index
| 0始まりのテクスチャ配列インデックス。 |
value
|
新しいテクセル値。
valueは逆チャンネル伝達関数で変換されます。
|
注:
論理テクセルアドレスが不正な場合:
-
coordsのいずれかの要素が、対応する要素の範囲[0, textureDimensions(t))外の場合 -
array_indexが[0, textureNumLayers(t))の範囲外の場合
論理テクセルアドレスが不正な場合、組み込み関数は必ず実行されません。
17.8. アトミック組み込み関数
アトミック組み込み関数は、アトミック オブジェクトの読み取り/書き込み/読み取り-変更-書き込みに使用できる。これらは § 6.2.8 Atomic Types に対して許可される唯一の操作である。
すべてのアトミック組み込み関数は、relaxed なメモリ
順序づけを使用する。これは、同期および順序づけの保証が、同じメモリ位置に作用する
アトミック操作の間にのみ適用されることを意味する。アトミックメモリアクセスと非アトミックメモリアクセスの間、
または異なるメモリ位置に作用するアトミックアクセスの間には、同期
または順序づけの保証は適用されない。
アトミック組み込み関数は、してはならない vertex シェーダーステージで使用してはならない。
すべてのアトミック組み込み関数における atomic_ptr パラメーターのアドレス空間
AS は、必ず storage または workgroup のいずれかでなければならない。
T は、必ず u32 または i32 のいずれかでなければならない
17.8.1.
atomicLoad
fn atomicLoad ( atomic_ptr : ptr< AS , atomic< T > , read_write> ) -> T
atomic_ptrで指された値をアトミックにロードして返します。オブジェクト自体は変更しません。
17.8.2.
atomicStore
fn atomicStore ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T )
vの値をatomic_ptrで指されたアトミックオブジェクトにアトミックに格納します。
17.8.3. アトミック読取-修正-書き込み演算・論理関数
各関数は以下の手順をアトミックに行います:
-
atomic_ptrで指された元の値をロードする。 -
関数名から指定された操作(例: max)を値vとともに実行し、新しい値を取得する。
-
atomic_ptrを使って新しい値を格納する。
各関数は、操作前にアトミックオブジェクトに格納されていた元の値を返します。
17.8.3.1.
atomicAdd
fn atomicAdd ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptrで指されたアトミックオブジェクトにvの値を加算し、操作前に格納されていた元の値を返します。
// すべての操作はアトミックに実行されます fn atomicAdd ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old + v ; return old ; }
17.8.3.2.
atomicSub
fn atomicSub ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptrで指されたアトミックオブジェクトからvの値を減算し、操作前に格納されていた元の値を返します。
// すべての操作はアトミックに実行されます fn atomicSub ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old - v ; return old ; }
17.8.3.3.
atomicMax
fn atomicMax ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptrで指されたアトミックオブジェクトに対しvとの最大値をアトミックに計算し、操作前の元の値を返します。
// すべての操作はアトミックに実行されます fn atomicMax ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = max ( old , v ); return old ; }
17.8.3.4.
atomicMin
fn atomicMin ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptrで指されたアトミックオブジェクトに対しvとの最小値をアトミックに計算し、操作前の元の値を返します。
// すべての操作はアトミックに実行されます fn atomicMin ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = min ( old , v ); return old ; }
17.8.3.5.
atomicAnd
fn atomicAnd ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptrが指すアトミックオブジェクトに値vとのビットごとのAND演算をアトミックに行い、操作前にアトミックオブジェクトに格納されていた元の値を返します。
// すべての操作はアトミックに実行されます fn atomicAnd ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old & v ; return old ; }
17.8.3.6.
atomicOr
fn atomicOr ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptrが指すアトミックオブジェクトに値vとのビットごとのOR演算をアトミックに行い、操作前にアトミックオブジェクトに格納されていた元の値を返します。
// すべての操作はアトミックに実行されます fn atomicOr ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old | v ; return old ; }
17.8.3.7.
atomicXor
fn atomicXor ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptrが指すアトミックオブジェクトに値vとのビットごとのXOR演算をアトミックに行い、操作前にアトミックオブジェクトに格納されていた元の値を返します。
// すべての操作はアトミックに実行されます fn atomicXor ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old ^ v ; return old ; }
17.8.4.
atomicExchange
fn atomicExchange ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptrが指すアトミックオブジェクトに値vをアトミックに格納し、操作前にアトミックオブジェクトに格納されていた元の値を返します。
// すべての操作はアトミックに実行されます fn atomicExchange ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = v ; return old ; }
17.8.5.
atomicCompareExchangeWeak
fn atomicCompareExchangeWeak ( atomic_ptr : ptr< AS , atomic< T > , read_write> , cmp : T , v : T ) -> __atomic_compare_exchange_result < T > struct __atomic_compare_exchange_result < T > { old_value : T , // アトミックに格納されていた古い値 exchanged : bool// 交換が実行された場合はtrue }
注:
__atomic_compare_exchange_result型で値を明示的に宣言することはできませんが、型推論は可能です。
次のステップをアトミックに実行します:
-
atomic_ptrが指す元の値をロードします。 -
元の値と
cmpの値を等価演算で比較します。 -
等価比較の結果が
trueの場合のみ、値vを格納します。
2つのメンバーからなる構造体を返します。最初のメンバーold_valueは操作前のアトミックオブジェクトの元の値で、2番目のメンバーexchangedは比較が成功したかどうかを示します。
// すべての操作はアトミックに実行されます fn atomicCompareExchangeWeak ( atomic_ptr : ptr< AS , atomic< T > , read_write> , cmp : T , v : T ) -> _atomic_compare_exchange_result < T > { let old = * atomic_ptr ; // この比較は偽陽性で失敗する可能性があります。 let comparison = old == cmp ; if comparison { * atomic_ptr = v ; } return _atomic_compare_exchange_result < T > ( old , comparison ); }
注:
一部の実装では等価比較が偽陽性で失敗する場合があります。つまり、結果ベクトルの第2成分がfalseとなる場合でも、第1成分がcmpと等しいことがあります。
17.9. データパッキング組み込み関数
データパッキング組み込み関数は、WGSLの型と直接対応しないデータフォーマットを使用して値をエンコードするために利用できます。 これにより、多くの密集した値をメモリに書き込むことが可能となり、シェーダのメモリ帯域幅要求を削減できます。
各組み込み関数は、複数の入力値にチャネル転送関数の逆を適用し、その結果を一つの出力値にまとめます。
注: unorm値のパッキングでは、正規化された浮動小数点値は区間[0.0, 1.0]にあります。
注: snorm値のパッキングでは、正規化された浮動小数点値は区間[-1.0, 1.0]にあります。
17.9.1.
pack4x8snorm
| オーバーロード |
|
| 説明 |
4つの正規化された浮動小数点値を8ビット符号付き整数に変換し、それらを1つのu32値にまとめます。
入力の各成分 |
17.9.2.
pack4x8unorm
| オーバーロード |
|
| 説明 |
4つの正規化された浮動小数点値を8ビット符号なし整数に変換し、それらを1つのu32値にまとめます。
入力の各成分 |
17.9.3.
pack4xI8
| オーバーロード |
|
| 説明 |
eの各コンポーネントの下位8ビットをu32値にパックし、未使用のビットはすべて捨てます。
入力のコンポーネント |
17.9.4.
pack4xU8
| オーバーロード |
|
| 説明 |
eの各コンポーネントの下位8ビットをu32値にパックし、未使用のビットはすべて捨てます。
入力のコンポーネント |
17.9.5.
pack4xI8Clamp
| オーバーロード |
|
| 説明 |
e の各コンポーネントを範囲 [-128, 127] にクランプし、その後各コンポーネントの下位8ビットを u32 値にパックします。
入力のコンポーネント |
17.9.6.
pack4xU8Clamp
| オーバーロード |
|
| 説明 |
e の各コンポーネントを [0, 255] の範囲でクランプし、その後各コンポーネントの下位8ビットを u32 値にパックします。
入力のコンポーネント |
17.9.7.
pack2x16snorm
| オーバーロード |
|
| 説明 | 2つの正規化された浮動小数点値を16ビット符号付き整数に変換し、それらを1つのu32値にまとめます。入力の各成分 e[i]は、16ビット2の補数整数値
⌊ 0.5 + 32767 × min(1, max(-1, e[i])) ⌋に変換され、
結果の16 × iから16 × i + 15までのビットに配置されます。
|
17.9.8.
pack2x16unorm
| オーバーロード |
|
| 説明 | 2つの正規化された浮動小数点値を16ビット符号なし整数に変換し、それらを1つのu32値にまとめます。入力の各成分 e[i]は、16ビット符号なし整数値
⌊ 0.5 + 65535 × min(1, max(0, e[i])) ⌋に変換され、
結果の16 × iから16 × i + 15までのビットに配置されます。
|
17.9.9.
pack2x16float
| オーバーロード |
|
| 説明 |
2 つの浮動小数点値を半精度浮動小数点数に変換し、その後それらを
1 つの u32 値に結合する。入力の成分 e[i] は IEEE-754 binary16
値に変換され、その後
結果のビット
16 × i から
16 × i + 15 に配置される。
§ 15.7.6 浮動小数点変換を参照。
|
17.10. データアンパック組み込み関数
データアンパック組み込み関数は、WGSLの型と直接対応しないデータフォーマット内の値をデコードするために利用できます。 これにより、プログラムはメモリから多くの密集した値を読み取ることができ、シェーダのメモリ帯域幅の要求を削減できます。
各組み込み関数は入力値をチャネルに分割し、それぞれにチャネル転送関数を適用します。
注: unorm値のアンパックでは、正規化された浮動小数点の結果は区間[0.0, 1.0]にあります。
注: snorm値のアンパックでは、正規化された浮動小数点の結果は区間[-1.0, 1.0]にあります。
17.10.1.
unpack4x8snorm
| オーバーロード |
|
| 説明 | 32ビット値を4つの8ビットチャンクに分解し、各チャンクを符号付き正規化浮動小数点値として再解釈します。 結果の成分 iはmax(v ÷ 127, -1)です。ここでvは
eの8×iから8×i + 7のビットを2の補数符号付き整数として解釈した値です。
|
17.10.2.
unpack4x8unorm
| オーバーロード |
|
| 説明 | 32ビット値を4つの8ビットチャンクに分解し、各チャンクを符号なし正規化浮動小数点値として再解釈します。 結果の成分 iはv ÷ 255です。ここでvは
eの8×iから8×i + 7のビットを符号なし整数として解釈した値です。
|
17.10.3.
unpack4xI8
| オーバーロード |
|
| 説明 | eは4つの8ビット符号付き整数成分を持つベクトルとして解釈されます。eを符号拡張付きのvec4<i32>にアンパックします。
|
17.10.4.
unpack4xU8
| オーバーロード |
|
| 説明 | eは4つの8ビット符号なし整数成分を持つベクトルとして解釈されます。eをゼロ拡張付きのvec4<u32>にアンパックします。
|
17.10.5.
unpack2x16snorm
| オーバーロード |
|
| 説明 | 32ビット値を2つの16ビットチャンクに分解し、各チャンクを符号付き正規化浮動小数点値として再解釈します。 結果の成分 iはmax(v ÷ 32767, -1)です。ここでvは
eの16×iから16×i + 15のビットを2の補数符号付き整数として解釈した値です。
|
17.10.6.
unpack2x16unorm
| オーバーロード |
|
| 説明 | 32ビット値を2つの16ビットチャンクに分解し、各チャンクを符号なし正規化浮動小数点値として再解釈します。 結果の成分 iはv ÷ 65535です。ここでvは
eの16×iから16×i + 15のビットを符号なし整数として解釈した値です。
|
17.10.7.
unpack2x16float
| オーバーロード |
|
| 説明 | 32ビット値を2つの16ビットチャンクに分解し、各チャンクを浮動小数点値として再解釈します。 結果の成分 iはvのf32表現です。ここでvは
eの16×iから16×i + 15のビットをIEEE-754 binary16値として解釈したものです。
§ 15.7.6 浮動小数点変換も参照してください。
|
17.11. 同期組み込み関数
すべての同期関数は制御バリアを Acquire/Release メモリ順序で実行します。 つまり、すべての同期関数と、影響を受けるメモリおよびアトミック操作は、同期関数に対してプログラム順序で並べられます。 さらに、同期関数よりプログラム順序で前にある影響を受けるメモリやアトミック操作は、同期関数より後にワークグループのメンバーによって実行される任意の影響を受けるメモリやアトミック操作の前に、ワークグループ内のすべての他のスレッドに対して可視でなければなりません。
すべての同期関数は、Workgroup メモリスコープを使用する。
すべての同期関数は、Workgroup 実行スコープを持つ。
すべての同期関数は、必ず
compute シェーダーステージでのみ使用されなければならない。
すべての同期関数は、必ず
uniform control
flow 内でのみ呼び出されなければならない。
17.11.1.
storageBarrier
| オーバーロード |
|
| 説明 | 制御バリア同期関数を実行し、 storageアドレス空間の メモリおよびアトミック操作に影響します。 |
17.11.2.
textureBarrier
| オーバーロード |
|
| 説明 | 制御バリア同期関数を実行し、 handleアドレス空間の メモリ操作に影響します。 |
17.11.3.
workgroupBarrier
| オーバーロード |
|
| 説明 | 制御バリア同期関数を実行し、 workgroupアドレス空間の メモリおよびアトミック操作に影響します。 |
17.11.4.
workgroupUniformLoad
| オーバーロード |
|
| パラメータ化 | T は具象の構築可能型である。
|
| 説明 |
p が指す値をワークグループ内のすべての呼び出しに返す。
戻り値は一様である。
p は一様値でなければならない。
|
| オーバーロード |
|
| 説明 |
p が指す値をアトミックにロードし、それをワークグループ内のすべての呼び出しに返す。
戻り値は一様である。
p は一様値でなければならない。
|
17.12. サブグループ組み込み関数
これらの関数の呼び出しは:
-
一様性解析が、 呼び出しが 一様制御フロー内にあることを証明できない場合、発生させる subgroup_uniformity 診断を。
注記: compute シェーダーステージでは、 一様制御フローのスコープは workgroupである。 fragment シェーダーステージでは、一様制御フローのスコープは draw commandである。 これらのスコープはいずれも subgroup より大きい。
17.12.1.
subgroupAdd
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
集約(リダクション)操作。 |
17.12.1.1. subgroupExclusiveAdd
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
除外プレフィックススキャン操作(エクスクルーシブスキャン)。
アクティブな呼び出しの中で最もIDが小さい呼び出しに対して返る値は |
17.12.1.2. subgroupInclusiveAdd
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
包含プレフィックススキャン操作(インクルーシブスキャン)。
注:
|
17.12.2.
subgroupAll
| オーバーロード |
|
| 説明 | アクティブな呼び出しのすべてでeがtrueの場合にtrueを返します。対象はサブグループです。
|
17.12.3.
subgroupAnd
| オーバーロード |
|
| 前提条件 | Tはi32, u32, vecN<i32>, またはvecN<u32>です
|
| 説明 |
集約(リダクション)操作。 |
17.12.4.
subgroupAny
| オーバーロード |
|
| 説明 | アクティブな呼び出しのいずれかでeがtrueの場合にtrueを返します。対象はサブグループです。
|
17.12.5.
subgroupBallot
| オーバーロード |
|
| 説明 |
アクティブな呼び出しのうち、predがtrueであるもののビットマスクを
サブグループ内で返します。戻り値のx成分は呼び出しID 0〜31を含みます。 各成分内では、IDはビット位置で昇順です(例:ID 32はy成分のビット位置0)。 |
17.12.6.
subgroupBroadcast
| オーバーロード |
|
| 前提条件 | T は具象 数値スカラーまたは数値ベクトルであるI は u32 または i32 である
|
| 説明 |
id に一致するサブグループ呼び出し
IDを持つ呼び出しの e の値を、サブグループ内のすべてのアクティブな呼び出しへ返すサブグループ内で。
注記: 非定数版の
|
17.12.6.1. subgroupBroadcastFirst
| オーバーロード |
|
| 事前条件 | T は 具象 数値スカラー または 数値ベクトル です
|
| 説明 | サブグループ呼び出しID が最小の呼び出し(アクティブ
な呼び出しの中で)から e の値を、サブグループ内の全アクティブ呼び出しに返します。
サブグループ
|
17.12.7.
subgroupElect
| オーバーロード |
|
| 説明 | 現在の呼び出しがアクティブな呼び出しの中で最も小さいサブグループ呼び出しIDを持つ場合trueを返します。対象はサブグループです。
|
17.12.8.
subgroupMax
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
集約(リダクション)操作。 |
17.12.9.
subgroupMin
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
集約(リダクション)操作。 |
17.12.10.
subgroupMul
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
集約(リダクション)操作。 |
17.12.10.1. subgroupExclusiveMul
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
除外プレフィックススキャン操作(エクスクルーシブスキャン)。 アクティブな呼び出しのうち、現在の呼び出しIDより小さい
サブグループ呼び出しIDを持つ呼び出し全体で アクティブな呼び出しのうち最もIDが小さい呼び出しに対して返る値は |
17.12.10.2. subgroupInclusiveMul
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
包含プレフィックススキャン操作(インクルーシブスキャン)。 アクティブな呼び出しのうち、現在の呼び出しID以下の
サブグループ呼び出しIDを持つ呼び出し全体で 注:
|
17.12.11.
subgroupOr
| オーバーロード |
|
| 前提条件 | Tはi32, u32, vecN<i32>, またはvecN<u32>です
|
| 説明 |
集約(リダクション)操作。 |
17.12.12.
subgroupShuffle
| オーバーロード |
|
| 前提条件 | T は具象 数値スカラーまたは数値ベクトルであるI は u32 または i32 である
|
| 説明 |
id に一致するサブグループ呼び出し
IDを持つ呼び出しから e を返す。
|
17.12.12.1. subgroupShuffleDown
| オーバーロード |
|
| 前提条件 | T は具象 数値スカラーまたは数値ベクトルである
|
| 説明 |
現在の呼び出しについて subgroup_invocation_id + delta に一致するサブグループ呼び出し
ID
を持つ呼び出しから e を返す。
|
17.12.12.2. subgroupShuffleUp
| オーバーロード |
|
| 前提条件 | T は具象 数値スカラーまたは数値ベクトルである
|
| 説明 |
現在の呼び出しについて subgroup_invocation_id - delta に一致するサブグループ呼び出し
ID
を持つ呼び出しから e を返す。
|
17.12.12.3. subgroupShuffleXor
| オーバーロード |
|
| 前提条件 | T は具象 数値スカラーまたは数値ベクトルである
|
| 説明 |
現在の呼び出しについて subgroup_invocation_id ^ mask に一致するサブグループ呼び出し
ID
を持つ呼び出しから e を返す。
|
17.12.13.
subgroupXor
| オーバーロード |
|
| 前提条件 | Tはi32, u32, vecN<i32>, またはvecN<u32>です
|
| 説明 |
集約(リダクション)操作。 |
17.13. クアッド操作
§ 15.6.4 クアッド操作を参照。
これらの関数の呼び出しは:
-
一様性解析が、 呼び出しが 一様制御フロー内にあることを証明できない場合、発生させる subgroup_uniformity 診断を。
注記: compute シェーダーステージでは、 一様制御フローのスコープは workgroupである。 fragment シェーダーステージでは、一様制御フローのスコープは draw commandである。 これらのスコープはいずれも quad より大きい。
17.13.1.
quadBroadcast
| オーバーロード |
|
| 前提条件 | T は具象 数値スカラーまたは数値ベクトルであるI は u32 または i32 である
|
| 説明 |
quad 内で id に一致するquad 呼び出し ID
を持つ呼び出しから、quad 内のすべてのアクティブな呼び出しへ e の値を返す。
注記: subgroupBroadcast とは異なり、現在のところ 非定数の代替手段はない。 |
17.13.2.
quadSwapDiagonal
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
クアッド内で対角にある呼び出しのeの値を返します。
すなわち:
|
17.13.3.
quadSwapX
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
クアッド内で同じX次元を共有する呼び出しのeの値を返します。
すなわち:
|
17.13.4.
quadSwapY
| オーバーロード |
|
| 前提条件 | Tは具体的な数値スカラーまたは数値ベクトルです
|
| 説明 |
クアッド内で同じY次元を共有する呼び出しのeの値を返します。
すなわち:
|
18. 再帰下降構文解析用の文法
この章は規範的ではありません。
WGSLの文法はLALR(1)パーサに適した形式で定義されています。 実装によっては、再帰下降パーサを使いたい場合もあります。
規範的な文法は、再帰下降パーサには直接利用できません。なぜなら、いくつかの規則が左再帰的だからです。 文法規則が直接左再帰であるとは、定義されている非終端記号がその生成規則の最初に現れる場合を指します。
以下はWGSL文法ですが、機械的に次のように変換されています:
-
直接・間接左再帰の除去。
-
空生成規則(イプシロン規則)の回避。
-
兄弟規則間の共通プレフィックスの統合。
ただし、LL(1)ではありません。
非終端記号によっては、複数の生成規則が共通の先読み集合を持ちます。
例として、attribute 非終端記号のすべての生成規則は attr トークンで始まります。
より微妙な例としては global_decl で、3つの生成規則が attribute * 句で始まり、
その後 fn, override, var トークンで区別されます。
簡潔さのため、多くのトークン定義は繰り返されません。 トークン定義は仕様書の主部のものを利用してください。
'+'
| '-'
'(' ( expression ( ',' expression )* ',' ? )?
')'
| '='
| '@' ident_pattern_token ( '(' ( expression ( ',' expression )* ',' ? )?
')' )?
| '@' 'align' '(' expression ',' ? ')'
| '@' 'binding' '(' expression ',' ? ')'
| '@' 'blend_src' '(' expression ',' ? ')'
| '@' 'builtin' '(' builtin_value_name ',' ?
')'
| '@' 'diagnostic' diagnostic_control
| '@' 'group' '(' expression ',' ? ')'
| '@' 'id' '(' expression ',' ? ')'
| '@' 'location' '(' expression ',' ? ')'
| '@' 'size' '(' expression ',' ?
')'
| '@' 'subgroup_size' '(' expression ',' ?
')'
'&' unary_expression ( '&'
unary_expression )*
| '^' unary_expression ( '^' unary_expression )*
| '|' unary_expression ( '|' unary_expression )*
'false'
| 'true'
template_elaborated_ident.post.ident
'(' ( expression ( ',' expression )* ',' ? )?
')'
| 'default'
'.' member_ident component_or_swizzle_specifier
?
| '.' swizzle_name component_or_swizzle_specifier
?
| '[' expression ']' component_or_swizzle_specifier
?
| '%='
| '&='
| '*='
| '+='
| '-='
| '/='
| '^='
| '|='
'@' 'compute'
'@' 'const'
/0[iu]?/
| /[1-9][0-9]*[iu]?/
'(' ident_pattern_token ',' diagnostic_rule_name ','
? ')'
unary_expression bitwise_expression.post.unary_expression
| unary_expression relational_expression.post.unary_expression
| unary_expression relational_expression.post.unary_expression
'&&' unary_expression relational_expression.post.unary_expression
( '&&' unary_expression relational_expression.post.unary_expression
)*
| unary_expression relational_expression.post.unary_expression
'||' unary_expression relational_expression.post.unary_expression
( '||' unary_expression relational_expression.post.unary_expression
)*
'@' 'fragment'
'const_assert' ';'
attribute * 'fn' ident '(' ( attribute * ident
':' type_specifier ( ',' param )* ',' ? )? ')' (
'->' attribute * ident template_elaborated_ident.post.ident
)? attribute * '{' statement * '}'
| attribute * 'var' ( _template_args_start expression ( ',' expression )* ',' ? _template_args_end )? optionally_typed_ident (
'=' expression )? ';'
| global_value_decl ';'
| 'alias' ident '=' ident template_elaborated_ident.post.ident
';'
| 'struct' ident '{' attribute * member_ident ':' type_specifier ( ',' attribute * member_ident ':' type_specifier )* ',' ?
'}'
'diagnostic' '(' ident_pattern_token ',' diagnostic_rule_name
',' ? ')' ';'
| 'enable' ident_pattern_token ( ',' ident_pattern_token )* ',' ?
';'
| 'requires' ident_pattern_token ( ',' ident_pattern_token )* ',' ?
';'
attribute * 'override' optionally_typed_ident (
'=' expression )?
| 'const' optionally_typed_ident
'=' expression
'@' 'interpolate' '(' ident_pattern_token
',' ? ')'
| '@' 'interpolate' '(' ident_pattern_token
',' ident_pattern_token ',' ?
')'
'@' 'invariant'
core_lhs_expression component_or_swizzle_specifier ?
| '&' lhs_expression
| '*' lhs_expression
'%'
| '*'
| '/'
'@' 'must_use'
ident ( ':' type_specifier )?
attribute * ident
':' type_specifier
ident template_elaborated_ident.post.ident
| ident template_elaborated_ident.post.ident argument_expression_list
| literal
| '(' expression ')'
shift_expression.post.unary_expression
| shift_expression.post.unary_expression greater_than unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression greater_than_equal unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression less_than unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression less_than_equal unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression
'!=' unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression
'==' unary_expression shift_expression.post.unary_expression
( multiplicative_operator unary_expression )* ( additive_operator unary_expression ( multiplicative_operator unary_expression )* )*
attribute * 'for'
'(' for_init ? ';' expression ? ';' for_update ? ')' compound_statement
| attribute * 'if' expression compound_statement (
'else' 'if' expression compound_statement )* (
'else' compound_statement )?
| attribute * 'loop' attribute * '{' statement * ( 'continuing' attribute * '{' statement * ( 'break'
'if' expression ';' )?
'}' )? '}'
| attribute * 'switch' expression attribute * '{' switch_clause * '}'
| attribute * 'while' expression compound_statement
| ident template_elaborated_ident.post.ident
argument_expression_list
';'
| variable_or_value_statement
';'
| variable_updating_statement
';'
| assert_statement ';'
| break_statement ';'
| continue_statement ';'
| ';'
| 'discard' ';'
| 'return' expression ? ';'
'case' case_selector ( ',' case_selector )* ',' ?
':' ? compound_statement
| 'default' ':' ? compound_statement
/[rgba]/
| /[rgba][rgba]/
| /[rgba][rgba][rgba]/
| /[rgba][rgba][rgba][rgba]/
| /[xyzw]/
| /[xyzw][xyzw]/
| /[xyzw][xyzw][xyzw]/
| /[xyzw][xyzw][xyzw][xyzw]/
( _template_args_start template_arg_expression (
',' expression )* ',' ? _template_args_end )?
global_directive * ( global_decl | global_assert | ';' ) *
ident ( _template_args_start template_arg_expression (
',' expression )* ',' ? _template_args_end )?
primary_expression component_or_swizzle_specifier ?
| '!' unary_expression
| '&' unary_expression
| '*' unary_expression
| '-' unary_expression
| '~' unary_expression
'var' ( _template_args_start expression ( ',' expression )* ',' ? _template_args_end )? optionally_typed_ident
| variable_decl '=' expression
| 'const' optionally_typed_ident
'=' expression
| 'let' optionally_typed_ident
'=' expression
lhs_expression ( '=' | compound_assignment_operator
) expression
| lhs_expression '++'
| lhs_expression '--'
| '_' '=' expression
'@' 'vertex'
'@' 'workgroup_size' '(' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ',' expression ',' ?
')'
付録A: text/wgsl
メディアタイプ
Internet Assigned Numbers Authority (IANA) はメディアタイプのレジストリを管理しています。詳細は [IANA-MEDIA-TYPES] をご覧ください。
以下は WGSL モジュール向け text/wgsl メディアタイプの定義です。
これは IANA に登録されており、
https://www.iana.org/assignments/media-types/text/wgsl
に掲載されています。
- タイプ名
-
text
- サブタイプ名
-
wgsl
- 必須パラメータ
-
N/A
- オプションパラメータ
-
なし
- エンコーディングに関する考慮事項
-
binary
WGSLはUTF-8エンコーディングを使用するUnicodeテキストであり、バイトオーダーマーク(BOM)はありません。 詳細は § 3 テキスト構造 を参照してください。
- セキュリティに関する考慮事項
-
WebGPU Shading Language (WGSL) はGPUコードのためのプログラミング言語であり、WebGPU API のコンテキストで実行されます。セキュリティに関する考慮事項については [WebGPU] の2.1節をご覧ください。 プライバシーに関する考慮事項については [WebGPU] の2.2節をご覧ください。
- 相互運用性に関する考慮事項
-
WebGPUの実装ごとに異なる機能を持つ場合があり、これらの違いはWGSLプログラムで利用できる機能に影響を及ぼします。詳細は [WebGPU] の3.6節や、 § 4.1.2 言語拡張 を参照してください。
本登録はWGSLの後続版にも適用されることが期待されており、公開仕様の参照も随時更新される可能性があります。このような期待はメディアタイプ登録の中では異例ですが、業界慣習には合致します。
- 公開仕様
-
WebGPU Shading Language
- このメディアタイプを利用するアプリケーション
-
WebGPUの実装。これにはWebブラウザも含まれると想定されます。
- フラグメント識別子の考慮事項
-
なし
- 追加情報
-
マジックナンバー: なし
ファイル拡張子:
.wgslMacintoshファイルタイプコード:
TEXT - 追加情報の問い合わせ先(氏名・メールアドレス)
-
David Neto, dneto@google.com、または WGSL に記載されている編集者。
- 意図された用途
-
COMMON
- 著者
-
W3C。WGSLに記載の編集者を参照。
- 変更管理者
-
W3C
- 規範的参考文献
-
[WebGPU] W3C, "WebGPU” W3C Working Draft, January 2023. https://w3.org/TR/webgpu
Webgpu Shading Language W3C, "WebGPU Shading Language" W3C Working Draft, January 2023. https://w3.org/TR/WGSL